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.
- package/LICENSE +21 -21
- package/README.md +229 -659
- package/adapters/README.md +46 -46
- package/adapters/css.ts +116 -116
- package/adapters/decisionthemes.d.ts +44 -0
- package/adapters/decisionthemes.d.ts.map +1 -0
- package/adapters/decisionthemes.js +35 -0
- package/adapters/decisionthemes.ts +59 -0
- 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 +89 -33
- package/cli/commands/validate.ts +180 -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.map +1 -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.map +1 -1
- package/cli/graph-poset.ts +74 -74
- package/cli/json-output.d.ts +69 -0
- package/cli/json-output.d.ts.map +1 -0
- package/cli/json-output.js +109 -0
- package/cli/json-output.ts +184 -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/cli/version-banner.d.ts +20 -0
- package/cli/version-banner.d.ts.map +1 -0
- package/cli/version-banner.js +49 -0
- package/cli/version-banner.ts +61 -0
- 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.map +1 -1
- 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/cli/engine-helpers.d.ts +0 -8
- package/cli/engine-helpers.js +0 -70
- package/cli/engine-helpers.ts +0 -61
- package/core/cross-axis-config.d.ts +0 -5
- package/core/cross-axis-config.js +0 -144
- package/core/cross-axis-config.ts +0 -152
- 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/adapters/README.md
CHANGED
|
@@ -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}`);
|