design-constraint-validator 1.0.0 → 2.0.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.
Files changed (121) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +229 -659
  3. package/adapters/README.md +46 -46
  4. package/adapters/css.ts +116 -116
  5. package/adapters/decisionthemes.d.ts +44 -0
  6. package/adapters/decisionthemes.d.ts.map +1 -0
  7. package/adapters/decisionthemes.js +35 -0
  8. package/adapters/decisionthemes.ts +59 -0
  9. package/adapters/js.ts +14 -14
  10. package/adapters/json.ts +45 -45
  11. package/cli/build-css.ts +32 -32
  12. package/cli/commands/build.ts +65 -65
  13. package/cli/commands/graph.d.ts.map +1 -1
  14. package/cli/commands/graph.js +26 -10
  15. package/cli/commands/graph.ts +180 -137
  16. package/cli/commands/index.ts +7 -7
  17. package/cli/commands/patch-apply.ts +80 -80
  18. package/cli/commands/patch.ts +22 -22
  19. package/cli/commands/set.d.ts.map +1 -1
  20. package/cli/commands/set.js +12 -4
  21. package/cli/commands/set.ts +239 -225
  22. package/cli/commands/utils.ts +50 -50
  23. package/cli/commands/validate.d.ts.map +1 -1
  24. package/cli/commands/validate.js +89 -33
  25. package/cli/commands/validate.ts +180 -115
  26. package/cli/commands/why.d.ts.map +1 -1
  27. package/cli/commands/why.js +86 -20
  28. package/cli/commands/why.ts +158 -46
  29. package/cli/config-schema.ts +27 -27
  30. package/cli/config.ts +35 -35
  31. package/cli/constraint-registry.d.ts +101 -0
  32. package/cli/constraint-registry.d.ts.map +1 -0
  33. package/cli/constraint-registry.js +225 -0
  34. package/cli/constraint-registry.ts +304 -0
  35. package/cli/constraints-loader.d.ts.map +1 -0
  36. package/cli/cross-axis-loader.d.ts +91 -0
  37. package/cli/cross-axis-loader.d.ts.map +1 -0
  38. package/cli/cross-axis-loader.js +222 -0
  39. package/cli/cross-axis-loader.ts +289 -0
  40. package/cli/dcv.js +4 -0
  41. package/cli/dcv.ts +111 -107
  42. package/cli/engine-helpers.d.ts.map +1 -1
  43. package/cli/graph-poset.ts +74 -74
  44. package/cli/json-output.d.ts +69 -0
  45. package/cli/json-output.d.ts.map +1 -0
  46. package/cli/json-output.js +109 -0
  47. package/cli/json-output.ts +184 -0
  48. package/cli/result.ts +27 -27
  49. package/cli/run.ts +54 -54
  50. package/cli/smoke-test.ts +40 -40
  51. package/cli/types.d.ts +6 -0
  52. package/cli/types.d.ts.map +1 -1
  53. package/cli/types.ts +84 -78
  54. package/cli/version-banner.d.ts +20 -0
  55. package/cli/version-banner.d.ts.map +1 -0
  56. package/cli/version-banner.js +49 -0
  57. package/cli/version-banner.ts +61 -0
  58. package/core/breakpoints.ts +50 -50
  59. package/core/cli-format.ts +31 -31
  60. package/core/color.ts +148 -148
  61. package/core/constraints/cross-axis.ts +114 -114
  62. package/core/constraints/monotonic-lightness.ts +38 -38
  63. package/core/constraints/monotonic.ts +74 -74
  64. package/core/constraints/threshold.ts +43 -43
  65. package/core/constraints/wcag.ts +70 -70
  66. package/core/cross-axis-config.d.ts.map +1 -1
  67. package/core/engine.d.ts +95 -0
  68. package/core/engine.d.ts.map +1 -1
  69. package/core/engine.js +22 -0
  70. package/core/engine.ts +167 -65
  71. package/core/flatten.ts +116 -116
  72. package/core/image-export.ts +48 -48
  73. package/core/index.d.ts +9 -30
  74. package/core/index.d.ts.map +1 -1
  75. package/core/index.js +7 -54
  76. package/core/index.ts +10 -72
  77. package/core/patch.ts +134 -134
  78. package/core/poset.ts +311 -311
  79. package/core/why.ts +63 -63
  80. package/package.json +96 -90
  81. package/themes/color.lg.order.json +15 -15
  82. package/themes/color.md.order.json +15 -15
  83. package/themes/color.order.json +15 -15
  84. package/themes/color.sm.order.json +15 -15
  85. package/themes/cross-axis.rules.json +35 -35
  86. package/themes/cross-axis.sm.rules.json +12 -12
  87. package/themes/layout.lg.order.json +18 -18
  88. package/themes/layout.md.order.json +18 -18
  89. package/themes/layout.order.json +18 -18
  90. package/themes/layout.sm.order.json +18 -18
  91. package/themes/spacing.order.json +14 -14
  92. package/themes/typography.lg.order.json +15 -15
  93. package/themes/typography.md.order.json +15 -15
  94. package/themes/typography.order.json +15 -15
  95. package/themes/typography.sm.order.json +15 -15
  96. package/cli/engine-helpers.d.ts +0 -8
  97. package/cli/engine-helpers.js +0 -70
  98. package/cli/engine-helpers.ts +0 -61
  99. package/core/cross-axis-config.d.ts +0 -5
  100. package/core/cross-axis-config.js +0 -144
  101. package/core/cross-axis-config.ts +0 -152
  102. package/dist/test-overrides-removal.json +0 -4
  103. package/dist/tmp.patch.json +0 -35
  104. package/tokens/overrides/base.json +0 -22
  105. package/tokens/overrides/lg.json +0 -20
  106. package/tokens/overrides/md.json +0 -16
  107. package/tokens/overrides/sm.json +0 -16
  108. package/tokens/overrides/viol.color.json +0 -6
  109. package/tokens/overrides/viol.typography.json +0 -6
  110. package/tokens/tokens.demo-violations.json +0 -116
  111. package/tokens/tokens.example.json +0 -128
  112. package/tokens/tokens.json +0 -67
  113. package/tokens/tokens.multi-violations.json +0 -21
  114. package/tokens/tokens.schema.d.ts +0 -2298
  115. package/tokens/tokens.schema.d.ts.map +0 -1
  116. package/tokens/tokens.schema.js +0 -148
  117. package/tokens/tokens.schema.ts +0 -196
  118. package/tokens/tokens.test.json +0 -38
  119. package/tokens/tokens.touch-violation.json +0 -8
  120. package/tokens/typography.classes.css +0 -11
  121. package/tokens/typography.css +0 -20
