design-constraint-validator 1.0.0 → 1.1.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/LICENSE +21 -21
- package/README.md +215 -659
- package/adapters/README.md +46 -46
- package/adapters/css.ts +116 -116
- package/adapters/js.ts +14 -14
- package/adapters/json.ts +45 -45
- package/cli/build-css.ts +32 -32
- package/cli/commands/build.ts +65 -65
- package/cli/commands/graph.d.ts.map +1 -1
- package/cli/commands/graph.js +26 -10
- package/cli/commands/graph.ts +180 -137
- package/cli/commands/index.ts +7 -7
- package/cli/commands/patch-apply.ts +80 -80
- package/cli/commands/patch.ts +22 -22
- package/cli/commands/set.d.ts.map +1 -1
- package/cli/commands/set.js +12 -4
- package/cli/commands/set.ts +239 -225
- package/cli/commands/utils.ts +50 -50
- package/cli/commands/validate.d.ts.map +1 -1
- package/cli/commands/validate.js +86 -33
- package/cli/commands/validate.ts +176 -115
- package/cli/commands/why.d.ts.map +1 -1
- package/cli/commands/why.js +86 -20
- package/cli/commands/why.ts +158 -46
- package/cli/config-schema.ts +27 -27
- package/cli/config.ts +35 -35
- package/cli/constraint-registry.d.ts +101 -0
- package/cli/constraint-registry.d.ts.map +1 -0
- package/cli/constraint-registry.js +225 -0
- package/cli/constraint-registry.ts +304 -0
- package/cli/constraints-loader.d.ts +30 -0
- package/cli/constraints-loader.d.ts.map +1 -0
- package/cli/constraints-loader.js +58 -0
- package/cli/constraints-loader.ts +83 -0
- package/cli/cross-axis-loader.d.ts +91 -0
- package/cli/cross-axis-loader.d.ts.map +1 -0
- package/cli/cross-axis-loader.js +222 -0
- package/cli/cross-axis-loader.ts +289 -0
- package/cli/dcv.js +4 -0
- package/cli/dcv.ts +111 -107
- package/cli/engine-helpers.d.ts +33 -0
- package/cli/engine-helpers.d.ts.map +1 -1
- package/cli/engine-helpers.js +87 -22
- package/cli/engine-helpers.ts +133 -61
- package/cli/graph-poset.ts +74 -74
- package/cli/json-output.d.ts +64 -0
- package/cli/json-output.d.ts.map +1 -0
- package/cli/json-output.js +107 -0
- package/cli/json-output.ts +177 -0
- package/cli/result.ts +27 -27
- package/cli/run.ts +54 -54
- package/cli/smoke-test.ts +40 -40
- package/cli/types.d.ts +6 -0
- package/cli/types.d.ts.map +1 -1
- package/cli/types.ts +84 -78
- package/core/breakpoints.ts +50 -50
- package/core/cli-format.ts +31 -31
- package/core/color.ts +148 -148
- package/core/constraints/cross-axis.ts +114 -114
- package/core/constraints/monotonic-lightness.ts +38 -38
- package/core/constraints/monotonic.ts +74 -74
- package/core/constraints/threshold.ts +43 -43
- package/core/constraints/wcag.ts +70 -70
- package/core/cross-axis-config.d.ts +29 -0
- package/core/cross-axis-config.d.ts.map +1 -1
- package/core/cross-axis-config.js +29 -0
- package/core/cross-axis-config.ts +181 -151
- package/core/engine.d.ts +95 -0
- package/core/engine.d.ts.map +1 -1
- package/core/engine.js +22 -0
- package/core/engine.ts +167 -65
- package/core/flatten.ts +116 -116
- package/core/image-export.ts +48 -48
- package/core/index.d.ts +9 -30
- package/core/index.d.ts.map +1 -1
- package/core/index.js +7 -54
- package/core/index.ts +10 -72
- package/core/patch.ts +134 -134
- package/core/poset.ts +311 -311
- package/core/why.ts +63 -63
- package/package.json +96 -90
- package/themes/color.lg.order.json +15 -15
- package/themes/color.md.order.json +15 -15
- package/themes/color.order.json +15 -15
- package/themes/color.sm.order.json +15 -15
- package/themes/cross-axis.rules.json +35 -35
- package/themes/cross-axis.sm.rules.json +12 -12
- package/themes/layout.lg.order.json +18 -18
- package/themes/layout.md.order.json +18 -18
- package/themes/layout.order.json +18 -18
- package/themes/layout.sm.order.json +18 -18
- package/themes/spacing.order.json +14 -14
- package/themes/typography.lg.order.json +15 -15
- package/themes/typography.md.order.json +15 -15
- package/themes/typography.order.json +15 -15
- package/themes/typography.sm.order.json +15 -15
- package/dist/test-overrides-removal.json +0 -4
- package/dist/tmp.patch.json +0 -35
- package/tokens/overrides/base.json +0 -22
- package/tokens/overrides/lg.json +0 -20
- package/tokens/overrides/md.json +0 -16
- package/tokens/overrides/sm.json +0 -16
- package/tokens/overrides/viol.color.json +0 -6
- package/tokens/overrides/viol.typography.json +0 -6
- package/tokens/tokens.demo-violations.json +0 -116
- package/tokens/tokens.example.json +0 -128
- package/tokens/tokens.json +0 -67
- package/tokens/tokens.multi-violations.json +0 -21
- package/tokens/tokens.schema.d.ts +0 -2298
- package/tokens/tokens.schema.d.ts.map +0 -1
- package/tokens/tokens.schema.js +0 -148
- package/tokens/tokens.schema.ts +0 -196
- package/tokens/tokens.test.json +0 -38
- package/tokens/tokens.touch-violation.json +0 -8
- package/tokens/typography.classes.css +0 -11
- package/tokens/typography.css +0 -20
package/cli/smoke-test.ts
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
// cli/smoke-test.ts
|
|
2
|
-
import { writeFileSync, readFileSync, mkdirSync } from "node:fs";
|
|
3
|
-
import { dirname } from "node:path";
|
|
4
|
-
import { flattenTokens } from "../core/flatten.js";
|
|
5
|
-
import { Engine } from "../core/engine.js";
|
|
6
|
-
import { WcagContrastPlugin } from "../core/constraints/wcag.js";
|
|
7
|
-
import { patchToCss } from "../adapters/css.js";
|
|
8
|
-
|
|
9
|
-
// 1. Flatten tokens
|
|
10
|
-
const tokensRoot = JSON.parse(readFileSync("tokens/tokens.example.json", "utf8"));
|
|
11
|
-
const { flat, edges } = flattenTokens(tokensRoot);
|
|
12
|
-
|
|
13
|
-
// 2. Build engine
|
|
14
|
-
const init: Record<string, string | number> = {};
|
|
15
|
-
for (const [id, t] of Object.entries(flat)) init[id] = t.value;
|
|
16
|
-
|
|
17
|
-
const engine = new Engine(init, edges).use(
|
|
18
|
-
WcagContrastPlugin([
|
|
19
|
-
{ fg: "color.role.text.default", bg: "color.role.bg.surface", min: 4.5, where: "Body text" },
|
|
20
|
-
])
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
// 3. Commit one change
|
|
24
|
-
const overrideId = "color.palette.brand.600";
|
|
25
|
-
const overrideValue = "#FF00FF"; // A loud magenta to make it obvious
|
|
26
|
-
const result = engine.commit(overrideId, overrideValue);
|
|
27
|
-
|
|
28
|
-
console.log("--- Smoke Test ---");
|
|
29
|
-
console.log(`Committed: ${overrideId} = ${overrideValue}`);
|
|
30
|
-
console.log("Affected:", result.affected);
|
|
31
|
-
console.log("Issues:", result.issues);
|
|
32
|
-
console.log("Patch:", result.patch);
|
|
33
|
-
|
|
34
|
-
// 4. Write overrides.css using the adapter
|
|
35
|
-
const css = patchToCss(result.patch);
|
|
36
|
-
const outFile = "css/overrides.css";
|
|
37
|
-
mkdirSync(dirname(outFile), { recursive: true });
|
|
38
|
-
writeFileSync(outFile, css);
|
|
39
|
-
console.log(`\nWrote ${outFile}`);
|
|
40
|
-
console.log("--- End Smoke Test ---");
|
|
1
|
+
// cli/smoke-test.ts
|
|
2
|
+
import { writeFileSync, readFileSync, mkdirSync } from "node:fs";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { flattenTokens } from "../core/flatten.js";
|
|
5
|
+
import { Engine } from "../core/engine.js";
|
|
6
|
+
import { WcagContrastPlugin } from "../core/constraints/wcag.js";
|
|
7
|
+
import { patchToCss } from "../adapters/css.js";
|
|
8
|
+
|
|
9
|
+
// 1. Flatten tokens
|
|
10
|
+
const tokensRoot = JSON.parse(readFileSync("tokens/tokens.example.json", "utf8"));
|
|
11
|
+
const { flat, edges } = flattenTokens(tokensRoot);
|
|
12
|
+
|
|
13
|
+
// 2. Build engine
|
|
14
|
+
const init: Record<string, string | number> = {};
|
|
15
|
+
for (const [id, t] of Object.entries(flat)) init[id] = t.value;
|
|
16
|
+
|
|
17
|
+
const engine = new Engine(init, edges).use(
|
|
18
|
+
WcagContrastPlugin([
|
|
19
|
+
{ fg: "color.role.text.default", bg: "color.role.bg.surface", min: 4.5, where: "Body text" },
|
|
20
|
+
])
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// 3. Commit one change
|
|
24
|
+
const overrideId = "color.palette.brand.600";
|
|
25
|
+
const overrideValue = "#FF00FF"; // A loud magenta to make it obvious
|
|
26
|
+
const result = engine.commit(overrideId, overrideValue);
|
|
27
|
+
|
|
28
|
+
console.log("--- Smoke Test ---");
|
|
29
|
+
console.log(`Committed: ${overrideId} = ${overrideValue}`);
|
|
30
|
+
console.log("Affected:", result.affected);
|
|
31
|
+
console.log("Issues:", result.issues);
|
|
32
|
+
console.log("Patch:", result.patch);
|
|
33
|
+
|
|
34
|
+
// 4. Write overrides.css using the adapter
|
|
35
|
+
const css = patchToCss(result.patch);
|
|
36
|
+
const outFile = "css/overrides.css";
|
|
37
|
+
mkdirSync(dirname(outFile), { recursive: true });
|
|
38
|
+
writeFileSync(outFile, css);
|
|
39
|
+
console.log(`\nWrote ${outFile}`);
|
|
40
|
+
console.log("--- End Smoke Test ---");
|
package/cli/types.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export type OverridesTree = {
|
|
|
18
18
|
export interface GlobalOptions {
|
|
19
19
|
tokens?: string;
|
|
20
20
|
config?: string;
|
|
21
|
+
theme?: string;
|
|
21
22
|
verbose?: boolean;
|
|
22
23
|
quiet?: boolean;
|
|
23
24
|
breakpoint?: 'sm' | 'md' | 'lg';
|
|
@@ -47,6 +48,11 @@ export interface ValidateOptions extends GlobalOptions {
|
|
|
47
48
|
perf?: boolean;
|
|
48
49
|
budgetTotalMs?: number;
|
|
49
50
|
budgetPerBpMs?: number;
|
|
51
|
+
format?: 'text' | 'json';
|
|
52
|
+
output?: string;
|
|
53
|
+
receipt?: string;
|
|
54
|
+
failOn?: 'off' | 'warn' | 'error';
|
|
55
|
+
summary?: 'none' | 'table' | 'json';
|
|
50
56
|
}
|
|
51
57
|
export interface GraphOptions extends GlobalOptions {
|
|
52
58
|
output?: string;
|
package/cli/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,WAAW,cAAc;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE;AAChH,MAAM,MAAM,SAAS,GAAG,eAAe,CAAC;AACxC,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AACrD,MAAM,WAAW,aAAa;IAAG,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAAE;AAClE,MAAM,MAAM,aAAa,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,aAAa,CAAA;CAAE,GAAG,aAAa,CAAC;AAE3F,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAChC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AACD,MAAM,WAAW,UAAW,SAAQ,aAAa;IAC/C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AACD,MAAM,WAAW,YAAa,SAAQ,aAAa;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AACD,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"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"}
|
package/cli/types.ts
CHANGED
|
@@ -1,78 +1,84 @@
|
|
|
1
|
-
import type { TokenValue } from '../core/flatten.js';
|
|
2
|
-
import type { Breakpoint } from '../core/breakpoints.js';
|
|
3
|
-
import type { DcvConfigParsed } from './config-schema.js';
|
|
4
|
-
|
|
5
|
-
export interface WcagRuleConfig { foreground: string; background: string; ratio?: number; description?: string }
|
|
6
|
-
export type DcvConfig = DcvConfigParsed;
|
|
7
|
-
export type ValuesPatch = Record<string, TokenValue>;
|
|
8
|
-
export interface OverridesLeaf { $value?: string | number | null }
|
|
9
|
-
export type OverridesTree = { [k: string]: OverridesTree | OverridesLeaf } & OverridesLeaf;
|
|
10
|
-
|
|
11
|
-
export interface GlobalOptions {
|
|
12
|
-
tokens?: string;
|
|
13
|
-
config?: string;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
output?: string;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
export interface
|
|
73
|
-
|
|
74
|
-
output?: string;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
export
|
|
1
|
+
import type { TokenValue } from '../core/flatten.js';
|
|
2
|
+
import type { Breakpoint } from '../core/breakpoints.js';
|
|
3
|
+
import type { DcvConfigParsed } from './config-schema.js';
|
|
4
|
+
|
|
5
|
+
export interface WcagRuleConfig { foreground: string; background: string; ratio?: number; description?: string }
|
|
6
|
+
export type DcvConfig = DcvConfigParsed;
|
|
7
|
+
export type ValuesPatch = Record<string, TokenValue>;
|
|
8
|
+
export interface OverridesLeaf { $value?: string | number | null }
|
|
9
|
+
export type OverridesTree = { [k: string]: OverridesTree | OverridesLeaf } & OverridesLeaf;
|
|
10
|
+
|
|
11
|
+
export interface GlobalOptions {
|
|
12
|
+
tokens?: string;
|
|
13
|
+
config?: string;
|
|
14
|
+
theme?: string;
|
|
15
|
+
verbose?: boolean;
|
|
16
|
+
quiet?: boolean;
|
|
17
|
+
breakpoint?: 'sm' | 'md' | 'lg';
|
|
18
|
+
allBreakpoints?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface SetOptions extends GlobalOptions {
|
|
21
|
+
expressions: string[];
|
|
22
|
+
output?: string;
|
|
23
|
+
format?: 'json' | 'css' | 'js';
|
|
24
|
+
theme?: string;
|
|
25
|
+
write?: boolean;
|
|
26
|
+
json?: string;
|
|
27
|
+
unset?: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface BuildOptions extends GlobalOptions {
|
|
30
|
+
output?: string;
|
|
31
|
+
format?: 'css' | 'json' | 'js';
|
|
32
|
+
watch?: boolean;
|
|
33
|
+
theme?: string;
|
|
34
|
+
mapper?: string;
|
|
35
|
+
dryRun?: boolean;
|
|
36
|
+
allFormats?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface ValidateOptions extends GlobalOptions {
|
|
39
|
+
strict?: boolean;
|
|
40
|
+
constraints?: string[];
|
|
41
|
+
perf?: boolean;
|
|
42
|
+
budgetTotalMs?: number;
|
|
43
|
+
budgetPerBpMs?: number;
|
|
44
|
+
format?: 'text' | 'json';
|
|
45
|
+
output?: string;
|
|
46
|
+
receipt?: string;
|
|
47
|
+
failOn?: 'off' | 'warn' | 'error';
|
|
48
|
+
summary?: 'none' | 'table' | 'json';
|
|
49
|
+
}
|
|
50
|
+
export interface GraphOptions extends GlobalOptions {
|
|
51
|
+
output?: string;
|
|
52
|
+
format?: 'dot' | 'mermaid' | 'json' | 'svg' | 'png';
|
|
53
|
+
imageFrom?: 'mermaid' | 'dot';
|
|
54
|
+
filter?: string;
|
|
55
|
+
hasse?: string;
|
|
56
|
+
filterPrefix?: string;
|
|
57
|
+
excludePrefix?: string;
|
|
58
|
+
onlyViolations?: boolean;
|
|
59
|
+
highlightViolations?: boolean;
|
|
60
|
+
violationColor?: string;
|
|
61
|
+
labelViolations?: boolean;
|
|
62
|
+
labelTruncate?: number;
|
|
63
|
+
minSeverity?: 'warn' | 'error';
|
|
64
|
+
focus?: string;
|
|
65
|
+
radius?: number;
|
|
66
|
+
tokens?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface WhyOptions extends GlobalOptions {
|
|
69
|
+
tokenId: string;
|
|
70
|
+
format?: 'json' | 'table';
|
|
71
|
+
}
|
|
72
|
+
export interface PatchOptions extends GlobalOptions {
|
|
73
|
+
overrides?: string; // path to flat overrides json or inline json
|
|
74
|
+
output?: string;
|
|
75
|
+
format?: 'json' | 'css' | 'js';
|
|
76
|
+
tokens?: string;
|
|
77
|
+
}
|
|
78
|
+
export interface PatchApplyOptions extends GlobalOptions {
|
|
79
|
+
patch: string; // path or inline patch JSON
|
|
80
|
+
output?: string; // where to write updated tokens (if omitted, prints result)
|
|
81
|
+
tokens?: string; // source tokens file (baseline)
|
|
82
|
+
dryRun?: boolean; // if true do not write
|
|
83
|
+
}
|
|
84
|
+
export type { Breakpoint };
|
package/core/breakpoints.ts
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
// core/breakpoints.ts
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import type { TokenNode } from "./flatten.js";
|
|
4
|
-
|
|
5
|
-
export type Breakpoint = "sm" | "md" | "lg";
|
|
6
|
-
|
|
7
|
-
export function parseBreakpoints(argv: string[]): Breakpoint[] {
|
|
8
|
-
const allIdx = argv.indexOf("--all-breakpoints");
|
|
9
|
-
if (allIdx >= 0) return ["sm", "md", "lg"];
|
|
10
|
-
const bpIdx = argv.indexOf("--breakpoint");
|
|
11
|
-
if (bpIdx >= 0) return [argv[bpIdx + 1] as Breakpoint];
|
|
12
|
-
return []; // no BP slicing requested
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function loadJsonSafe<T = unknown>(path: string): T | null {
|
|
16
|
-
try {
|
|
17
|
-
const data = JSON.parse(fs.readFileSync(path, "utf8"));
|
|
18
|
-
return data;
|
|
19
|
-
} catch {
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function loadOrders(axis: string, bp?: Breakpoint): [string, "<=" | ">=", string][] {
|
|
25
|
-
const withBp = bp ? loadJsonSafe<{ order: unknown[] }>(`themes/${axis}.${bp}.order.json`) : null;
|
|
26
|
-
if (withBp?.order) return withBp.order as [string, "<=" | ">=", string][];
|
|
27
|
-
const global = loadJsonSafe<{ order: unknown[] }>(`themes/${axis}.order.json`);
|
|
28
|
-
return (global?.order ?? []) as [string, "<=" | ">=", string][];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function mergeTokens(base: unknown, overlay: unknown): TokenNode {
|
|
32
|
-
if (!overlay) return base as TokenNode;
|
|
33
|
-
if (typeof base !== "object" || base === null) return overlay as TokenNode;
|
|
34
|
-
const out = Array.isArray(base) ? [...base] : { ...base };
|
|
35
|
-
for (const k of Object.keys(overlay as Record<string, unknown>)) {
|
|
36
|
-
(out as Record<string, unknown>)[k] = mergeTokens((base as Record<string, unknown>)?.[k], (overlay as Record<string, unknown>)[k]);
|
|
37
|
-
}
|
|
38
|
-
return out as TokenNode;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** Load tokens with optional breakpoint override: base + overrides/<bp>.json */
|
|
42
|
-
/**
|
|
43
|
-
* Load tokens with override precedence: base < local < breakpoint
|
|
44
|
-
*/
|
|
45
|
-
export function loadTokensWithBreakpoint(bp?: Breakpoint): TokenNode {
|
|
46
|
-
const base = loadJsonSafe<TokenNode>("tokens/tokens.example.json") ?? {};
|
|
47
|
-
const local = loadJsonSafe<TokenNode>("tokens/overrides/local.json");
|
|
48
|
-
const ov = bp ? loadJsonSafe<TokenNode>(`tokens/overrides/${bp}.json`) : null;
|
|
49
|
-
return mergeTokens(mergeTokens(base, local), ov);
|
|
50
|
-
}
|
|
1
|
+
// core/breakpoints.ts
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import type { TokenNode } from "./flatten.js";
|
|
4
|
+
|
|
5
|
+
export type Breakpoint = "sm" | "md" | "lg";
|
|
6
|
+
|
|
7
|
+
export function parseBreakpoints(argv: string[]): Breakpoint[] {
|
|
8
|
+
const allIdx = argv.indexOf("--all-breakpoints");
|
|
9
|
+
if (allIdx >= 0) return ["sm", "md", "lg"];
|
|
10
|
+
const bpIdx = argv.indexOf("--breakpoint");
|
|
11
|
+
if (bpIdx >= 0) return [argv[bpIdx + 1] as Breakpoint];
|
|
12
|
+
return []; // no BP slicing requested
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function loadJsonSafe<T = unknown>(path: string): T | null {
|
|
16
|
+
try {
|
|
17
|
+
const data = JSON.parse(fs.readFileSync(path, "utf8"));
|
|
18
|
+
return data;
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function loadOrders(axis: string, bp?: Breakpoint): [string, "<=" | ">=", string][] {
|
|
25
|
+
const withBp = bp ? loadJsonSafe<{ order: unknown[] }>(`themes/${axis}.${bp}.order.json`) : null;
|
|
26
|
+
if (withBp?.order) return withBp.order as [string, "<=" | ">=", string][];
|
|
27
|
+
const global = loadJsonSafe<{ order: unknown[] }>(`themes/${axis}.order.json`);
|
|
28
|
+
return (global?.order ?? []) as [string, "<=" | ">=", string][];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function mergeTokens(base: unknown, overlay: unknown): TokenNode {
|
|
32
|
+
if (!overlay) return base as TokenNode;
|
|
33
|
+
if (typeof base !== "object" || base === null) return overlay as TokenNode;
|
|
34
|
+
const out = Array.isArray(base) ? [...base] : { ...base };
|
|
35
|
+
for (const k of Object.keys(overlay as Record<string, unknown>)) {
|
|
36
|
+
(out as Record<string, unknown>)[k] = mergeTokens((base as Record<string, unknown>)?.[k], (overlay as Record<string, unknown>)[k]);
|
|
37
|
+
}
|
|
38
|
+
return out as TokenNode;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Load tokens with optional breakpoint override: base + overrides/<bp>.json */
|
|
42
|
+
/**
|
|
43
|
+
* Load tokens with override precedence: base < local < breakpoint
|
|
44
|
+
*/
|
|
45
|
+
export function loadTokensWithBreakpoint(bp?: Breakpoint): TokenNode {
|
|
46
|
+
const base = loadJsonSafe<TokenNode>("tokens/tokens.example.json") ?? {};
|
|
47
|
+
const local = loadJsonSafe<TokenNode>("tokens/overrides/local.json");
|
|
48
|
+
const ov = bp ? loadJsonSafe<TokenNode>(`tokens/overrides/${bp}.json`) : null;
|
|
49
|
+
return mergeTokens(mergeTokens(base, local), ov);
|
|
50
|
+
}
|
package/core/cli-format.ts
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
// core/cli-format.ts
|
|
2
|
-
export function pad(s: string, w: number) {
|
|
3
|
-
if (s.length >= w) return s;
|
|
4
|
-
return s + " ".repeat(w - s.length);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function trunc(s: string, w: number) {
|
|
8
|
-
return s.length <= w ? s : s.slice(0, Math.max(0, w - 1)) + "…";
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function levenshtein(a: string, b: string): number {
|
|
12
|
-
const dp = Array(b.length + 1).fill(0).map((_, j) => j);
|
|
13
|
-
for (let i = 1; i <= a.length; i++) {
|
|
14
|
-
let prev = i - 1, cur = i;
|
|
15
|
-
for (let j = 1; j <= b.length; j++) {
|
|
16
|
-
const tmp = cur;
|
|
17
|
-
cur = Math.min(dp[j] + 1, cur + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
18
|
-
dp[j] = tmp;
|
|
19
|
-
prev = tmp;
|
|
20
|
-
}
|
|
21
|
-
dp[b.length] = cur;
|
|
22
|
-
}
|
|
23
|
-
return dp[b.length];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function suggestIds(id: string, candidates: string[], k = 3): { id: string; d: number }[] {
|
|
27
|
-
return candidates
|
|
28
|
-
.map(c => ({ id: c, d: levenshtein(id, c) }))
|
|
29
|
-
.sort((x, y) => x.d - y.d)
|
|
30
|
-
.slice(0, k);
|
|
31
|
-
}
|
|
1
|
+
// core/cli-format.ts
|
|
2
|
+
export function pad(s: string, w: number) {
|
|
3
|
+
if (s.length >= w) return s;
|
|
4
|
+
return s + " ".repeat(w - s.length);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function trunc(s: string, w: number) {
|
|
8
|
+
return s.length <= w ? s : s.slice(0, Math.max(0, w - 1)) + "…";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function levenshtein(a: string, b: string): number {
|
|
12
|
+
const dp = Array(b.length + 1).fill(0).map((_, j) => j);
|
|
13
|
+
for (let i = 1; i <= a.length; i++) {
|
|
14
|
+
let prev = i - 1, cur = i;
|
|
15
|
+
for (let j = 1; j <= b.length; j++) {
|
|
16
|
+
const tmp = cur;
|
|
17
|
+
cur = Math.min(dp[j] + 1, cur + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
18
|
+
dp[j] = tmp;
|
|
19
|
+
prev = tmp;
|
|
20
|
+
}
|
|
21
|
+
dp[b.length] = cur;
|
|
22
|
+
}
|
|
23
|
+
return dp[b.length];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function suggestIds(id: string, candidates: string[], k = 3): { id: string; d: number }[] {
|
|
27
|
+
return candidates
|
|
28
|
+
.map(c => ({ id: c, d: levenshtein(id, c) }))
|
|
29
|
+
.sort((x, y) => x.d - y.d)
|
|
30
|
+
.slice(0, k);
|
|
31
|
+
}
|