@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/README.md +26 -2
- 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 +17 -2
- package/.github/workflows/publish.yml +0 -62
- package/.github/workflows/test.yml +0 -66
- package/.vscode/extensions.json +0 -5
- package/.vscode/launch.json +0 -24
- package/.vscode/tasks.json +0 -24
- package/.vscodeignore +0 -9
- package/CONTRIBUTING.md +0 -75
- package/DISPLAY-P3.md +0 -120
- package/src/build.ts +0 -39
- 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/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
|
-
}
|