css-is-awesome 1.16.1 → 1.18.0
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/AGENTS.md +10 -5
- package/CHANGELOG.md +20 -0
- package/CONTRACT.md +19 -0
- package/README.md +7 -3
- package/VERSIONING.md +1 -0
- package/bin/cia.cjs +19 -0
- package/bin/theme-from-tokens.cjs +139 -0
- package/dist/tokens.d.ts +1 -1
- package/figma-tokens/README.md +15 -0
- package/llm.txt +3 -3
- package/mcp/server.cjs +45 -3
- package/package.json +3 -1
- package/scripts/theme-contract.json +96 -3
- package/scripts/theme-validator.js +33 -7
- package/scripts/tokens-to-theme.cjs +668 -0
|
@@ -342,7 +342,19 @@ function validateTokenSet(declared, contract) {
|
|
|
342
342
|
for (const optional of Array.isArray(contract.optional) ? contract.optional : []) {
|
|
343
343
|
if (!declared.has(optional)) optionalMissing.push(optional);
|
|
344
344
|
}
|
|
345
|
-
|
|
345
|
+
// Contract 1.2: group by the feature each optional token enables, so the
|
|
346
|
+
// report can say "missing the tokens for print" instead of listing 41 names.
|
|
347
|
+
const featureOf = {};
|
|
348
|
+
const features = contract.features && typeof contract.features === 'object' ? contract.features : {};
|
|
349
|
+
for (const [feature, def] of Object.entries(features)) {
|
|
350
|
+
for (const t of (def && Array.isArray(def.tokens)) ? def.tokens : []) featureOf[t] = feature;
|
|
351
|
+
}
|
|
352
|
+
const optionalMissingByFeature = {};
|
|
353
|
+
for (const t of optionalMissing) {
|
|
354
|
+
const f = featureOf[t] || 'other';
|
|
355
|
+
(optionalMissingByFeature[f] = optionalMissingByFeature[f] || []).push(t);
|
|
356
|
+
}
|
|
357
|
+
return { ok: missing.length === 0, missing, optionalMissing, optionalMissingByFeature, declaredCount: declared.size };
|
|
346
358
|
}
|
|
347
359
|
|
|
348
360
|
// -----------------------------------------------------------
|
|
@@ -367,6 +379,7 @@ function validateText(text, contract, options) {
|
|
|
367
379
|
declaredCount: 0,
|
|
368
380
|
missing: [],
|
|
369
381
|
optionalMissing: [],
|
|
382
|
+
optionalMissingByFeature: {},
|
|
370
383
|
themes: null,
|
|
371
384
|
a11y: null,
|
|
372
385
|
error: null,
|
|
@@ -389,6 +402,7 @@ function validateText(text, contract, options) {
|
|
|
389
402
|
declaredCount: v.declaredCount,
|
|
390
403
|
missing: v.missing,
|
|
391
404
|
optionalMissing: v.optionalMissing,
|
|
405
|
+
optionalMissingByFeature: v.optionalMissingByFeature,
|
|
392
406
|
a11y: null,
|
|
393
407
|
};
|
|
394
408
|
if (wantA11y) theme.a11y = a11y.auditThemeTokens({ name: b.name, values: b.values });
|
|
@@ -417,6 +431,7 @@ function validateText(text, contract, options) {
|
|
|
417
431
|
result.declaredCount = v.declaredCount;
|
|
418
432
|
result.missing = v.missing;
|
|
419
433
|
result.optionalMissing = v.optionalMissing;
|
|
434
|
+
result.optionalMissingByFeature = v.optionalMissingByFeature;
|
|
420
435
|
result.ok = v.ok;
|
|
421
436
|
if (wantA11y) {
|
|
422
437
|
const inferredName = label !== '(pasted CSS)' ? (path.basename(path.dirname(label)) || path.basename(label, '.css')) : 'theme';
|
|
@@ -456,11 +471,18 @@ function relForDisplay(p) {
|
|
|
456
471
|
|
|
457
472
|
// Optional tokens a theme leaves to the library default. Info only — shown as
|
|
458
473
|
// a count, or listed with --show-optional. Never affects the exit code.
|
|
459
|
-
function optionalInfo(optionalMissing, indent) {
|
|
474
|
+
function optionalInfo(optionalMissing, byFeature, indent) {
|
|
460
475
|
const list = Array.isArray(optionalMissing) ? optionalMissing : [];
|
|
461
476
|
if (!list.length) return;
|
|
462
|
-
|
|
463
|
-
|
|
477
|
+
const groups = byFeature && typeof byFeature === 'object' ? byFeature : {};
|
|
478
|
+
const summary = Object.entries(groups).map(([f, ts]) => `${f} ${ts.length}`).join(' · ');
|
|
479
|
+
console.log(`${indent}${dim(`i ${list.length} optional token(s) not declared — library default applies${summary ? ` (${summary})` : ''}`)}`);
|
|
480
|
+
if (SHOW_OPTIONAL) {
|
|
481
|
+
for (const [f, ts] of Object.entries(groups)) {
|
|
482
|
+
console.log(`${indent} ${dim(f + ':')}`);
|
|
483
|
+
for (const token of ts) console.log(`${indent} ${dim(token)}`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
464
486
|
}
|
|
465
487
|
|
|
466
488
|
function reportResult(result) {
|
|
@@ -483,7 +505,7 @@ function reportResult(result) {
|
|
|
483
505
|
console.log(
|
|
484
506
|
` ${green('✓')} [data-theme="${t.name}"] ${dim(`(${t.declaredCount} tokens)`)}`
|
|
485
507
|
);
|
|
486
|
-
optionalInfo(t.optionalMissing, ' ');
|
|
508
|
+
optionalInfo(t.optionalMissing, t.optionalMissingByFeature, ' ');
|
|
487
509
|
} else {
|
|
488
510
|
const n = t.missing.length;
|
|
489
511
|
console.log(
|
|
@@ -502,7 +524,7 @@ function reportResult(result) {
|
|
|
502
524
|
console.log(
|
|
503
525
|
`${green('✓')} ${bold(rel)} ${dim(`passes (${result.declaredCount} tokens declared)`)}`
|
|
504
526
|
);
|
|
505
|
-
optionalInfo(result.optionalMissing, ' ');
|
|
527
|
+
optionalInfo(result.optionalMissing, result.optionalMissingByFeature, ' ');
|
|
506
528
|
return;
|
|
507
529
|
}
|
|
508
530
|
|
|
@@ -583,7 +605,7 @@ function printUsage() {
|
|
|
583
605
|
' --all validate every theme.css under public/ (CI mode)',
|
|
584
606
|
' --no-a11y skip the WCAG 2.2 AA contrast audit',
|
|
585
607
|
' --allow-a11y-fail do NOT exit non-zero on a11y FAILs (report only)',
|
|
586
|
-
' --show-optional list optional contract tokens a theme leaves to the library default (info only)',
|
|
608
|
+
' --show-optional list optional contract tokens a theme leaves to the library default, grouped by feature (info only)',
|
|
587
609
|
' --strict accepted for backwards compatibility (no-op; FAIL is now the default)',
|
|
588
610
|
'',
|
|
589
611
|
'Exit codes:',
|
|
@@ -713,6 +735,10 @@ module.exports = {
|
|
|
713
735
|
validateFile,
|
|
714
736
|
validateText,
|
|
715
737
|
loadContract,
|
|
738
|
+
// Reporters — reused by `cia theme from-tokens` so its output reads exactly
|
|
739
|
+
// like `npm run validate-themes`.
|
|
740
|
+
reportResult,
|
|
741
|
+
reportA11yForTheme,
|
|
716
742
|
a11y: a11y,
|
|
717
743
|
};
|
|
718
744
|
|