design-constraint-validator 1.0.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.
Files changed (195) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +659 -0
  3. package/adapters/README.md +46 -0
  4. package/adapters/css.d.ts +44 -0
  5. package/adapters/css.d.ts.map +1 -0
  6. package/adapters/css.js +97 -0
  7. package/adapters/css.ts +116 -0
  8. package/adapters/js.d.ts +3 -0
  9. package/adapters/js.d.ts.map +1 -0
  10. package/adapters/js.js +15 -0
  11. package/adapters/js.ts +14 -0
  12. package/adapters/json.d.ts +18 -0
  13. package/adapters/json.d.ts.map +1 -0
  14. package/adapters/json.js +35 -0
  15. package/adapters/json.ts +45 -0
  16. package/cli/build-css.d.ts +2 -0
  17. package/cli/build-css.d.ts.map +1 -0
  18. package/cli/build-css.js +23 -0
  19. package/cli/build-css.ts +32 -0
  20. package/cli/commands/build.d.ts +5 -0
  21. package/cli/commands/build.d.ts.map +1 -0
  22. package/cli/commands/build.js +89 -0
  23. package/cli/commands/build.ts +65 -0
  24. package/cli/commands/graph.d.ts +3 -0
  25. package/cli/commands/graph.d.ts.map +1 -0
  26. package/cli/commands/graph.js +219 -0
  27. package/cli/commands/graph.ts +137 -0
  28. package/cli/commands/index.d.ts +8 -0
  29. package/cli/commands/index.d.ts.map +1 -0
  30. package/cli/commands/index.js +7 -0
  31. package/cli/commands/index.ts +7 -0
  32. package/cli/commands/patch-apply.d.ts +3 -0
  33. package/cli/commands/patch-apply.d.ts.map +1 -0
  34. package/cli/commands/patch-apply.js +75 -0
  35. package/cli/commands/patch-apply.ts +80 -0
  36. package/cli/commands/patch.d.ts +3 -0
  37. package/cli/commands/patch.d.ts.map +1 -0
  38. package/cli/commands/patch.js +21 -0
  39. package/cli/commands/patch.ts +22 -0
  40. package/cli/commands/set.d.ts +3 -0
  41. package/cli/commands/set.d.ts.map +1 -0
  42. package/cli/commands/set.js +286 -0
  43. package/cli/commands/set.ts +225 -0
  44. package/cli/commands/utils.d.ts +4 -0
  45. package/cli/commands/utils.d.ts.map +1 -0
  46. package/cli/commands/utils.js +51 -0
  47. package/cli/commands/utils.ts +50 -0
  48. package/cli/commands/validate.d.ts +3 -0
  49. package/cli/commands/validate.d.ts.map +1 -0
  50. package/cli/commands/validate.js +131 -0
  51. package/cli/commands/validate.ts +115 -0
  52. package/cli/commands/why.d.ts +3 -0
  53. package/cli/commands/why.d.ts.map +1 -0
  54. package/cli/commands/why.js +64 -0
  55. package/cli/commands/why.ts +46 -0
  56. package/cli/config-schema.d.ts +238 -0
  57. package/cli/config-schema.d.ts.map +1 -0
  58. package/cli/config-schema.js +21 -0
  59. package/cli/config-schema.ts +27 -0
  60. package/cli/config.d.ts +4 -0
  61. package/cli/config.d.ts.map +1 -0
  62. package/cli/config.js +37 -0
  63. package/cli/config.ts +35 -0
  64. package/cli/dcv.d.ts +3 -0
  65. package/cli/dcv.d.ts.map +1 -0
  66. package/cli/dcv.js +86 -0
  67. package/cli/dcv.ts +107 -0
  68. package/cli/engine-helpers.d.ts +8 -0
  69. package/cli/engine-helpers.d.ts.map +1 -0
  70. package/cli/engine-helpers.js +70 -0
  71. package/cli/engine-helpers.ts +61 -0
  72. package/cli/graph-poset.d.ts +9 -0
  73. package/cli/graph-poset.d.ts.map +1 -0
  74. package/cli/graph-poset.js +58 -0
  75. package/cli/graph-poset.ts +74 -0
  76. package/cli/index.d.ts +3 -0
  77. package/cli/index.d.ts.map +1 -0
  78. package/cli/index.js +2 -0
  79. package/cli/index.ts +2 -0
  80. package/cli/result.d.ts +17 -0
  81. package/cli/result.d.ts.map +1 -0
  82. package/cli/result.js +29 -0
  83. package/cli/result.ts +27 -0
  84. package/cli/run.d.ts +3 -0
  85. package/cli/run.d.ts.map +1 -0
  86. package/cli/run.js +47 -0
  87. package/cli/run.ts +54 -0
  88. package/cli/smoke-test.d.ts +2 -0
  89. package/cli/smoke-test.d.ts.map +1 -0
  90. package/cli/smoke-test.js +33 -0
  91. package/cli/smoke-test.ts +40 -0
  92. package/cli/types.d.ts +86 -0
  93. package/cli/types.d.ts.map +1 -0
  94. package/cli/types.js +1 -0
  95. package/cli/types.ts +78 -0
  96. package/core/breakpoints.d.ts +12 -0
  97. package/core/breakpoints.d.ts.map +1 -0
  98. package/core/breakpoints.js +48 -0
  99. package/core/breakpoints.ts +50 -0
  100. package/core/cli-format.d.ts +8 -0
  101. package/core/cli-format.d.ts.map +1 -0
  102. package/core/cli-format.js +29 -0
  103. package/core/cli-format.ts +31 -0
  104. package/core/color.d.ts +14 -0
  105. package/core/color.d.ts.map +1 -0
  106. package/core/color.js +136 -0
  107. package/core/color.ts +148 -0
  108. package/core/constraints/cross-axis.d.ts +33 -0
  109. package/core/constraints/cross-axis.d.ts.map +1 -0
  110. package/core/constraints/cross-axis.js +93 -0
  111. package/core/constraints/cross-axis.ts +114 -0
  112. package/core/constraints/monotonic-lightness.d.ts +5 -0
  113. package/core/constraints/monotonic-lightness.d.ts.map +1 -0
  114. package/core/constraints/monotonic-lightness.js +37 -0
  115. package/core/constraints/monotonic-lightness.ts +38 -0
  116. package/core/constraints/monotonic.d.ts +7 -0
  117. package/core/constraints/monotonic.d.ts.map +1 -0
  118. package/core/constraints/monotonic.js +65 -0
  119. package/core/constraints/monotonic.ts +74 -0
  120. package/core/constraints/threshold.d.ts +10 -0
  121. package/core/constraints/threshold.d.ts.map +1 -0
  122. package/core/constraints/threshold.js +36 -0
  123. package/core/constraints/threshold.ts +43 -0
  124. package/core/constraints/wcag.d.ts +11 -0
  125. package/core/constraints/wcag.d.ts.map +1 -0
  126. package/core/constraints/wcag.js +53 -0
  127. package/core/constraints/wcag.ts +70 -0
  128. package/core/cross-axis-config.d.ts +5 -0
  129. package/core/cross-axis-config.d.ts.map +1 -0
  130. package/core/cross-axis-config.js +144 -0
  131. package/core/cross-axis-config.ts +152 -0
  132. package/core/engine.d.ts +32 -0
  133. package/core/engine.d.ts.map +1 -0
  134. package/core/engine.js +46 -0
  135. package/core/engine.ts +65 -0
  136. package/core/flatten.d.ts +20 -0
  137. package/core/flatten.d.ts.map +1 -0
  138. package/core/flatten.js +80 -0
  139. package/core/flatten.ts +116 -0
  140. package/core/image-export.d.ts +10 -0
  141. package/core/image-export.d.ts.map +1 -0
  142. package/core/image-export.js +43 -0
  143. package/core/image-export.ts +48 -0
  144. package/core/index.d.ts +31 -0
  145. package/core/index.d.ts.map +1 -0
  146. package/core/index.js +54 -0
  147. package/core/index.ts +72 -0
  148. package/core/patch.d.ts +28 -0
  149. package/core/patch.d.ts.map +1 -0
  150. package/core/patch.js +110 -0
  151. package/core/patch.ts +134 -0
  152. package/core/poset.d.ts +41 -0
  153. package/core/poset.d.ts.map +1 -0
  154. package/core/poset.js +275 -0
  155. package/core/poset.ts +311 -0
  156. package/core/why.d.ts +17 -0
  157. package/core/why.d.ts.map +1 -0
  158. package/core/why.js +45 -0
  159. package/core/why.ts +63 -0
  160. package/dist/test-overrides-removal.json +4 -0
  161. package/dist/tmp.patch.json +35 -0
  162. package/package.json +90 -0
  163. package/themes/color.lg.order.json +15 -0
  164. package/themes/color.md.order.json +15 -0
  165. package/themes/color.order.json +15 -0
  166. package/themes/color.sm.order.json +15 -0
  167. package/themes/cross-axis.rules.json +36 -0
  168. package/themes/cross-axis.sm.rules.json +12 -0
  169. package/themes/layout.lg.order.json +18 -0
  170. package/themes/layout.md.order.json +18 -0
  171. package/themes/layout.order.json +18 -0
  172. package/themes/layout.sm.order.json +18 -0
  173. package/themes/spacing.order.json +14 -0
  174. package/themes/typography.lg.order.json +15 -0
  175. package/themes/typography.md.order.json +15 -0
  176. package/themes/typography.order.json +15 -0
  177. package/themes/typography.sm.order.json +15 -0
  178. package/tokens/overrides/base.json +22 -0
  179. package/tokens/overrides/lg.json +20 -0
  180. package/tokens/overrides/md.json +16 -0
  181. package/tokens/overrides/sm.json +16 -0
  182. package/tokens/overrides/viol.color.json +6 -0
  183. package/tokens/overrides/viol.typography.json +6 -0
  184. package/tokens/tokens.demo-violations.json +116 -0
  185. package/tokens/tokens.example.json +128 -0
  186. package/tokens/tokens.json +67 -0
  187. package/tokens/tokens.multi-violations.json +21 -0
  188. package/tokens/tokens.schema.d.ts +2298 -0
  189. package/tokens/tokens.schema.d.ts.map +1 -0
  190. package/tokens/tokens.schema.js +148 -0
  191. package/tokens/tokens.schema.ts +196 -0
  192. package/tokens/tokens.test.json +38 -0
  193. package/tokens/tokens.touch-violation.json +8 -0
  194. package/tokens/typography.classes.css +11 -0
  195. package/tokens/typography.css +20 -0
