@pierre/theme 0.0.25 → 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/dist/index.mjs +1 -0
- package/dist/pierre-dark-vibrant.mjs +1 -0
- package/dist/pierre-dark.mjs +1 -0
- package/dist/pierre-light-vibrant.mjs +1 -0
- package/dist/pierre-light.mjs +1 -0
- package/package.json +6 -1
- package/.github/workflows/publish.yml +0 -68
- package/.github/workflows/test.yml +0 -80
- package/.vscode/extensions.json +0 -5
- package/.vscode/launch.json +0 -24
- package/.vscode/tasks.json +0 -24
- package/.vscodeignore +0 -10
- package/CONTRIBUTING.md +0 -75
- package/DISPLAY-P3.md +0 -120
- package/src/build.ts +0 -60
- package/src/color-p3.ts +0 -229
- package/src/demo-p3.ts +0 -44
- package/src/package-vsix.ts +0 -22
- package/src/palette.ts +0 -379
- package/src/test.ts +0 -272
- package/src/theme.ts +0 -615
- package/src/zed-theme.ts +0 -606
- package/tsconfig.json +0 -21
- package/zed/LICENSE.md +0 -21
- package/zed/README.md +0 -25
- package/zed/extension.toml +0 -7
- package/zed/themes/pierre.json +0 -991
package/src/package-vsix.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from "fs";
|
|
2
|
-
import { execSync } from "child_process";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
|
|
5
|
-
const pkgPath = join(__dirname, "..", "package.json");
|
|
6
|
-
const original = readFileSync(pkgPath, "utf-8");
|
|
7
|
-
const pkg = JSON.parse(original);
|
|
8
|
-
|
|
9
|
-
// Store original name and swap to unscoped version for VSIX
|
|
10
|
-
const originalName = pkg.name;
|
|
11
|
-
pkg.name = "pierre-theme";
|
|
12
|
-
|
|
13
|
-
console.log(`Temporarily renaming package: ${originalName} → ${pkg.name}\n`);
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
17
|
-
execSync("vsce package", { stdio: "inherit", cwd: join(__dirname, "..") });
|
|
18
|
-
} finally {
|
|
19
|
-
// Always restore original package.json
|
|
20
|
-
writeFileSync(pkgPath, original);
|
|
21
|
-
console.log(`\nRestored package name: ${originalName}`);
|
|
22
|
-
}
|
package/src/palette.ts
DELETED
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
// src/palette.ts
|
|
2
|
-
|
|
3
|
-
const gray = {
|
|
4
|
-
"020":"#fbfbfb",
|
|
5
|
-
"040":"#f9f9f9",
|
|
6
|
-
"060":"#f8f8f8",
|
|
7
|
-
"080":"#f2f2f3",
|
|
8
|
-
"100":"#eeeeef",
|
|
9
|
-
"200":"#dbdbdd",
|
|
10
|
-
"300":"#c6c6c8",
|
|
11
|
-
"400":"#adadb1",
|
|
12
|
-
"500":"#8E8E95",
|
|
13
|
-
"600":"#84848A",
|
|
14
|
-
"700":"#79797F",
|
|
15
|
-
"800":"#6C6C71",
|
|
16
|
-
"900":"#4A4A4E",
|
|
17
|
-
"920":"#424245",
|
|
18
|
-
"940":"#39393c",
|
|
19
|
-
"960":"#2e2e30",
|
|
20
|
-
"980":"#1F1F21",
|
|
21
|
-
"1000":"#141415",
|
|
22
|
-
"1020":"#0B0B0C",
|
|
23
|
-
"1040":"#070707"
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const red = {
|
|
27
|
-
"050":"#ffedea",
|
|
28
|
-
"100":"#ffdbd6",
|
|
29
|
-
"200":"#ffb7ae",
|
|
30
|
-
"300":"#ff9187",
|
|
31
|
-
"400":"#ff6762",
|
|
32
|
-
"500":"#ff2e3f",
|
|
33
|
-
"600":"#d52c36",
|
|
34
|
-
"700":"#ad292e",
|
|
35
|
-
"800":"#862425",
|
|
36
|
-
"900":"#611e1d",
|
|
37
|
-
"950":"#3e1715"
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const orange = {
|
|
41
|
-
"050":"#fff3ea",
|
|
42
|
-
"100":"#ffe8d5",
|
|
43
|
-
"200":"#ffd1ab",
|
|
44
|
-
"300":"#ffba82",
|
|
45
|
-
"400":"#ffa359",
|
|
46
|
-
"500":"#fe8c2c",
|
|
47
|
-
"600":"#d47628",
|
|
48
|
-
"700":"#ac6023",
|
|
49
|
-
"800":"#854c1e",
|
|
50
|
-
"900":"#603819",
|
|
51
|
-
"950":"#3d2513"
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const yellow = {
|
|
55
|
-
"050": "#fff9ea",
|
|
56
|
-
"100": "#fff4d5",
|
|
57
|
-
"200": "#ffe9ab",
|
|
58
|
-
"300": "#ffde80",
|
|
59
|
-
"400": "#ffd452",
|
|
60
|
-
"500": "#ffca00",
|
|
61
|
-
"600": "#d5a910",
|
|
62
|
-
"700": "#ac8816",
|
|
63
|
-
"800": "#856a17",
|
|
64
|
-
"900": "#604c16",
|
|
65
|
-
"950": "#3d3112"
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const green = {
|
|
69
|
-
"050": "#edf9ed",
|
|
70
|
-
"100": "#daf3db",
|
|
71
|
-
"200": "#b4e7b7",
|
|
72
|
-
"300": "#8cda94",
|
|
73
|
-
"400": "#5ecc71",
|
|
74
|
-
"500": "#0dbe4e",
|
|
75
|
-
"600": "#199f43",
|
|
76
|
-
"700": "#1d8138",
|
|
77
|
-
"800": "#1d642e",
|
|
78
|
-
"900": "#1b4923",
|
|
79
|
-
"950": "#162f19"
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const mint = {
|
|
83
|
-
"050": "#edfaf7",
|
|
84
|
-
"100": "#dbf5ef",
|
|
85
|
-
"200": "#b7ebdf",
|
|
86
|
-
"300": "#8fe0d0",
|
|
87
|
-
"400": "#61d5c0",
|
|
88
|
-
"500": "#00cab1",
|
|
89
|
-
"600": "#16a994",
|
|
90
|
-
"700": "#1d8978",
|
|
91
|
-
"800": "#1e6a5e",
|
|
92
|
-
"900": "#1c4d44",
|
|
93
|
-
"950": "#16312c"
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const teal = {
|
|
97
|
-
"050": "#eef9fa",
|
|
98
|
-
"100": "#ddf4f6",
|
|
99
|
-
"200": "#b9e8ed",
|
|
100
|
-
"300": "#92dde4",
|
|
101
|
-
"400": "#64d1db",
|
|
102
|
-
"500": "#00c5d2",
|
|
103
|
-
"600": "#17a5af",
|
|
104
|
-
"700": "#1e858e",
|
|
105
|
-
"800": "#1f686e",
|
|
106
|
-
"900": "#1d4b4f",
|
|
107
|
-
"950": "#173033"
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
const cyan = {
|
|
111
|
-
"050": "#eff9fe",
|
|
112
|
-
"100": "#def2fc",
|
|
113
|
-
"200": "#bce6f9",
|
|
114
|
-
"300": "#96d9f6",
|
|
115
|
-
"400": "#68cdf2",
|
|
116
|
-
"500": "#08c0ef",
|
|
117
|
-
"600": "#1ca1c7",
|
|
118
|
-
"700": "#2182a1",
|
|
119
|
-
"800": "#22657c",
|
|
120
|
-
"900": "#1e4959",
|
|
121
|
-
"950": "#182f38"
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const blue = {
|
|
125
|
-
"050": "#eff5ff",
|
|
126
|
-
"100": "#dfebff",
|
|
127
|
-
"200": "#bdd7ff",
|
|
128
|
-
"300": "#97c4ff",
|
|
129
|
-
"400": "#69b1ff",
|
|
130
|
-
"500": "#009fff",
|
|
131
|
-
"600": "#1a85d4",
|
|
132
|
-
"700": "#216cab",
|
|
133
|
-
"800": "#215584",
|
|
134
|
-
"900": "#1f3e5e",
|
|
135
|
-
"950": "#19283c"
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const indigo = {
|
|
139
|
-
"050": "#f5ecff",
|
|
140
|
-
"100": "#ead9ff",
|
|
141
|
-
"200": "#d3b4fe",
|
|
142
|
-
"300": "#ba8ffd",
|
|
143
|
-
"400": "#9d6afb",
|
|
144
|
-
"500": "#7b43f8",
|
|
145
|
-
"600": "#693acf",
|
|
146
|
-
"700": "#5731a7",
|
|
147
|
-
"800": "#462981",
|
|
148
|
-
"900": "#35205c",
|
|
149
|
-
"950": "#24173a"
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const purple = {
|
|
153
|
-
"050": "#fbedfd",
|
|
154
|
-
"100": "#f7dbfb",
|
|
155
|
-
"200": "#eeb6f6",
|
|
156
|
-
"300": "#e290f0",
|
|
157
|
-
"400": "#d568ea",
|
|
158
|
-
"500": "#c635e4",
|
|
159
|
-
"600": "#a631be",
|
|
160
|
-
"700": "#872b9a",
|
|
161
|
-
"800": "#692677",
|
|
162
|
-
"900": "#4d1f56",
|
|
163
|
-
"950": "#321736"
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
const pink = {
|
|
167
|
-
"050": "#ffedf0",
|
|
168
|
-
"100": "#ffdbe1",
|
|
169
|
-
"200": "#ffb7c4",
|
|
170
|
-
"300": "#ff91a8",
|
|
171
|
-
"400": "#ff678d",
|
|
172
|
-
"500": "#fc2b73",
|
|
173
|
-
"600": "#d32a61",
|
|
174
|
-
"700": "#aa2850",
|
|
175
|
-
"800": "#84243f",
|
|
176
|
-
"900": "#5f1e2f",
|
|
177
|
-
"950": "#3d1720"
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const brown = {
|
|
181
|
-
"050": "#f8f2ee",
|
|
182
|
-
"100": "#f1e4dd",
|
|
183
|
-
"200": "#e3cabb",
|
|
184
|
-
"300": "#d3b19b",
|
|
185
|
-
"400": "#c3987b",
|
|
186
|
-
"500": "#b27f5c",
|
|
187
|
-
"600": "#956b4f",
|
|
188
|
-
"700": "#7a5841",
|
|
189
|
-
"800": "#5f4534",
|
|
190
|
-
"900": "#453327",
|
|
191
|
-
"950": "#2d221b"
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
export type Roles = {
|
|
195
|
-
bg: {
|
|
196
|
-
editor: string; // main editor background (brightest in light, darkest in dark)
|
|
197
|
-
window: string; // sidebar, activity bar, status bar, title bar, inactive tabs
|
|
198
|
-
inset: string; // inputs, dropdowns
|
|
199
|
-
elevated: string; // panels, hover backgrounds
|
|
200
|
-
};
|
|
201
|
-
fg: { base: string; fg1: string; fg2: string; fg3: string; fg4: string };
|
|
202
|
-
border: {
|
|
203
|
-
window: string; // borders for sidebar, activity bar, status bar, title bar
|
|
204
|
-
editor: string; // general editor borders
|
|
205
|
-
indentGuide: string; // indent guide lines
|
|
206
|
-
indentGuideActive: string; // active indent guide line
|
|
207
|
-
inset: string; // borders for inputs, dropdowns
|
|
208
|
-
elevated: string; // borders for panels
|
|
209
|
-
};
|
|
210
|
-
accent: { primary: string; link: string; subtle: string; contrastOnAccent: string };
|
|
211
|
-
states: { merge: string, success: string; danger: string; warn: string; info: string };
|
|
212
|
-
syntax: {
|
|
213
|
-
comment: string; string: string; number: string; keyword: string;
|
|
214
|
-
regexp: string; func: string; type: string; variable: string;
|
|
215
|
-
// Extended token types
|
|
216
|
-
operator: string; punctuation: string; constant: string;
|
|
217
|
-
parameter: string; namespace: string; decorator: string;
|
|
218
|
-
escape: string; invalid: string; tag: string; attribute: string;
|
|
219
|
-
};
|
|
220
|
-
ansi: {
|
|
221
|
-
black: string; red: string; green: string; yellow: string;
|
|
222
|
-
blue: string; magenta: string; cyan: string; white: string;
|
|
223
|
-
brightBlack: string; brightRed: string; brightGreen: string; brightYellow: string;
|
|
224
|
-
brightBlue: string; brightMagenta: string; brightCyan: string; brightWhite: string;
|
|
225
|
-
};
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
export const light: Roles = {
|
|
229
|
-
bg: {
|
|
230
|
-
editor: "#ffffff",
|
|
231
|
-
window: gray["060"],
|
|
232
|
-
inset: gray["080"],
|
|
233
|
-
elevated: gray["040"]
|
|
234
|
-
},
|
|
235
|
-
fg: {
|
|
236
|
-
base: gray["1040"],
|
|
237
|
-
fg1: gray["900"],
|
|
238
|
-
fg2: gray["800"],
|
|
239
|
-
fg3: gray["600"],
|
|
240
|
-
fg4: gray["500"]
|
|
241
|
-
},
|
|
242
|
-
border: {
|
|
243
|
-
window: gray["100"],
|
|
244
|
-
editor: gray["200"],
|
|
245
|
-
indentGuide: gray["100"],
|
|
246
|
-
indentGuideActive: gray["200"],
|
|
247
|
-
inset: gray["200"],
|
|
248
|
-
elevated: gray["100"]
|
|
249
|
-
},
|
|
250
|
-
accent: {
|
|
251
|
-
primary: blue["500"],
|
|
252
|
-
link: blue["500"],
|
|
253
|
-
subtle: blue["100"],
|
|
254
|
-
contrastOnAccent: "#ffffff"
|
|
255
|
-
},
|
|
256
|
-
states: {
|
|
257
|
-
merge: indigo["500"],
|
|
258
|
-
success: mint["500"],
|
|
259
|
-
danger: red["500"],
|
|
260
|
-
warn: yellow["500"],
|
|
261
|
-
info: cyan["500"]
|
|
262
|
-
},
|
|
263
|
-
syntax: {
|
|
264
|
-
comment: gray["600"],
|
|
265
|
-
string: green["600"],
|
|
266
|
-
number: cyan["600"],
|
|
267
|
-
keyword: pink["500"],
|
|
268
|
-
regexp: teal["600"],
|
|
269
|
-
func: indigo["500"],
|
|
270
|
-
type: purple["500"],
|
|
271
|
-
variable: orange["600"],
|
|
272
|
-
// Extended token types
|
|
273
|
-
operator: cyan["500"],
|
|
274
|
-
punctuation: gray["700"],
|
|
275
|
-
constant: yellow["600"],
|
|
276
|
-
parameter: gray["700"],
|
|
277
|
-
namespace: yellow["600"],
|
|
278
|
-
decorator: blue["500"],
|
|
279
|
-
escape: cyan["600"],
|
|
280
|
-
invalid: gray["1040"],
|
|
281
|
-
tag: red["600"],
|
|
282
|
-
attribute: mint["600"]
|
|
283
|
-
},
|
|
284
|
-
ansi: {
|
|
285
|
-
black: gray["980"],
|
|
286
|
-
red: red["500"],
|
|
287
|
-
green: green["500"],
|
|
288
|
-
yellow: yellow["500"],
|
|
289
|
-
blue: blue["500"],
|
|
290
|
-
magenta: purple["500"],
|
|
291
|
-
cyan: cyan["500"],
|
|
292
|
-
white: gray["300"],
|
|
293
|
-
// make bright colors match the non-bright counterparts
|
|
294
|
-
brightBlack: gray["980"],
|
|
295
|
-
brightRed: red["500"],
|
|
296
|
-
brightGreen: green["500"],
|
|
297
|
-
brightYellow: yellow["500"],
|
|
298
|
-
brightBlue: blue["500"],
|
|
299
|
-
brightMagenta: purple["500"],
|
|
300
|
-
brightCyan: cyan["500"],
|
|
301
|
-
brightWhite: gray["300"]
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
export const dark: Roles = {
|
|
306
|
-
bg: {
|
|
307
|
-
editor: gray["1040"],
|
|
308
|
-
window: gray["1000"],
|
|
309
|
-
inset: gray["980"],
|
|
310
|
-
elevated: gray["1020"]
|
|
311
|
-
},
|
|
312
|
-
fg: {
|
|
313
|
-
base: gray["020"],
|
|
314
|
-
fg1: gray["200"],
|
|
315
|
-
fg2: gray["400"],
|
|
316
|
-
fg3: gray["600"],
|
|
317
|
-
fg4: gray["700"]
|
|
318
|
-
},
|
|
319
|
-
border: {
|
|
320
|
-
window: gray["1040"],
|
|
321
|
-
editor: gray["980"],
|
|
322
|
-
indentGuide: gray["980"],
|
|
323
|
-
indentGuideActive: gray["960"],
|
|
324
|
-
inset: gray["980"],
|
|
325
|
-
elevated: gray["980"]
|
|
326
|
-
},
|
|
327
|
-
accent: {
|
|
328
|
-
primary: blue["500"],
|
|
329
|
-
link: blue["500"],
|
|
330
|
-
subtle: blue["950"],
|
|
331
|
-
contrastOnAccent: gray["1040"]
|
|
332
|
-
},
|
|
333
|
-
states: {
|
|
334
|
-
merge: indigo["500"],
|
|
335
|
-
success: mint["500"],
|
|
336
|
-
danger: red["500"],
|
|
337
|
-
warn: yellow["500"],
|
|
338
|
-
info: cyan["500"]
|
|
339
|
-
},
|
|
340
|
-
syntax: {
|
|
341
|
-
comment: gray["600"],
|
|
342
|
-
string: green["400"],
|
|
343
|
-
number: cyan["400"],
|
|
344
|
-
keyword: pink["400"],
|
|
345
|
-
regexp: teal["400"],
|
|
346
|
-
func: indigo["400"],
|
|
347
|
-
type: purple["400"],
|
|
348
|
-
variable: orange["400"],
|
|
349
|
-
// Extended token types
|
|
350
|
-
operator: cyan["500"],
|
|
351
|
-
punctuation: gray["700"],
|
|
352
|
-
constant: yellow["400"],
|
|
353
|
-
parameter: gray["400"],
|
|
354
|
-
namespace: yellow["500"],
|
|
355
|
-
decorator: blue["400"],
|
|
356
|
-
escape: cyan["400"],
|
|
357
|
-
invalid: gray["020"],
|
|
358
|
-
tag: red["400"],
|
|
359
|
-
attribute: mint["400"]
|
|
360
|
-
},
|
|
361
|
-
ansi: {
|
|
362
|
-
black: gray["1000"],
|
|
363
|
-
red: red["500"],
|
|
364
|
-
green: green["500"],
|
|
365
|
-
yellow: yellow["500"],
|
|
366
|
-
blue: blue["500"],
|
|
367
|
-
magenta: purple["500"],
|
|
368
|
-
cyan: cyan["500"],
|
|
369
|
-
white: gray["300"],
|
|
370
|
-
brightBlack: gray["1000"],
|
|
371
|
-
brightRed: red["500"],
|
|
372
|
-
brightGreen: green["500"],
|
|
373
|
-
brightYellow: yellow["500"],
|
|
374
|
-
brightBlue: blue["500"],
|
|
375
|
-
brightMagenta: purple["500"],
|
|
376
|
-
brightCyan: cyan["500"],
|
|
377
|
-
brightWhite: gray["300"]
|
|
378
|
-
}
|
|
379
|
-
};
|
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
|
-
}
|