@pierre/theme 0.0.24 โ†’ 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/test.ts DELETED
@@ -1,272 +0,0 @@
1
- // src/test.ts
2
- import { readFileSync, existsSync } from "node:fs";
3
- import { light as rolesLight, dark as rolesDark } from "./palette";
4
- import { makeTheme } from "./theme";
5
-
6
- // Color tracking for detecting undefined values
7
- const usedColors = new Set<string>();
8
-
9
- // Helper functions
10
- function isValidHexColor(color: string): boolean {
11
- // Match #RGB, #RRGGBB, #RRGGBBAA formats
12
- return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(color);
13
- }
14
-
15
- function isValidP3Color(color: string): boolean {
16
- // Match color(display-p3 r g b) or color(display-p3 r g b / alpha)
17
- return /^color\(display-p3\s+[\d.]+\s+[\d.]+\s+[\d.]+(\s+\/\s+[\d.]+)?\)$/.test(color);
18
- }
19
-
20
- function isValidColor(color: string): boolean {
21
- return isValidHexColor(color) || isValidP3Color(color);
22
- }
23
-
24
- function collectColors(obj: any, path = ""): string[] {
25
- const issues: string[] = [];
26
-
27
- for (const [key, value] of Object.entries(obj)) {
28
- const currentPath = path ? `${path}.${key}` : key;
29
-
30
- if (typeof value === "string") {
31
- usedColors.add(value);
32
- if (value.startsWith("#") || value.startsWith("color(")) {
33
- if (!isValidColor(value)) {
34
- issues.push(`Invalid color at ${currentPath}: ${value}`);
35
- }
36
- }
37
- } else if (typeof value === "object" && value !== null) {
38
- issues.push(...collectColors(value, currentPath));
39
- }
40
- }
41
-
42
- return issues;
43
- }
44
-
45
- function testThemeGeneration(themeName: string, themeType: "light" | "dark", roles: any) {
46
- console.log(`\n๐Ÿงช Testing ${themeName}...`);
47
- const errors: string[] = [];
48
-
49
- try {
50
- const theme = makeTheme(themeName, themeType, roles);
51
-
52
- // Test 1: Required properties exist
53
- if (!theme.name) errors.push("Missing theme name");
54
- if (!theme.type) errors.push("Missing theme type");
55
- if (!theme.colors) errors.push("Missing colors object");
56
- if (!theme.tokenColors) errors.push("Missing tokenColors array");
57
- if (!theme.semanticTokenColors) errors.push("Missing semanticTokenColors object");
58
-
59
- // Test 2: Type is correct
60
- if (theme.type !== themeType) {
61
- errors.push(`Expected type "${themeType}" but got "${theme.type}"`);
62
- }
63
-
64
- // Test 3: Critical editor colors exist
65
- const criticalColors = [
66
- "editor.background",
67
- "editor.foreground",
68
- "foreground",
69
- "focusBorder",
70
- "sideBar.background",
71
- "activityBar.background",
72
- "statusBar.background"
73
- ];
74
-
75
- for (const key of criticalColors) {
76
- if (!theme.colors[key]) {
77
- errors.push(`Missing critical color: ${key}`);
78
- }
79
- }
80
-
81
- // Test 4: Validate all color values
82
- const colorIssues = collectColors(theme.colors);
83
- errors.push(...colorIssues);
84
-
85
- // Test 5: Check for undefined/null values in colors
86
- for (const [key, value] of Object.entries(theme.colors)) {
87
- if (value === undefined || value === null) {
88
- errors.push(`Color "${key}" is ${value}`);
89
- }
90
- }
91
-
92
- // Test 6: TokenColors should be an array with entries
93
- if (!Array.isArray(theme.tokenColors)) {
94
- errors.push("tokenColors is not an array");
95
- } else if (theme.tokenColors.length === 0) {
96
- errors.push("tokenColors array is empty");
97
- }
98
-
99
- // Test 7: Validate tokenColors structure
100
- theme.tokenColors.forEach((token, idx) => {
101
- if (!token.scope) {
102
- errors.push(`tokenColors[${idx}] missing scope`);
103
- }
104
- if (!token.settings) {
105
- errors.push(`tokenColors[${idx}] missing settings`);
106
- } else if (token.settings.foreground) {
107
- usedColors.add(token.settings.foreground);
108
- if (!isValidColor(token.settings.foreground)) {
109
- errors.push(`tokenColors[${idx}] has invalid foreground color: ${token.settings.foreground}`);
110
- }
111
- }
112
- });
113
-
114
- // Test 8: Semantic tokens validation
115
- for (const [key, value] of Object.entries(theme.semanticTokenColors)) {
116
- if (typeof value === "string") {
117
- usedColors.add(value);
118
- if (!isValidColor(value)) {
119
- errors.push(`semanticTokenColors["${key}"] has invalid color: ${value}`);
120
- }
121
- } else if (typeof value === "object" && value !== null) {
122
- const semanticValue = value as any;
123
- if (semanticValue.foreground) {
124
- usedColors.add(semanticValue.foreground);
125
- if (!isValidColor(semanticValue.foreground)) {
126
- errors.push(`semanticTokenColors["${key}"].foreground has invalid color: ${semanticValue.foreground}`);
127
- }
128
- }
129
- }
130
- }
131
-
132
- if (errors.length === 0) {
133
- console.log(`โœ… ${themeName} passed all checks`);
134
- return true;
135
- } else {
136
- console.error(`โŒ ${themeName} failed with ${errors.length} error(s):`);
137
- errors.forEach(err => console.error(` - ${err}`));
138
- return false;
139
- }
140
- } catch (error) {
141
- console.error(`โŒ ${themeName} threw an error:`, error);
142
- return false;
143
- }
144
- }
145
-
146
- function testGeneratedFiles() {
147
- console.log("\n๐Ÿงช Testing generated theme files...");
148
- const errors: string[] = [];
149
-
150
- const files = [
151
- { path: "themes/pierre-light.json", expectedType: "light" },
152
- { path: "themes/pierre-dark.json", expectedType: "dark" },
153
- { path: "themes/pierre-light-vibrant.json", expectedType: "light" },
154
- { path: "themes/pierre-dark-vibrant.json", expectedType: "dark" }
155
- ];
156
-
157
- for (const { path, expectedType } of files) {
158
- // Test 1: File exists
159
- if (!existsSync(path)) {
160
- errors.push(`File does not exist: ${path}`);
161
- continue;
162
- }
163
-
164
- try {
165
- // Test 2: File is valid JSON
166
- const content = readFileSync(path, "utf8");
167
- if (content.trim() === "") {
168
- errors.push(`File is empty: ${path}`);
169
- continue;
170
- }
171
-
172
- const theme = JSON.parse(content);
173
-
174
- // Test 3: Has required structure
175
- if (!theme.name) errors.push(`${path}: Missing name`);
176
- if (!theme.type) errors.push(`${path}: Missing type`);
177
- if (theme.type !== expectedType) {
178
- errors.push(`${path}: Expected type "${expectedType}" but got "${theme.type}"`);
179
- }
180
- if (!theme.colors || Object.keys(theme.colors).length === 0) {
181
- errors.push(`${path}: Missing or empty colors object`);
182
- }
183
- if (!Array.isArray(theme.tokenColors) || theme.tokenColors.length === 0) {
184
- errors.push(`${path}: Missing or empty tokenColors array`);
185
- }
186
-
187
- console.log(`โœ… ${path} is valid`);
188
- } catch (error) {
189
- errors.push(`${path}: Invalid JSON - ${error}`);
190
- }
191
- }
192
-
193
- if (errors.length > 0) {
194
- console.error(`โŒ Generated files validation failed:`);
195
- errors.forEach(err => console.error(` - ${err}`));
196
- return false;
197
- }
198
-
199
- console.log("โœ… All generated files are valid");
200
- return true;
201
- }
202
-
203
- function testPaletteRoles() {
204
- console.log("\n๐Ÿงช Testing palette roles...");
205
- const errors: string[] = [];
206
-
207
- function validateRoles(roles: any, name: string) {
208
- // Check all required role categories exist
209
- const requiredCategories = ["bg", "fg", "border", "accent", "states", "syntax", "ansi"];
210
- for (const category of requiredCategories) {
211
- if (!roles[category]) {
212
- errors.push(`${name}: Missing "${category}" category`);
213
- }
214
- }
215
-
216
- // Validate that all role values are hex colors
217
- function checkRoleColors(obj: any, path: string) {
218
- for (const [key, value] of Object.entries(obj)) {
219
- const fullPath = `${path}.${key}`;
220
- if (typeof value === "string") {
221
- if (!isValidHexColor(value)) {
222
- errors.push(`${name}.${fullPath}: Invalid color "${value}"`);
223
- }
224
- } else if (typeof value === "object" && value !== null) {
225
- checkRoleColors(value, fullPath);
226
- }
227
- }
228
- }
229
-
230
- checkRoleColors(roles, name);
231
- }
232
-
233
- validateRoles(rolesLight, "light");
234
- validateRoles(rolesDark, "dark");
235
-
236
- if (errors.length > 0) {
237
- console.error(`โŒ Palette roles validation failed:`);
238
- errors.forEach(err => console.error(` - ${err}`));
239
- return false;
240
- }
241
-
242
- console.log("โœ… Palette roles are valid");
243
- return true;
244
- }
245
-
246
- // Run all tests
247
- console.log("๐Ÿš€ Running Pierre Theme Tests\n");
248
- console.log("=" .repeat(50));
249
-
250
- let allPassed = true;
251
-
252
- // Test palette roles first
253
- allPassed = testPaletteRoles() && allPassed;
254
-
255
- // Test theme generation
256
- allPassed = testThemeGeneration("Pierre Light", "light", rolesLight) && allPassed;
257
- allPassed = testThemeGeneration("Pierre Dark", "dark", rolesDark) && allPassed;
258
-
259
- // Test generated files (only if they exist - they should after build)
260
- allPassed = testGeneratedFiles() && allPassed;
261
-
262
- // Summary
263
- console.log("\n" + "=".repeat(50));
264
- console.log(`\n๐Ÿ“Š Total unique colors used: ${usedColors.size}`);
265
-
266
- if (allPassed) {
267
- console.log("\nโœ… All tests passed!");
268
- process.exit(0);
269
- } else {
270
- console.log("\nโŒ Some tests failed!");
271
- process.exit(1);
272
- }