chore: improve asset matching logic

This commit is contained in:
Thomas Camlong
2026-01-09 13:31:55 +01:00
parent 6732d7f282
commit c08bc94b70
2 changed files with 58 additions and 50 deletions

View File

@@ -34991,12 +34991,9 @@
"name": "0xb0ec1d" "name": "0xb0ec1d"
} }
}, },
"colors": {
"dark": "broadcom-dark"
},
"wordmark": { "wordmark": {
"light": "broadcom-wordmark-light", "light": "broadcom-wordmark-light",
"dark": "broadcom-wordmark-dark" "dark": "broadcom-dark"
} }
}, },
"solarwinds": { "solarwinds": {

103
scripts/import-icon.ts Normal file → Executable file
View File

@@ -72,7 +72,7 @@ type VariantKey =
interface VariantTarget { interface VariantTarget {
key: VariantKey; key: VariantKey;
destFilename: string; destFilename: string;
matchers: string[]; // lowercase substrings to prefer when selecting assets exactFilename?: string; // exact filename to match (from extras.wordmark or extras.colors)
sourceAsset?: string; // chosen source asset name sourceAsset?: string; // chosen source asset name
} }
@@ -169,59 +169,42 @@ function inferBase(assets: string[], extrasBase?: string) {
function buildTargets(submission: Submission): VariantTarget[] { function buildTargets(submission: Submission): VariantTarget[] {
const iconId = submission.name; const iconId = submission.name;
const ext = inferBase(submission.assets, submission.extras?.base); const ext = inferBase(submission.assets, submission.extras?.base);
const assetsLower = submission.assets.map((a) => a.toLowerCase());
const hasLight =
submission.extras?.colors?.light ||
assetsLower.some((a) => a.includes("light") && !a.includes("wordmark"));
const hasDark =
submission.extras?.colors?.dark ||
assetsLower.some((a) => a.includes("dark") && !a.includes("wordmark"));
const hasWordmark =
submission.extras?.wordmark ||
assetsLower.some((a) => a.includes("wordmark"));
const hasWordmarkLight =
submission.extras?.wordmark?.light ||
assetsLower.some((a) => a.includes("wordmark") && a.includes("light"));
const hasWordmarkDark =
submission.extras?.wordmark?.dark ||
assetsLower.some((a) => a.includes("wordmark") && a.includes("dark"));
const targets: VariantTarget[] = [ const targets: VariantTarget[] = [
{ key: "base", destFilename: `${iconId}.${ext}`, matchers: [] }, { key: "base", destFilename: `${iconId}.${ext}` },
]; ];
if (hasLight) { // Only create variants that are explicitly defined in extras
if (submission.extras?.colors?.light) {
targets.push({ targets.push({
key: "light", key: "light",
destFilename: `${iconId}-light.${ext}`, destFilename: `${iconId}-light.${ext}`,
matchers: ["light"], exactFilename: submission.extras.colors.light,
}); });
} }
if (hasDark) { if (submission.extras?.colors?.dark) {
targets.push({ targets.push({
key: "dark", key: "dark",
destFilename: `${iconId}-dark.${ext}`, destFilename: `${iconId}-dark.${ext}`,
matchers: ["dark"], exactFilename: submission.extras.colors.dark,
}); });
} }
if (hasWordmark || hasWordmarkLight || hasWordmarkDark) { if (submission.extras?.wordmark?.light) {
if (hasWordmarkLight || hasWordmark) { targets.push({
targets.push({ key: "wordmark-light",
key: "wordmark-light", destFilename: `${iconId}-wordmark-light.${ext}`,
destFilename: `${iconId}-wordmark-light.${ext}`, exactFilename: submission.extras.wordmark.light,
matchers: ["wordmark", "light"], });
}); }
}
if (hasWordmarkDark || hasWordmark) { if (submission.extras?.wordmark?.dark) {
targets.push({ targets.push({
key: "wordmark-dark", key: "wordmark-dark",
destFilename: `${iconId}-wordmark-dark.${ext}`, destFilename: `${iconId}-wordmark-dark.${ext}`,
matchers: ["wordmark", "dark"], exactFilename: submission.extras.wordmark.dark,
}); });
}
} }
return targets; return targets;
@@ -233,11 +216,9 @@ function assignAssetsToTargets(
): VariantTarget[] { ): VariantTarget[] {
const remaining = new Set(assets); const remaining = new Set(assets);
const takeMatching = (matchers: string[]): string | undefined => { const takeExact = (exactFilename: string): string | undefined => {
for (const asset of remaining) { for (const asset of remaining) {
const lower = asset.toLowerCase(); if (asset === exactFilename) {
const allMatch = matchers.every((m) => lower.includes(m));
if (allMatch) {
remaining.delete(asset); remaining.delete(asset);
return asset; return asset;
} }
@@ -251,11 +232,36 @@ function assignAssetsToTargets(
return first; return first;
}; };
return targets.map((t) => { // Process variants with exact filenames first to reserve them
const matched = t.matchers.length ? takeMatching(t.matchers) : takeAny(); // Then process the base icon to take any remaining asset
const fallback = matched ?? takeAny(); const assignments = new Map<VariantTarget, string | undefined>();
return { ...t, sourceAsset: fallback };
}); // First pass: assign variants with exact filenames
for (const t of targets) {
if (t.exactFilename) {
const exact = takeExact(t.exactFilename);
assignments.set(t, exact);
}
}
// Second pass: assign base icon and any remaining targets
for (const t of targets) {
if (!assignments.has(t)) {
if (t.key === "base") {
const asset = takeAny();
assignments.set(t, asset);
} else {
// Should not reach here if logic is correct
assignments.set(t, undefined);
}
}
}
// Return in original order
return targets.map((t) => ({
...t,
sourceAsset: assignments.get(t),
}));
} }
async function downloadAsset( async function downloadAsset(
@@ -321,6 +327,11 @@ function buildMetadataVariants(assignments: VariantTarget[]) {
const wordmark: IconWordmark = {}; const wordmark: IconWordmark = {};
for (const v of assignments) { for (const v of assignments) {
// Only include variants that actually have a source asset assigned
if (!v.sourceAsset) {
continue;
}
const baseName = v.destFilename.replace(/\.[^.]+$/, ""); const baseName = v.destFilename.replace(/\.[^.]+$/, "");
if (v.key === "light") { if (v.key === "light") {
colors.light = baseName; colors.light = baseName;