diff --git a/src/build.ts b/src/build.ts index a415655..c6d312c 100644 --- a/src/build.ts +++ b/src/build.ts @@ -16,12 +16,60 @@ const rolesDarkP3 = convertRolesToP3(rolesDark); // VS Code Themes // ============================================ const vscodeThemes = [ - { file: "themes/pierre-light.json", theme: makeTheme("Pierre Light", "light", rolesLight) }, - { file: "themes/pierre-light-soft.json", theme: makeTheme("Pierre Light Soft", "light", rolesLightSoft) }, - { file: "themes/pierre-dark.json", theme: makeTheme("Pierre Dark", "dark", rolesDark) }, - { file: "themes/pierre-dark-soft.json", theme: makeTheme("Pierre Dark Soft", "dark", rolesDarkSoft) }, - { file: "themes/pierre-light-vibrant.json", theme: makeTheme("Pierre Light Vibrant", "light", rolesLightP3) }, - { file: "themes/pierre-dark-vibrant.json", theme: makeTheme("Pierre Dark Vibrant", "dark", rolesDarkP3) } + { + file: "themes/pierre-light.json", + theme: makeTheme({ + name: "pierre-light", + displayName: "Pierre Light", + type: "light", + roles: rolesLight + }) + }, + { + file: "themes/pierre-light-soft.json", + theme: makeTheme({ + name: "pierre-light-soft", + displayName: "Pierre Light Soft", + type: "light", + roles: rolesLightSoft + }) + }, + { + file: "themes/pierre-dark.json", + theme: makeTheme({ + name: "pierre-dark", + displayName: "Pierre Dark", + type: "dark", + roles: rolesDark + }) + }, + { + file: "themes/pierre-dark-soft.json", + theme: makeTheme({ + name: "pierre-dark-soft", + displayName: "Pierre Dark Soft", + type: "dark", + roles: rolesDarkSoft + }) + }, + { + file: "themes/pierre-light-vibrant.json", + theme: makeTheme({ + name: "pierre-light-vibrant", + displayName: "Pierre Light Vibrant", + type: "light", + roles: rolesLightP3 + }) + }, + { + file: "themes/pierre-dark-vibrant.json", + theme: makeTheme({ + name: "pierre-dark-vibrant", + displayName: "Pierre Dark Vibrant", + type: "dark", + roles: rolesDarkP3 + }) + } ]; for (const {file, theme} of vscodeThemes) { @@ -53,6 +101,7 @@ const themeNames: string[] = []; const themeDts = `/** VS Code / TextMate theme object (frozen at runtime). */ interface PierreTheme { readonly name: string; + readonly displayName: string; readonly type: "light" | "dark"; readonly colors: Readonly>; readonly tokenColors: ReadonlyArray<{ diff --git a/src/test.ts b/src/test.ts index 258cb97..4ebbaa2 100644 --- a/src/test.ts +++ b/src/test.ts @@ -42,26 +42,46 @@ function collectColors(obj: any, path = ""): string[] { return issues; } -function testThemeGeneration(themeName: string, themeType: "light" | "dark", roles: any) { - console.log(`\n๐Ÿงช Testing ${themeName}...`); +function testThemeGeneration( + expectedName: string, + displayName: string, + themeType: "light" | "dark", + roles: any +) { + console.log(`\n๐Ÿงช Testing ${displayName}...`); const errors: string[] = []; try { - const theme = makeTheme(themeName, themeType, roles); + const theme = makeTheme({ + name: expectedName, + displayName, + type: themeType, + roles + }); + const themeMetadata = theme as { name?: string; displayName?: string }; // Test 1: Required properties exist - if (!theme.name) errors.push("Missing theme name"); + if (!themeMetadata.name) errors.push("Missing theme name"); + if (!themeMetadata.displayName) errors.push("Missing theme displayName"); if (!theme.type) errors.push("Missing theme type"); if (!theme.colors) errors.push("Missing colors object"); if (!theme.tokenColors) errors.push("Missing tokenColors array"); if (!theme.semanticTokenColors) errors.push("Missing semanticTokenColors object"); - // Test 2: Type is correct + // Test 2: Theme metadata uses package-safe names plus display labels + if (themeMetadata.name !== expectedName) { + errors.push(`Expected name "${expectedName}" but got "${themeMetadata.name}"`); + } + if (themeMetadata.displayName !== displayName) { + errors.push(`Expected displayName "${displayName}" but got "${themeMetadata.displayName}"`); + } + + // Test 3: Type is correct if (theme.type !== themeType) { errors.push(`Expected type "${themeType}" but got "${theme.type}"`); } - // Test 3: Critical editor colors exist + // Test 4: Critical editor colors exist const criticalColors = [ "editor.background", "editor.foreground", @@ -78,25 +98,25 @@ function testThemeGeneration(themeName: string, themeType: "light" | "dark", rol } } - // Test 4: Validate all color values + // Test 5: Validate all color values const colorIssues = collectColors(theme.colors); errors.push(...colorIssues); - // Test 5: Check for undefined/null values in colors + // Test 6: Check for undefined/null values in colors for (const [key, value] of Object.entries(theme.colors)) { if (value === undefined || value === null) { errors.push(`Color "${key}" is ${value}`); } } - // Test 6: TokenColors should be an array with entries + // Test 7: TokenColors should be an array with entries if (!Array.isArray(theme.tokenColors)) { errors.push("tokenColors is not an array"); } else if (theme.tokenColors.length === 0) { errors.push("tokenColors array is empty"); } - // Test 7: Validate tokenColors structure + // Test 8: Validate tokenColors structure theme.tokenColors.forEach((token, idx) => { if (!token.scope) { errors.push(`tokenColors[${idx}] missing scope`); @@ -111,7 +131,7 @@ function testThemeGeneration(themeName: string, themeType: "light" | "dark", rol } }); - // Test 8: Semantic tokens validation + // Test 9: Semantic tokens validation for (const [key, value] of Object.entries(theme.semanticTokenColors)) { if (typeof value === "string") { usedColors.add(value); @@ -130,15 +150,15 @@ function testThemeGeneration(themeName: string, themeType: "light" | "dark", rol } if (errors.length === 0) { - console.log(`โœ… ${themeName} passed all checks`); + console.log(`โœ… ${displayName} passed all checks`); return true; } else { - console.error(`โŒ ${themeName} failed with ${errors.length} error(s):`); + console.error(`โŒ ${displayName} failed with ${errors.length} error(s):`); errors.forEach(err => console.error(` - ${err}`)); return false; } } catch (error) { - console.error(`โŒ ${themeName} threw an error:`, error); + console.error(`โŒ ${displayName} threw an error:`, error); return false; } } @@ -148,13 +168,15 @@ function testGeneratedFiles() { const errors: string[] = []; const files = [ - { path: "themes/pierre-light.json", expectedType: "light" }, - { path: "themes/pierre-dark.json", expectedType: "dark" }, - { path: "themes/pierre-light-vibrant.json", expectedType: "light" }, - { path: "themes/pierre-dark-vibrant.json", expectedType: "dark" } + { path: "themes/pierre-light.json", expectedType: "light", expectedName: "pierre-light", expectedDisplayName: "Pierre Light" }, + { path: "themes/pierre-light-soft.json", expectedType: "light", expectedName: "pierre-light-soft", expectedDisplayName: "Pierre Light Soft" }, + { path: "themes/pierre-dark.json", expectedType: "dark", expectedName: "pierre-dark", expectedDisplayName: "Pierre Dark" }, + { path: "themes/pierre-dark-soft.json", expectedType: "dark", expectedName: "pierre-dark-soft", expectedDisplayName: "Pierre Dark Soft" }, + { path: "themes/pierre-light-vibrant.json", expectedType: "light", expectedName: "pierre-light-vibrant", expectedDisplayName: "Pierre Light Vibrant" }, + { path: "themes/pierre-dark-vibrant.json", expectedType: "dark", expectedName: "pierre-dark-vibrant", expectedDisplayName: "Pierre Dark Vibrant" } ]; - for (const { path, expectedType } of files) { + for (const { path, expectedType, expectedName, expectedDisplayName } of files) { // Test 1: File exists if (!existsSync(path)) { errors.push(`File does not exist: ${path}`); @@ -173,6 +195,13 @@ function testGeneratedFiles() { // Test 3: Has required structure if (!theme.name) errors.push(`${path}: Missing name`); + if (!theme.displayName) errors.push(`${path}: Missing displayName`); + if (theme.name !== expectedName) { + errors.push(`${path}: Expected name "${expectedName}" but got "${theme.name}"`); + } + if (theme.displayName !== expectedDisplayName) { + errors.push(`${path}: Expected displayName "${expectedDisplayName}" but got "${theme.displayName}"`); + } if (!theme.type) errors.push(`${path}: Missing type`); if (theme.type !== expectedType) { errors.push(`${path}: Expected type "${expectedType}" but got "${theme.type}"`); @@ -253,8 +282,8 @@ let allPassed = true; allPassed = testPaletteRoles() && allPassed; // Test theme generation -allPassed = testThemeGeneration("Pierre Light", "light", rolesLight) && allPassed; -allPassed = testThemeGeneration("Pierre Dark", "dark", rolesDark) && allPassed; +allPassed = testThemeGeneration("pierre-light", "Pierre Light", "light", rolesLight) && allPassed; +allPassed = testThemeGeneration("pierre-dark", "Pierre Dark", "dark", rolesDark) && allPassed; // Test generated files (only if they exist - they should after build) allPassed = testGeneratedFiles() && allPassed; diff --git a/src/theme.ts b/src/theme.ts index e9a0e6d..e20e87e 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -3,15 +3,24 @@ import type { Roles } from "./palette"; type VSCodeTheme = { name: string; + displayName: string; type: "light" | "dark"; colors: Record; tokenColors: any[]; semanticTokenColors: Record; }; -export function makeTheme(name: string, kind: "light"|"dark", c: Roles): VSCodeTheme { +type MakeThemeOptions = { + name: string; + displayName: string; + type: "light" | "dark"; + roles: Roles; +}; + +export function makeTheme({ name, displayName, type: kind, roles: c }: MakeThemeOptions): VSCodeTheme { return { name, + displayName, type: kind, colors: { // Core editor & text diff --git a/themes/pierre-dark-soft.json b/themes/pierre-dark-soft.json index c52d4f8..d56d5d1 100644 --- a/themes/pierre-dark-soft.json +++ b/themes/pierre-dark-soft.json @@ -1,5 +1,6 @@ { - "name": "Pierre Dark Soft", + "name": "pierre-dark-soft", + "displayName": "Pierre Dark Soft", "type": "dark", "colors": { "editor.background": "#171717", diff --git a/themes/pierre-dark-vibrant.json b/themes/pierre-dark-vibrant.json index 6a2854e..0d4a757 100644 --- a/themes/pierre-dark-vibrant.json +++ b/themes/pierre-dark-vibrant.json @@ -1,5 +1,6 @@ { - "name": "Pierre Dark Vibrant", + "name": "pierre-dark-vibrant", + "displayName": "Pierre Dark Vibrant", "type": "dark", "colors": { "editor.background": "color(display-p3 0.039216 0.039216 0.039216)", diff --git a/themes/pierre-dark.json b/themes/pierre-dark.json index 65f92b2..f074471 100644 --- a/themes/pierre-dark.json +++ b/themes/pierre-dark.json @@ -1,5 +1,6 @@ { - "name": "Pierre Dark", + "name": "pierre-dark", + "displayName": "Pierre Dark", "type": "dark", "colors": { "editor.background": "#0a0a0a", diff --git a/themes/pierre-light-soft.json b/themes/pierre-light-soft.json index ee6a5e8..17464b0 100644 --- a/themes/pierre-light-soft.json +++ b/themes/pierre-light-soft.json @@ -1,5 +1,6 @@ { - "name": "Pierre Light Soft", + "name": "pierre-light-soft", + "displayName": "Pierre Light Soft", "type": "light", "colors": { "editor.background": "#ffffff", diff --git a/themes/pierre-light-vibrant.json b/themes/pierre-light-vibrant.json index 1e093a0..43375e3 100644 --- a/themes/pierre-light-vibrant.json +++ b/themes/pierre-light-vibrant.json @@ -1,5 +1,6 @@ { - "name": "Pierre Light Vibrant", + "name": "pierre-light-vibrant", + "displayName": "Pierre Light Vibrant", "type": "light", "colors": { "editor.background": "color(display-p3 1.000000 1.000000 1.000000)", diff --git a/themes/pierre-light.json b/themes/pierre-light.json index c22032e..b833798 100644 --- a/themes/pierre-light.json +++ b/themes/pierre-light.json @@ -1,5 +1,6 @@ { - "name": "Pierre Light", + "name": "pierre-light", + "displayName": "Pierre Light", "type": "light", "colors": { "editor.background": "#ffffff",