@@ -1,46 +1,46 @@
1
- # Adapters
2
-
3
- DCV supports multiple **input shapes** via lightweight adapters that normalize external token formats into DCV's internal model.
4
-
5
- ## Goals
6
- - Accept common design-token ecosystems with zero/low friction.
7
- - Preserve **IDs** and **provenance** so diagnostics remain meaningful.
8
- - Avoid mutation: adapters are **pure mappings**.
9
-
10
- ## Currently targeted
11
- - **Style Dictionary** (`*.json`)
12
- - Map `tokens.foo.bar.value` → DCV node id `tokens.foo.bar`
13
- - Preserve `type`, `description` if present
14
- - **Tokens Studio JSON** (Figma plugin export)
15
- - Map `$value`, `$type`, `$description` to DCV fields
16
- - **DTCG** schema
17
- - Normalize `value`, `type`, `extensions` to DCV keys
18
-
19
- ## Minimal internal shape (simplified)
20
-
21
- ```ts
22
- type DCVToken = {
23
- id: string; // stable dot-path id
24
- type?: string; // 'color' | 'dimension' | ...
25
- value: unknown; // normalized primitive (hex, number, etc.)
26
- meta?: Record<string, any>; // passthrough fields (description, file, source)
27
- };
28
- ```
29
-
30
- ## Writing a custom adapter
31
-
32
- ```ts
33
- export function fromMyFormat(json: any): DCVToken[] {
34
- // 1) walk your input
35
- // 2) produce DCVToken[] with stable ids & normalized values
36
- // 3) do not throw on unknown fields; pass through to meta
37
- return tokens;
38
- }
39
- ```
40
-
41
- **Tip:** Keep **IDs stable**; diagnostics and graphs depend on them.
42
-
43
- ## Policy inputs
44
-
45
- Policies are separate JSONs (e.g., AA, AAA, org presets).
46
- Adapters do **not** alter policy files; they only map tokens.
1
+ # Adapters
2
+
3
+ DCV supports multiple **input shapes** via lightweight adapters that normalize external token formats into DCV's internal model.
4
+
5
+ ## Goals
6
+ - Accept common design-token ecosystems with zero/low friction.
7
+ - Preserve **IDs** and **provenance** so diagnostics remain meaningful.
8
+ - Avoid mutation: adapters are **pure mappings**.
9
+
10
+ ## Currently targeted
11
+ - **Style Dictionary** (`*.json`)
12
+ - Map `tokens.foo.bar.value` → DCV node id `tokens.foo.bar`
13
+ - Preserve `type`, `description` if present
14
+ - **Tokens Studio JSON** (Figma plugin export)
15
+ - Map `$value`, `$type`, `$description` to DCV fields
16
+ - **DTCG** schema
17
+ - Normalize `value`, `type`, `extensions` to DCV keys
18
+
19
+ ## Minimal internal shape (simplified)
20
+
21
+ ```ts
22
+ type DCVToken = {
23
+ id: string; // stable dot-path id
24
+ type?: string; // 'color' | 'dimension' | ...
25
+ value: unknown; // normalized primitive (hex, number, etc.)
26
+ meta?: Record<string, any>; // passthrough fields (description, file, source)
27
+ };
28
+ ```
29
+
30
+ ## Writing a custom adapter
31
+
32
+ ```ts
33
+ export function fromMyFormat(json: any): DCVToken[] {
34
+ // 1) walk your input
35
+ // 2) produce DCVToken[] with stable ids & normalized values
36
+ // 3) do not throw on unknown fields; pass through to meta
37
+ return tokens;
38
+ }
39
+ ```
40
+
41
+ **Tip:** Keep **IDs stable**; diagnostics and graphs depend on them.
42
+
43
+ ## Policy inputs
44
+
45
+ Policies are separate JSONs (e.g., AA, AAA, org presets).
46
+ Adapters do **not** alter policy files; they only map tokens.
package/adapters/css.ts CHANGED
@@ -1,116 +1,116 @@
1
- // adapters/css.ts
2
- export type TokenId = string;
3
- export type TokenValue = string | number;
4
-
5
- // Turn a token ID into a CSS custom property name.
6
- // Default: "--dimension-spacing-scale-4" (neutral, reversible).
7
- export type VarMapper = (id: TokenId) => string | null;
8
-
9
- export const defaultVarMapper: VarMapper = (id) =>
10
- `--${id.replace(/[^a-z0-9.]/gi, "-").replace(/\.+/g, "-").toLowerCase()}`;
11
-
12
- // Manifest driven mapping allowing canonical + legacy aliases.
13
- export type ManifestRow = { id: string; canonicalVar?: string | null; legacyVars?: string[] };
14
-
15
- export interface VarMapping { canonical: string; aliases: string[] };
16
-
17
- /**
18
- * Build a mapping of token id -> {canonical, aliases} from an optional manifest.
19
- * If no manifest provided, falls back to defaultVarMapper with no aliases.
20
- */
21
- export function buildVarMapping(ids: Iterable<string>, manifest?: ManifestRow[]): Map<string, VarMapping> {
22
- const map = new Map<string, VarMapping>();
23
- const byId: Map<string, ManifestRow> = new Map();
24
- if (manifest) {
25
- for (const row of manifest) {
26
- if (!row || !row.id) continue;
27
- byId.set(row.id, row);
28
- }
29
- }
30
- for (const id of ids) {
31
- const row = byId.get(id);
32
- // Always fall back to generated name so canonical is never null.
33
- const canonical = ((row?.canonicalVar ? row.canonicalVar.trim() : "") || defaultVarMapper(id)) as string;
34
- const aliasSet = new Set<string>();
35
- (row?.legacyVars || []).forEach(a => {
36
- if (!a) return;
37
- const alias = a.trim();
38
- if (alias && alias !== canonical) aliasSet.add(alias);
39
- });
40
- map.set(id, { canonical, aliases: Array.from(aliasSet) });
41
- }
42
- return map;
43
- }
44
-
45
- export function makeManifestVarMapper(manifest: ManifestRow[]): VarMapper {
46
- const byId = new Map<string, string>();
47
- for (const m of manifest) if (m.canonicalVar) byId.set(m.id, m.canonicalVar);
48
- return (id) => byId.get(id) ?? defaultVarMapper(id);
49
- }
50
-
51
- // Build a CSS block from a map of token IDs to values.
52
- function buildCssBlock(
53
- values: Record<TokenId, TokenValue>,
54
- opts: { mapVar?: VarMapper; manifest?: ManifestRow[] }
55
- ): string {
56
- const decls: string[] = [];
57
- if (opts.manifest) {
58
- const mapping = buildVarMapping(Object.keys(values), opts.manifest);
59
- for (const [id, val] of Object.entries(values)) {
60
- const m = mapping.get(id);
61
- if (!m) continue;
62
- const v = String(val).trim();
63
- if (!v) continue;
64
- decls.push(`${m.canonical}: ${v};`);
65
- for (const alias of m.aliases) {
66
- decls.push(`${alias}: var(${m.canonical});`);
67
- }
68
- }
69
- } else {
70
- const mapVar = opts.mapVar ?? defaultVarMapper;
71
- for (const [id, val] of Object.entries(values)) {
72
- const cssVar = mapVar(id);
73
- if (!cssVar) continue; // skip if intentionally unmapped
74
- const v = String(val).trim();
75
- if (v) decls.push(`${cssVar}: ${v};`);
76
- }
77
- }
78
- return decls.join("\n ");
79
- }
80
-
81
- /**
82
- * Generate CSS for a *full* :root block (use for initial build from flat values).
83
- */
84
- export function valuesToCss(
85
- values: Record<TokenId, TokenValue>,
86
- opts?: { selector?: string; layer?: string; mapVar?: VarMapper; manifest?: ManifestRow[] }
87
- ): string {
88
- const selector = opts?.selector ?? ":root";
89
- const layer = opts?.layer ?? "tokens";
90
- const body = buildCssBlock(values, { mapVar: opts?.mapVar, manifest: opts?.manifest });
91
- return `@layer ${layer} {\n ${selector} {\n ${body}\n }\n}`;
92
- }
93
-
94
- /**
95
- * Generate CSS for a *patch* (small overlay you can inject at runtime).
96
- */
97
- export function patchToCss(
98
- patch: Record<TokenId, TokenValue>,
99
- opts?: { selector?: string; layer?: string; mapVar?: VarMapper; manifest?: ManifestRow[] }
100
- ): string {
101
- const selector = opts?.selector ?? ":root";
102
- const layer = opts?.layer ?? "tokens-overrides";
103
- const body = buildCssBlock(patch, { mapVar: opts?.mapVar, manifest: opts?.manifest });
104
- return `@layer ${layer} {\n ${selector} {\n ${body}\n }\n}`;
105
- }
106
-
107
- /**
108
- * (Browser only) Replace the contents of a <style> element with the given CSS.
109
- */
110
- export function applyCssToStyleEl(styleEl: { textContent: string | null }, cssText: string) {
111
- styleEl.textContent = cssText;
112
- }
113
-
114
- // NOTE: The design studio -> catalog preview iframe token sync uses a simplified
115
- // :root { --token: value } block (no @layer) built ad-hoc. For a layered build
116
- // prefer valuesToCss / patchToCss helpers above.
1
+ // adapters/css.ts
2
+ export type TokenId = string;
3
+ export type TokenValue = string | number;
4
+
5
+ // Turn a token ID into a CSS custom property name.
6
+ // Default: "--dimension-spacing-scale-4" (neutral, reversible).
7
+ export type VarMapper = (id: TokenId) => string | null;
8
+
9
+ export const defaultVarMapper: VarMapper = (id) =>
10
+ `--${id.replace(/[^a-z0-9.]/gi, "-").replace(/\.+/g, "-").toLowerCase()}`;
11
+
12
+ // Manifest driven mapping allowing canonical + legacy aliases.
13
+ export type ManifestRow = { id: string; canonicalVar?: string | null; legacyVars?: string[] };
14
+
15
+ export interface VarMapping { canonical: string; aliases: string[] };
16
+
17
+ /**
18
+ * Build a mapping of token id -> {canonical, aliases} from an optional manifest.
19
+ * If no manifest provided, falls back to defaultVarMapper with no aliases.
20
+ */
21
+ export function buildVarMapping(ids: Iterable<string>, manifest?: ManifestRow[]): Map<string, VarMapping> {
22
+ const map = new Map<string, VarMapping>();
23
+ const byId: Map<string, ManifestRow> = new Map();
24
+ if (manifest) {
25
+ for (const row of manifest) {
26
+ if (!row || !row.id) continue;
27
+ byId.set(row.id, row);
28
+ }
29
+ }
30
+ for (const id of ids) {
31
+ const row = byId.get(id);
32
+ // Always fall back to generated name so canonical is never null.
33
+ const canonical = ((row?.canonicalVar ? row.canonicalVar.trim() : "") || defaultVarMapper(id)) as string;
34
+ const aliasSet = new Set<string>();
35
+ (row?.legacyVars || []).forEach(a => {
36
+ if (!a) return;
37
+ const alias = a.trim();
38
+ if (alias && alias !== canonical) aliasSet.add(alias);
39
+ });
40
+ map.set(id, { canonical, aliases: Array.from(aliasSet) });
41
+ }
42
+ return map;
43
+ }
44
+
45
+ export function makeManifestVarMapper(manifest: ManifestRow[]): VarMapper {
46
+ const byId = new Map<string, string>();
47
+ for (const m of manifest) if (m.canonicalVar) byId.set(m.id, m.canonicalVar);
48
+ return (id) => byId.get(id) ?? defaultVarMapper(id);
49
+ }
50
+
51
+ // Build a CSS block from a map of token IDs to values.
52
+ function buildCssBlock(
53
+ values: Record<TokenId, TokenValue>,
54
+ opts: { mapVar?: VarMapper; manifest?: ManifestRow[] }
55
+ ): string {
56
+ const decls: string[] = [];
57
+ if (opts.manifest) {
58
+ const mapping = buildVarMapping(Object.keys(values), opts.manifest);
59
+ for (const [id, val] of Object.entries(values)) {
60
+ const m = mapping.get(id);
61
+ if (!m) continue;
62
+ const v = String(val).trim();
63
+ if (!v) continue;
64
+ decls.push(`${m.canonical}: ${v};`);
65
+ for (const alias of m.aliases) {
66
+ decls.push(`${alias}: var(${m.canonical});`);
67
+ }
68
+ }
69
+ } else {
70
+ const mapVar = opts.mapVar ?? defaultVarMapper;
71
+ for (const [id, val] of Object.entries(values)) {
72
+ const cssVar = mapVar(id);
73
+ if (!cssVar) continue; // skip if intentionally unmapped
74
+ const v = String(val).trim();
75
+ if (v) decls.push(`${cssVar}: ${v};`);
76
+ }
77
+ }
78
+ return decls.join("\n ");
79
+ }
80
+
81
+ /**
82
+ * Generate CSS for a *full* :root block (use for initial build from flat values).
83
+ */
84
+ export function valuesToCss(
85
+ values: Record<TokenId, TokenValue>,
86
+ opts?: { selector?: string; layer?: string; mapVar?: VarMapper; manifest?: ManifestRow[] }
87
+ ): string {
88
+ const selector = opts?.selector ?? ":root";
89
+ const layer = opts?.layer ?? "tokens";
90
+ const body = buildCssBlock(values, { mapVar: opts?.mapVar, manifest: opts?.manifest });
91
+ return `@layer ${layer} {\n ${selector} {\n ${body}\n }\n}`;
92
+ }
93
+
94
+ /**
95
+ * Generate CSS for a *patch* (small overlay you can inject at runtime).
96
+ */
97
+ export function patchToCss(
98
+ patch: Record<TokenId, TokenValue>,
99
+ opts?: { selector?: string; layer?: string; mapVar?: VarMapper; manifest?: ManifestRow[] }
100
+ ): string {
101
+ const selector = opts?.selector ?? ":root";
102
+ const layer = opts?.layer ?? "tokens-overrides";
103
+ const body = buildCssBlock(patch, { mapVar: opts?.mapVar, manifest: opts?.manifest });
104
+ return `@layer ${layer} {\n ${selector} {\n ${body}\n }\n}`;
105
+ }
106
+
107
+ /**
108
+ * (Browser only) Replace the contents of a <style> element with the given CSS.
109
+ */
110
+ export function applyCssToStyleEl(styleEl: { textContent: string | null }, cssText: string) {
111
+ styleEl.textContent = cssText;
112
+ }
113
+
114
+ // NOTE: The design studio -> catalog preview iframe token sync uses a simplified
115
+ // :root { --token: value } block (no @layer) built ad-hoc. For a layered build
116
+ // prefer valuesToCss / patchToCss helpers above.
@@ -0,0 +1,44 @@
1
+ /**
2
+ * DecisionThemes Adapter (Placeholder)
3
+ *
4
+ * This adapter will integrate with the DecisionThemes framework (coming 2026).
5
+ * It transforms VT (Value Themes) + DT (Decision Themes) into flat tokens for DCV validation.
6
+ *
7
+ * @see https://www.decisionthemes.com
8
+ * @see docs/Adapters.md for implementation details
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { decisionthemesAdapter } from './adapters/decisionthemes.js';
13
+ *
14
+ * const { tokens, policy } = decisionthemesAdapter({
15
+ * vt: { ... }, // Value Themes (raw values)
16
+ * dt: { ... } // Decision Themes (formulas)
17
+ * });
18
+ *
19
+ * // tokens = flat token object for DCV validation
20
+ * // policy = auto-generated constraints from 5-axis model
21
+ * ```
22
+ */
23
+ export interface VT {
24
+ [key: string]: any;
25
+ }
26
+ export interface DT {
27
+ [key: string]: any;
28
+ }
29
+ export interface DecisionThemesInput {
30
+ vt: VT;
31
+ dt: DT;
32
+ }
33
+ export interface DecisionThemesOutput {
34
+ tokens: Record<string, any>;
35
+ policy?: string;
36
+ }
37
+ /**
38
+ * Transform DecisionThemes (VT+DT) into DCV-compatible tokens
39
+ *
40
+ * @param input - VT (values) + DT (decisions)
41
+ * @returns Flat tokens + optional policy JSON
42
+ */
43
+ export declare function decisionthemesAdapter(_input: DecisionThemesInput): DecisionThemesOutput;
44
+ //# sourceMappingURL=decisionthemes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decisionthemes.d.ts","sourceRoot":"","sources":["decisionthemes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,EAAE;IAEjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,EAAE;IAEjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,EAAE,CAAC;IACP,EAAE,EAAE,EAAE,CAAC;CACR;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,mBAAmB,GAAG,oBAAoB,CASvF"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * DecisionThemes Adapter (Placeholder)
3
+ *
4
+ * This adapter will integrate with the DecisionThemes framework (coming 2026).
5
+ * It transforms VT (Value Themes) + DT (Decision Themes) into flat tokens for DCV validation.
6
+ *
7
+ * @see https://www.decisionthemes.com
8
+ * @see docs/Adapters.md for implementation details
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { decisionthemesAdapter } from './adapters/decisionthemes.js';
13
+ *
14
+ * const { tokens, policy } = decisionthemesAdapter({
15
+ * vt: { ... }, // Value Themes (raw values)
16
+ * dt: { ... } // Decision Themes (formulas)
17
+ * });
18
+ *
19
+ * // tokens = flat token object for DCV validation
20
+ * // policy = auto-generated constraints from 5-axis model
21
+ * ```
22
+ */
23
+ /**
24
+ * Transform DecisionThemes (VT+DT) into DCV-compatible tokens
25
+ *
26
+ * @param input - VT (values) + DT (decisions)
27
+ * @returns Flat tokens + optional policy JSON
28
+ */
29
+ export function decisionthemesAdapter(_input) {
30
+ // TODO: Implement when DecisionThemes integration is ready
31
+ // This will call the DecisionThemes resolver/compute engine to process _input
32
+ throw new Error('DecisionThemes adapter not yet implemented. ' +
33
+ 'This is a placeholder for future integration with the DecisionThemes framework. ' +
34
+ 'See https://www.decisionthemes.com for updates.');
35
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * DecisionThemes Adapter (Placeholder)
3
+ *
4
+ * This adapter will integrate with the DecisionThemes framework (coming 2026).
5
+ * It transforms VT (Value Themes) + DT (Decision Themes) into flat tokens for DCV validation.
6
+ *
7
+ * @see https://www.decisionthemes.com
8
+ * @see docs/Adapters.md for implementation details
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { decisionthemesAdapter } from './adapters/decisionthemes.js';
13
+ *
14
+ * const { tokens, policy } = decisionthemesAdapter({
15
+ * vt: { ... }, // Value Themes (raw values)
16
+ * dt: { ... } // Decision Themes (formulas)
17
+ * });
18
+ *
19
+ * // tokens = flat token object for DCV validation
20
+ * // policy = auto-generated constraints from 5-axis model
21
+ * ```
22
+ */
23
+
24
+ export interface VT {
25
+ // Value Themes - raw design values
26
+ [key: string]: any;
27
+ }
28
+
29
+ export interface DT {
30
+ // Decision Themes - formulas and decision mappings
31
+ [key: string]: any;
32
+ }
33
+
34
+ export interface DecisionThemesInput {
35
+ vt: VT;
36
+ dt: DT;
37
+ }
38
+
39
+ export interface DecisionThemesOutput {
40
+ tokens: Record<string, any>;
41
+ policy?: string;
42
+ }
43
+
44
+ /**
45
+ * Transform DecisionThemes (VT+DT) into DCV-compatible tokens
46
+ *
47
+ * @param input - VT (values) + DT (decisions)
48
+ * @returns Flat tokens + optional policy JSON
49
+ */
50
+ export function decisionthemesAdapter(_input: DecisionThemesInput): DecisionThemesOutput {
51
+ // TODO: Implement when DecisionThemes integration is ready
52
+ // This will call the DecisionThemes resolver/compute engine to process _input
53
+
54
+ throw new Error(
55
+ 'DecisionThemes adapter not yet implemented. ' +
56
+ 'This is a placeholder for future integration with the DecisionThemes framework. ' +
57
+ 'See https://www.decisionthemes.com for updates.'
58
+ );
59
+ }
package/adapters/js.ts CHANGED
@@ -1,14 +1,14 @@
1
- // adapters/js.ts
2
- import { buildVarMapping, defaultVarMapper, type ManifestRow } from './css.js';
3
-
4
- export function emitJS(values: Record<string, any>, manifest?: ManifestRow[]): string {
5
- const ids = Object.keys(values).sort();
6
- let mapping: Map<string, { canonical: string; aliases: string[] }> | undefined;
7
- if (manifest) mapping = buildVarMapping(ids, manifest);
8
- const lines: string[] = [];
9
- for (const id of ids) {
10
- const canonical = mapping ? mapping.get(id)!.canonical : defaultVarMapper(id);
11
- if (canonical) lines.push(` "${canonical}": ${JSON.stringify(values[id])}`);
12
- }
13
- return `// Generated by DCV. Do not edit.\nexport default {\n${lines.join(',\n')}\n};\n`;
14
- }
1
+ // adapters/js.ts
2
+ import { buildVarMapping, defaultVarMapper, type ManifestRow } from './css.js';
3
+
4
+ export function emitJS(values: Record<string, any>, manifest?: ManifestRow[]): string {
5
+ const ids = Object.keys(values).sort();
6
+ let mapping: Map<string, { canonical: string; aliases: string[] }> | undefined;
7
+ if (manifest) mapping = buildVarMapping(ids, manifest);
8
+ const lines: string[] = [];
9
+ for (const id of ids) {
10
+ const canonical = mapping ? mapping.get(id)!.canonical : defaultVarMapper(id);
11
+ if (canonical) lines.push(` "${canonical}": ${JSON.stringify(values[id])}`);
12
+ }
13
+ return `// Generated by DCV. Do not edit.\nexport default {\n${lines.join(',\n')}\n};\n`;
14
+ }
package/adapters/json.ts CHANGED
@@ -1,45 +1,45 @@
1
- // adapters/json.ts
2
- import { buildVarMapping, defaultVarMapper, type ManifestRow } from './css.js';
3
-
4
- export function emitJSON(values: Record<string, any>, manifest?: ManifestRow[]): string {
5
- const ids = Object.keys(values).sort();
6
- let mapping: Map<string, { canonical: string; aliases: string[] }> | undefined;
7
- if (manifest) mapping = buildVarMapping(ids, manifest);
8
- const out: Record<string, any> = {};
9
- for (const id of ids) {
10
- const canonical = mapping ? mapping.get(id)!.canonical : defaultVarMapper(id);
11
- if (canonical) out[canonical] = values[id];
12
- }
13
- return JSON.stringify(out, null, 2) + '\n';
14
- }
15
- // adapters/json.ts
16
- import type { TokenId, TokenValue, FlatToken } from '../core/flatten.js';
17
-
18
- /**
19
- * Generates a JSON representation of the entire token set and dependency graph.
20
- */
21
- export function valuesToJson(data: {
22
- flat: Record<TokenId, FlatToken>;
23
- edges: [TokenId, TokenId][];
24
- }): string {
25
- const values = Object.fromEntries(Object.entries(data.flat).map(([id, token]) => [id, token.value]));
26
- const edges = data.edges.map(([from, to]) => ({ from, to }));
27
-
28
- return JSON.stringify({
29
- tokens: values,
30
- edges: edges,
31
- }, null, 2);
32
- }
33
-
34
- /**
35
- * Generates a JSON representation of a patch from an engine commit.
36
- */
37
- export function patchToJson(patch: {
38
- patch: Record<TokenId, TokenValue>;
39
- affected: TokenId[];
40
- }): string {
41
- return JSON.stringify({
42
- changed: patch.patch,
43
- affected: patch.affected,
44
- }, null, 2);
45
- }
1
+ // adapters/json.ts
2
+ import { buildVarMapping, defaultVarMapper, type ManifestRow } from './css.js';
3
+
4
+ export function emitJSON(values: Record<string, any>, manifest?: ManifestRow[]): string {
5
+ const ids = Object.keys(values).sort();
6
+ let mapping: Map<string, { canonical: string; aliases: string[] }> | undefined;
7
+ if (manifest) mapping = buildVarMapping(ids, manifest);
8
+ const out: Record<string, any> = {};
9
+ for (const id of ids) {
10
+ const canonical = mapping ? mapping.get(id)!.canonical : defaultVarMapper(id);
11
+ if (canonical) out[canonical] = values[id];
12
+ }
13
+ return JSON.stringify(out, null, 2) + '\n';
14
+ }
15
+ // adapters/json.ts
16
+ import type { TokenId, TokenValue, FlatToken } from '../core/flatten.js';
17
+
18
+ /**
19
+ * Generates a JSON representation of the entire token set and dependency graph.
20
+ */
21
+ export function valuesToJson(data: {
22
+ flat: Record<TokenId, FlatToken>;
23
+ edges: [TokenId, TokenId][];
24
+ }): string {
25
+ const values = Object.fromEntries(Object.entries(data.flat).map(([id, token]) => [id, token.value]));
26
+ const edges = data.edges.map(([from, to]) => ({ from, to }));
27
+
28
+ return JSON.stringify({
29
+ tokens: values,
30
+ edges: edges,
31
+ }, null, 2);
32
+ }
33
+
34
+ /**
35
+ * Generates a JSON representation of a patch from an engine commit.
36
+ */
37
+ export function patchToJson(patch: {
38
+ patch: Record<TokenId, TokenValue>;
39
+ affected: TokenId[];
40
+ }): string {
41
+ return JSON.stringify({
42
+ changed: patch.patch,
43
+ affected: patch.affected,
44
+ }, null, 2);
45
+ }
package/cli/build-css.ts CHANGED
@@ -1,32 +1,32 @@
1
- // cli/build-css.ts
2
- import { writeFileSync, readFileSync, mkdirSync } from "node:fs";
3
- import { dirname } from "node:path";
4
- import { flattenTokens } from "../core/flatten.js";
5
- import { valuesToCss } from "../adapters/css.js";
6
-
7
- const tokens = JSON.parse(readFileSync("tokens/tokens.example.json", "utf8"));
8
- const { flat } = flattenTokens(tokens);
9
-
10
- const allValues: Record<string, string|number> =
11
- Object.fromEntries(Object.values(flat).map(t => [t.id, t.value]));
12
-
13
- import yargs from "yargs";
14
- import { hideBin } from "yargs/helpers";
15
-
16
- const argv = yargs(hideBin(process.argv)).option('out', {
17
- alias: 'o',
18
- type: 'string',
19
- description: 'Output file path',
20
- default: 'dist/tokens.css'
21
- }).parseSync();
22
-
23
- // ... existing code ...
24
-
25
- const outFile = argv.out;
26
- const css = valuesToCss(allValues, { layer: "tokens", selector: ":root" });
27
- // ... existing code ...
28
-
29
-
30
- mkdirSync(dirname(outFile), { recursive: true });
31
- writeFileSync(outFile, css);
32
- console.log(`Wrote ${outFile}`);
1
+ // cli/build-css.ts
2
+ import { writeFileSync, readFileSync, mkdirSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import { flattenTokens } from "../core/flatten.js";
5
+ import { valuesToCss } from "../adapters/css.js";
6
+
7
+ const tokens = JSON.parse(readFileSync("tokens/tokens.example.json", "utf8"));
8
+ const { flat } = flattenTokens(tokens);
9
+
10
+ const allValues: Record<string, string|number> =
11
+ Object.fromEntries(Object.values(flat).map(t => [t.id, t.value]));
12
+
13
+ import yargs from "yargs";
14
+ import { hideBin } from "yargs/helpers";
15
+
16
+ const argv = yargs(hideBin(process.argv)).option('out', {
17
+ alias: 'o',
18
+ type: 'string',
19
+ description: 'Output file path',
20
+ default: 'dist/tokens.css'
21
+ }).parseSync();
22
+
23
+ // ... existing code ...
24
+
25
+ const outFile = argv.out;
26
+ const css = valuesToCss(allValues, { layer: "tokens", selector: ":root" });
27
+ // ... existing code ...
28
+
29
+
30
+ mkdirSync(dirname(outFile), { recursive: true });
31
+ writeFileSync(outFile, css);
32
+ console.log(`Wrote ${outFile}`);