package/cli/result.js ADDED
@@ -0,0 +1,29 @@
1
+ export function ok(value) { return { ok: true, value }; }
2
+ export function err(error) { return { ok: false, error }; }
3
+ export function wrap(fn) {
4
+ try {
5
+ return ok(fn());
6
+ }
7
+ catch (e) {
8
+ return err(e);
9
+ }
10
+ }
11
+ export async function wrapAsync(fn) {
12
+ try {
13
+ return ok(await fn());
14
+ }
15
+ catch (e) {
16
+ return err(e);
17
+ }
18
+ }
19
+ export function map(r, f) {
20
+ return r.ok ? ok(f(r.value)) : r;
21
+ }
22
+ export function chain(r, f) {
23
+ return r.ok ? f(r.value) : r;
24
+ }
25
+ export function getOrThrow(r) {
26
+ if (!r.ok)
27
+ throw r.error; // consumer decides how to handle
28
+ return r.value;
29
+ }
package/cli/result.ts ADDED
@@ -0,0 +1,27 @@
1
+ export type Ok<T> = { ok: true; value: T };
2
+ export type Err<E> = { ok: false; error: E };
3
+ export type Result<T, E = Error> = Ok<T> | Err<E>;
4
+
5
+ export function ok<T>(value: T): Ok<T> { return { ok: true, value }; }
6
+ export function err<E>(error: E): Err<E> { return { ok: false, error }; }
7
+
8
+ export function wrap<T>(fn: () => T): Result<T, unknown> {
9
+ try { return ok(fn()); } catch (e) { return err(e); }
10
+ }
11
+
12
+ export async function wrapAsync<T>(fn: () => Promise<T>): Promise<Result<T, unknown>> {
13
+ try { return ok(await fn()); } catch (e) { return err(e); }
14
+ }
15
+
16
+ export function map<T, U, E>(r: Result<T, E>, f: (v: T) => U): Result<U, E> {
17
+ return r.ok ? ok(f(r.value)) : r;
18
+ }
19
+
20
+ export function chain<T, U, E>(r: Result<T, E>, f: (v: T) => Result<U, E>): Result<U, E> {
21
+ return r.ok ? f(r.value) : r;
22
+ }
23
+
24
+ export function getOrThrow<T, E>(r: Result<T, E>): T {
25
+ if (!r.ok) throw r.error as any; // consumer decides how to handle
26
+ return r.value;
27
+ }
package/cli/run.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ts-node
2
+ export {};
3
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["run.ts"],"names":[],"mappings":""}
package/cli/run.js ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ts-node
2
+ import { readFileSync } from "node:fs";
3
+ import { flattenTokens } from "../core/flatten.js";
4
+ import { Engine } from "../core/engine.js";
5
+ import { WcagContrastPlugin } from "../core/constraints/wcag.js";
6
+ const tokensRoot = JSON.parse(readFileSync("tokens/tokens.example.json", "utf8"));
7
+ const { flat, edges } = flattenTokens(tokensRoot);
8
+ // Build init values map
9
+ const init = {};
10
+ for (const [id, t] of Object.entries(flat))
11
+ init[id] = t.value;
12
+ // Engine + plugin (example pairs; adjust IDs to your roles)
13
+ const engine = new Engine(init, edges).use(WcagContrastPlugin([
14
+ { fg: "color.role.text.default", bg: "color.role.surface.default", min: 4.5, where: "Body text" },
15
+ { fg: "color.role.accent.default", bg: "color.role.surface.default", min: 3.0, where: "Accent on surface" }
16
+ ]));
17
+ // Apply overrides if present
18
+ let overrides = {};
19
+ try {
20
+ const maybe = JSON.parse(readFileSync("tokens/overrides/local.json", "utf8"));
21
+ overrides = maybe.overrides ?? maybe;
22
+ }
23
+ catch {
24
+ // File doesn't exist or invalid JSON, use empty overrides
25
+ }
26
+ import { patchToJson } from "../adapters/json.js";
27
+ import yargs from "yargs/yargs";
28
+ import { hideBin } from "yargs/helpers";
29
+ const argvPromise = yargs(hideBin(process.argv)).option('json', {
30
+ alias: 'j',
31
+ type: 'boolean',
32
+ description: 'Output result as JSON'
33
+ }).argv;
34
+ // ... existing code ...
35
+ (async () => {
36
+ const argv = await argvPromise;
37
+ for (const [id, val] of Object.entries(overrides)) {
38
+ const res = engine.commit(id, val);
39
+ if (argv.json) {
40
+ const jsonOutput = patchToJson(res);
41
+ console.log(JSON.stringify(jsonOutput, null, 2));
42
+ }
43
+ else {
44
+ console.log(JSON.stringify(res, null, 2));
45
+ }
46
+ }
47
+ })();
package/cli/run.ts ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ts-node
2
+ import { readFileSync } from "node:fs";
3
+ import { flattenTokens } from "../core/flatten.js";
4
+ import { Engine } from "../core/engine.js";
5
+ import { WcagContrastPlugin } from "../core/constraints/wcag.js";
6
+
7
+ const tokensRoot = JSON.parse(readFileSync("tokens/tokens.example.json","utf8"));
8
+ const { flat, edges } = flattenTokens(tokensRoot);
9
+
10
+ // Build init values map
11
+ const init: Record<string, string|number> = {};
12
+ for (const [id, t] of Object.entries(flat)) init[id] = t.value;
13
+
14
+ // Engine + plugin (example pairs; adjust IDs to your roles)
15
+ const engine = new Engine(init, edges).use(
16
+ WcagContrastPlugin([
17
+ { fg: "color.role.text.default", bg: "color.role.surface.default", min: 4.5, where: "Body text" },
18
+ { fg: "color.role.accent.default", bg: "color.role.surface.default", min: 3.0, where: "Accent on surface" }
19
+ ])
20
+ );
21
+
22
+ // Apply overrides if present
23
+ let overrides: Record<string, string|number> = {};
24
+ try {
25
+ const maybe = JSON.parse(readFileSync("tokens/overrides/local.json","utf8"));
26
+ overrides = maybe.overrides ?? maybe;
27
+ } catch {
28
+ // File doesn't exist or invalid JSON, use empty overrides
29
+ }
30
+
31
+ import { patchToJson } from "../adapters/json.js";
32
+ import yargs from "yargs/yargs";
33
+ import { hideBin } from "yargs/helpers";
34
+
35
+ const argvPromise = yargs(hideBin(process.argv)).option('json', {
36
+ alias: 'j',
37
+ type: 'boolean',
38
+ description: 'Output result as JSON'
39
+ }).argv;
40
+
41
+ // ... existing code ...
42
+
43
+ (async () => {
44
+ const argv = await argvPromise;
45
+ for (const [id, val] of Object.entries(overrides)) {
46
+ const res = engine.commit(id, val);
47
+ if (argv.json) {
48
+ const jsonOutput = patchToJson(res);
49
+ console.log(JSON.stringify(jsonOutput, null, 2));
50
+ } else {
51
+ console.log(JSON.stringify(res, null, 2));
52
+ }
53
+ }
54
+ })();
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=smoke-test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke-test.d.ts","sourceRoot":"","sources":["smoke-test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,33 @@
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
+ // 1. Flatten tokens
9
+ const tokensRoot = JSON.parse(readFileSync("tokens/tokens.example.json", "utf8"));
10
+ const { flat, edges } = flattenTokens(tokensRoot);
11
+ // 2. Build engine
12
+ const init = {};
13
+ for (const [id, t] of Object.entries(flat))
14
+ init[id] = t.value;
15
+ const engine = new Engine(init, edges).use(WcagContrastPlugin([
16
+ { fg: "color.role.text.default", bg: "color.role.bg.surface", min: 4.5, where: "Body text" },
17
+ ]));
18
+ // 3. Commit one change
19
+ const overrideId = "color.palette.brand.600";
20
+ const overrideValue = "#FF00FF"; // A loud magenta to make it obvious
21
+ const result = engine.commit(overrideId, overrideValue);
22
+ console.log("--- Smoke Test ---");
23
+ console.log(`Committed: ${overrideId} = ${overrideValue}`);
24
+ console.log("Affected:", result.affected);
25
+ console.log("Issues:", result.issues);
26
+ console.log("Patch:", result.patch);
27
+ // 4. Write overrides.css using the adapter
28
+ const css = patchToCss(result.patch);
29
+ const outFile = "css/overrides.css";
30
+ mkdirSync(dirname(outFile), { recursive: true });
31
+ writeFileSync(outFile, css);
32
+ console.log(`\nWrote ${outFile}`);
33
+ console.log("--- End Smoke Test ---");
@@ -0,0 +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 ---");
package/cli/types.d.ts ADDED
@@ -0,0 +1,86 @@
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
+ export interface WcagRuleConfig {
5
+ foreground: string;
6
+ background: string;
7
+ ratio?: number;
8
+ description?: string;
9
+ }
10
+ export type DcvConfig = DcvConfigParsed;
11
+ export type ValuesPatch = Record<string, TokenValue>;
12
+ export interface OverridesLeaf {
13
+ $value?: string | number | null;
14
+ }
15
+ export type OverridesTree = {
16
+ [k: string]: OverridesTree | OverridesLeaf;
17
+ } & OverridesLeaf;
18
+ export interface GlobalOptions {
19
+ tokens?: string;
20
+ config?: string;
21
+ verbose?: boolean;
22
+ quiet?: boolean;
23
+ breakpoint?: 'sm' | 'md' | 'lg';
24
+ allBreakpoints?: boolean;
25
+ }
26
+ export interface SetOptions extends GlobalOptions {
27
+ expressions: string[];
28
+ output?: string;
29
+ format?: 'json' | 'css' | 'js';
30
+ theme?: string;
31
+ write?: boolean;
32
+ json?: string;
33
+ unset?: string[];
34
+ }
35
+ export interface BuildOptions extends GlobalOptions {
36
+ output?: string;
37
+ format?: 'css' | 'json' | 'js';
38
+ watch?: boolean;
39
+ theme?: string;
40
+ mapper?: string;
41
+ dryRun?: boolean;
42
+ allFormats?: boolean;
43
+ }
44
+ export interface ValidateOptions extends GlobalOptions {
45
+ strict?: boolean;
46
+ constraints?: string[];
47
+ perf?: boolean;
48
+ budgetTotalMs?: number;
49
+ budgetPerBpMs?: number;
50
+ }
51
+ export interface GraphOptions extends GlobalOptions {
52
+ output?: string;
53
+ format?: 'dot' | 'mermaid' | 'json' | 'svg' | 'png';
54
+ imageFrom?: 'mermaid' | 'dot';
55
+ filter?: string;
56
+ hasse?: string;
57
+ filterPrefix?: string;
58
+ excludePrefix?: string;
59
+ onlyViolations?: boolean;
60
+ highlightViolations?: boolean;
61
+ violationColor?: string;
62
+ labelViolations?: boolean;
63
+ labelTruncate?: number;
64
+ minSeverity?: 'warn' | 'error';
65
+ focus?: string;
66
+ radius?: number;
67
+ tokens?: string;
68
+ }
69
+ export interface WhyOptions extends GlobalOptions {
70
+ tokenId: string;
71
+ format?: 'json' | 'table';
72
+ }
73
+ export interface PatchOptions extends GlobalOptions {
74
+ overrides?: string;
75
+ output?: string;
76
+ format?: 'json' | 'css' | 'js';
77
+ tokens?: string;
78
+ }
79
+ export interface PatchApplyOptions extends GlobalOptions {
80
+ patch: string;
81
+ output?: string;
82
+ tokens?: string;
83
+ dryRun?: boolean;
84
+ }
85
+ export type { Breakpoint };
86
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"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"}
package/cli/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/cli/types.ts ADDED
@@ -0,0 +1,78 @@
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
+ verbose?: boolean;
15
+ quiet?: boolean;
16
+ breakpoint?: 'sm' | 'md' | 'lg';
17
+ allBreakpoints?: boolean;
18
+ }
19
+ export interface SetOptions extends GlobalOptions {
20
+ expressions: string[];
21
+ output?: string;
22
+ format?: 'json' | 'css' | 'js';
23
+ theme?: string;
24
+ write?: boolean;
25
+ json?: string;
26
+ unset?: string[];
27
+ }
28
+ export interface BuildOptions extends GlobalOptions {
29
+ output?: string;
30
+ format?: 'css' | 'json' | 'js';
31
+ watch?: boolean;
32
+ theme?: string;
33
+ mapper?: string;
34
+ dryRun?: boolean;
35
+ allFormats?: boolean;
36
+ }
37
+ export interface ValidateOptions extends GlobalOptions {
38
+ strict?: boolean;
39
+ constraints?: string[];
40
+ perf?: boolean;
41
+ budgetTotalMs?: number;
42
+ budgetPerBpMs?: number;
43
+ }
44
+ export interface GraphOptions extends GlobalOptions {
45
+ output?: string;
46
+ format?: 'dot' | 'mermaid' | 'json' | 'svg' | 'png';
47
+ imageFrom?: 'mermaid' | 'dot';
48
+ filter?: string;
49
+ hasse?: string;
50
+ filterPrefix?: string;
51
+ excludePrefix?: string;
52
+ onlyViolations?: boolean;
53
+ highlightViolations?: boolean;
54
+ violationColor?: string;
55
+ labelViolations?: boolean;
56
+ labelTruncate?: number;
57
+ minSeverity?: 'warn' | 'error';
58
+ focus?: string;
59
+ radius?: number;
60
+ tokens?: string;
61
+ }
62
+ export interface WhyOptions extends GlobalOptions {
63
+ tokenId: string;
64
+ format?: 'json' | 'table';
65
+ }
66
+ export interface PatchOptions extends GlobalOptions {
67
+ overrides?: string; // path to flat overrides json or inline json
68
+ output?: string;
69
+ format?: 'json' | 'css' | 'js';
70
+ tokens?: string;
71
+ }
72
+ export interface PatchApplyOptions extends GlobalOptions {
73
+ patch: string; // path or inline patch JSON
74
+ output?: string; // where to write updated tokens (if omitted, prints result)
75
+ tokens?: string; // source tokens file (baseline)
76
+ dryRun?: boolean; // if true do not write
77
+ }
78
+ export type { Breakpoint };
@@ -0,0 +1,12 @@
1
+ import type { TokenNode } from "./flatten.js";
2
+ export type Breakpoint = "sm" | "md" | "lg";
3
+ export declare function parseBreakpoints(argv: string[]): Breakpoint[];
4
+ export declare function loadJsonSafe<T = unknown>(path: string): T | null;
5
+ export declare function loadOrders(axis: string, bp?: Breakpoint): [string, "<=" | ">=", string][];
6
+ export declare function mergeTokens(base: unknown, overlay: unknown): TokenNode;
7
+ /** Load tokens with optional breakpoint override: base + overrides/<bp>.json */
8
+ /**
9
+ * Load tokens with override precedence: base < local < breakpoint
10
+ */
11
+ export declare function loadTokensWithBreakpoint(bp?: Breakpoint): TokenNode;
12
+ //# sourceMappingURL=breakpoints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breakpoints.d.ts","sourceRoot":"","sources":["breakpoints.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,CAM7D;AAED,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAOhE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,UAAU,GAAG,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,CAKzF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,CAQtE;AAED,gFAAgF;AAChF;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,CAAC,EAAE,UAAU,GAAG,SAAS,CAKnE"}
@@ -0,0 +1,48 @@
1
+ // core/breakpoints.ts
2
+ import fs from "node:fs";
3
+ export function parseBreakpoints(argv) {
4
+ const allIdx = argv.indexOf("--all-breakpoints");
5
+ if (allIdx >= 0)
6
+ return ["sm", "md", "lg"];
7
+ const bpIdx = argv.indexOf("--breakpoint");
8
+ if (bpIdx >= 0)
9
+ return [argv[bpIdx + 1]];
10
+ return []; // no BP slicing requested
11
+ }
12
+ export function loadJsonSafe(path) {
13
+ try {
14
+ const data = JSON.parse(fs.readFileSync(path, "utf8"));
15
+ return data;
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ export function loadOrders(axis, bp) {
22
+ const withBp = bp ? loadJsonSafe(`themes/${axis}.${bp}.order.json`) : null;
23
+ if (withBp?.order)
24
+ return withBp.order;
25
+ const global = loadJsonSafe(`themes/${axis}.order.json`);
26
+ return (global?.order ?? []);
27
+ }
28
+ export function mergeTokens(base, overlay) {
29
+ if (!overlay)
30
+ return base;
31
+ if (typeof base !== "object" || base === null)
32
+ return overlay;
33
+ const out = Array.isArray(base) ? [...base] : { ...base };
34
+ for (const k of Object.keys(overlay)) {
35
+ out[k] = mergeTokens(base?.[k], overlay[k]);
36
+ }
37
+ return out;
38
+ }
39
+ /** Load tokens with optional breakpoint override: base + overrides/<bp>.json */
40
+ /**
41
+ * Load tokens with override precedence: base < local < breakpoint
42
+ */
43
+ export function loadTokensWithBreakpoint(bp) {
44
+ const base = loadJsonSafe("tokens/tokens.example.json") ?? {};
45
+ const local = loadJsonSafe("tokens/overrides/local.json");
46
+ const ov = bp ? loadJsonSafe(`tokens/overrides/${bp}.json`) : null;
47
+ return mergeTokens(mergeTokens(base, local), ov);
48
+ }
@@ -0,0 +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
+ }
@@ -0,0 +1,8 @@
1
+ export declare function pad(s: string, w: number): string;
2
+ export declare function trunc(s: string, w: number): string;
3
+ export declare function levenshtein(a: string, b: string): number;
4
+ export declare function suggestIds(id: string, candidates: string[], k?: number): {
5
+ id: string;
6
+ d: number;
7
+ }[];
8
+ //# sourceMappingURL=cli-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-format.d.ts","sourceRoot":"","sources":["cli-format.ts"],"names":[],"mappings":"AACA,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,UAGvC;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,UAEzC;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAaxD;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,SAAI,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,CAK/F"}
@@ -0,0 +1,29 @@
1
+ // core/cli-format.ts
2
+ export function pad(s, w) {
3
+ if (s.length >= w)
4
+ return s;
5
+ return s + " ".repeat(w - s.length);
6
+ }
7
+ export function trunc(s, w) {
8
+ return s.length <= w ? s : s.slice(0, Math.max(0, w - 1)) + "…";
9
+ }
10
+ export function levenshtein(a, b) {
11
+ const dp = Array(b.length + 1).fill(0).map((_, j) => j);
12
+ for (let i = 1; i <= a.length; i++) {
13
+ let prev = i - 1, cur = i;
14
+ for (let j = 1; j <= b.length; j++) {
15
+ const tmp = cur;
16
+ cur = Math.min(dp[j] + 1, cur + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
17
+ dp[j] = tmp;
18
+ prev = tmp;
19
+ }
20
+ dp[b.length] = cur;
21
+ }
22
+ return dp[b.length];
23
+ }
24
+ export function suggestIds(id, candidates, k = 3) {
25
+ return candidates
26
+ .map(c => ({ id: c, d: levenshtein(id, c) }))
27
+ .sort((x, y) => x.d - y.d)
28
+ .slice(0, k);
29
+ }
@@ -0,0 +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
+ }
@@ -0,0 +1,14 @@
1
+ export type RGBA = {
2
+ r: number;
3
+ g: number;
4
+ b: number;
5
+ a: number;
6
+ };
7
+ export declare function srgbToLin(c: number): number;
8
+ export declare function linToSrgb(c: number): number;
9
+ export declare function relativeLuminance(rgb: RGBA): number;
10
+ export declare function contrastRatio(L1: number, L2: number): number;
11
+ export declare function parseCssColor(input: string | undefined | null): RGBA | null;
12
+ export declare function compositeOver(fg: RGBA, bg: RGBA): RGBA;
13
+ export declare function isOpaque(c: RGBA): boolean;
14
+ //# sourceMappingURL=color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["color.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,IAAI,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAMlE,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG3C;AACD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI3C;AAGD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,CAMnD;AACD,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAG5D;AAMD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CA4D3E;AAsCD,wBAAgB,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,GAAG,IAAI,CAStD;AAGD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,GAAG,OAAO,CAAyB"}