@lessonkit/themes 1.3.0 → 1.3.1
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.cjs +16 -3
- package/dist/index.js +16 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -74,7 +74,7 @@ function isNonEmptyString(v) {
|
|
|
74
74
|
return typeof v === "string" && v.trim().length > 0;
|
|
75
75
|
}
|
|
76
76
|
function isSafeCssCustomPropertyValue(value) {
|
|
77
|
-
return !/[;}\r\n]/.test(value) && !value.includes("/*");
|
|
77
|
+
return !/[;}\r\n\\<>]/.test(value) && !value.includes("/*");
|
|
78
78
|
}
|
|
79
79
|
function validateCssTokenValue(path, value, issues) {
|
|
80
80
|
if (!isSafeCssCustomPropertyValue(value)) {
|
|
@@ -224,9 +224,16 @@ function mergeThemes(base, ...overrides) {
|
|
|
224
224
|
|
|
225
225
|
// src/cssVariables.ts
|
|
226
226
|
function sanitizeCssCustomPropertyValue(value) {
|
|
227
|
-
if (/[;}\r\n]/.test(value) || value.includes("/*")) return null;
|
|
227
|
+
if (/[;}\r\n\\<>]/.test(value) || value.includes("/*")) return null;
|
|
228
228
|
return value;
|
|
229
229
|
}
|
|
230
|
+
function isSafeCssSelector(selector) {
|
|
231
|
+
if (selector === ":root") return true;
|
|
232
|
+
if (/^\.[a-zA-Z_][\w-]*$/.test(selector)) return true;
|
|
233
|
+
if (/^#[a-zA-Z_][\w-]*$/.test(selector)) return true;
|
|
234
|
+
if (/^\[data-lk-theme=(["'])[^"']+\1\]$/.test(selector)) return true;
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
230
237
|
function assignCssVar(vars, key, value) {
|
|
231
238
|
const safe = sanitizeCssCustomPropertyValue(value);
|
|
232
239
|
if (safe !== null) vars[key] = safe;
|
|
@@ -283,6 +290,9 @@ function themeToCssVariables(theme) {
|
|
|
283
290
|
}
|
|
284
291
|
function themeToCssDeclarationBlock(theme, opts) {
|
|
285
292
|
const selector = opts?.selector ?? ":root";
|
|
293
|
+
if (!isSafeCssSelector(selector)) {
|
|
294
|
+
throw new Error(`[lessonkit] unsafe CSS selector for theme block: ${selector}`);
|
|
295
|
+
}
|
|
286
296
|
const vars = themeToCssVariables(theme);
|
|
287
297
|
const body = Object.entries(vars).map(([k, v]) => ` ${k}: ${v};`).join("\n");
|
|
288
298
|
return `${selector} {
|
|
@@ -400,8 +410,11 @@ var PRESETS = {
|
|
|
400
410
|
dark: darkTheme,
|
|
401
411
|
brand: brandTheme
|
|
402
412
|
};
|
|
413
|
+
function cloneTheme(theme) {
|
|
414
|
+
return JSON.parse(JSON.stringify(theme));
|
|
415
|
+
}
|
|
403
416
|
function getPresetTheme(preset) {
|
|
404
|
-
return PRESETS[preset];
|
|
417
|
+
return cloneTheme(PRESETS[preset]);
|
|
405
418
|
}
|
|
406
419
|
|
|
407
420
|
// src/catalog.ts
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ function isNonEmptyString(v) {
|
|
|
25
25
|
return typeof v === "string" && v.trim().length > 0;
|
|
26
26
|
}
|
|
27
27
|
function isSafeCssCustomPropertyValue(value) {
|
|
28
|
-
return !/[;}\r\n]/.test(value) && !value.includes("/*");
|
|
28
|
+
return !/[;}\r\n\\<>]/.test(value) && !value.includes("/*");
|
|
29
29
|
}
|
|
30
30
|
function validateCssTokenValue(path, value, issues) {
|
|
31
31
|
if (!isSafeCssCustomPropertyValue(value)) {
|
|
@@ -175,9 +175,16 @@ function mergeThemes(base, ...overrides) {
|
|
|
175
175
|
|
|
176
176
|
// src/cssVariables.ts
|
|
177
177
|
function sanitizeCssCustomPropertyValue(value) {
|
|
178
|
-
if (/[;}\r\n]/.test(value) || value.includes("/*")) return null;
|
|
178
|
+
if (/[;}\r\n\\<>]/.test(value) || value.includes("/*")) return null;
|
|
179
179
|
return value;
|
|
180
180
|
}
|
|
181
|
+
function isSafeCssSelector(selector) {
|
|
182
|
+
if (selector === ":root") return true;
|
|
183
|
+
if (/^\.[a-zA-Z_][\w-]*$/.test(selector)) return true;
|
|
184
|
+
if (/^#[a-zA-Z_][\w-]*$/.test(selector)) return true;
|
|
185
|
+
if (/^\[data-lk-theme=(["'])[^"']+\1\]$/.test(selector)) return true;
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
181
188
|
function assignCssVar(vars, key, value) {
|
|
182
189
|
const safe = sanitizeCssCustomPropertyValue(value);
|
|
183
190
|
if (safe !== null) vars[key] = safe;
|
|
@@ -234,6 +241,9 @@ function themeToCssVariables(theme) {
|
|
|
234
241
|
}
|
|
235
242
|
function themeToCssDeclarationBlock(theme, opts) {
|
|
236
243
|
const selector = opts?.selector ?? ":root";
|
|
244
|
+
if (!isSafeCssSelector(selector)) {
|
|
245
|
+
throw new Error(`[lessonkit] unsafe CSS selector for theme block: ${selector}`);
|
|
246
|
+
}
|
|
237
247
|
const vars = themeToCssVariables(theme);
|
|
238
248
|
const body = Object.entries(vars).map(([k, v]) => ` ${k}: ${v};`).join("\n");
|
|
239
249
|
return `${selector} {
|
|
@@ -351,8 +361,11 @@ var PRESETS = {
|
|
|
351
361
|
dark: darkTheme,
|
|
352
362
|
brand: brandTheme
|
|
353
363
|
};
|
|
364
|
+
function cloneTheme(theme) {
|
|
365
|
+
return JSON.parse(JSON.stringify(theme));
|
|
366
|
+
}
|
|
354
367
|
function getPresetTheme(preset) {
|
|
355
|
-
return PRESETS[preset];
|
|
368
|
+
return cloneTheme(PRESETS[preset]);
|
|
356
369
|
}
|
|
357
370
|
|
|
358
371
|
// src/catalog.ts
|