design-constraint-validator 1.1.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +90 -21
  2. package/adapters/decisionthemes.d.ts +44 -0
  3. package/adapters/decisionthemes.d.ts.map +1 -0
  4. package/adapters/decisionthemes.js +35 -0
  5. package/adapters/decisionthemes.ts +59 -0
  6. package/cli/commands/build.js +1 -1
  7. package/cli/commands/build.ts +1 -1
  8. package/cli/commands/graph.js +4 -4
  9. package/cli/commands/graph.ts +4 -4
  10. package/cli/commands/validate.d.ts.map +1 -1
  11. package/cli/commands/validate.js +43 -6
  12. package/cli/commands/validate.ts +41 -8
  13. package/cli/config-schema.d.ts +39 -0
  14. package/cli/config-schema.d.ts.map +1 -1
  15. package/cli/config-schema.js +4 -2
  16. package/cli/config-schema.ts +4 -2
  17. package/cli/config.d.ts.map +1 -1
  18. package/cli/config.js +8 -2
  19. package/cli/config.ts +8 -2
  20. package/cli/constraint-registry.d.ts +16 -0
  21. package/cli/constraint-registry.d.ts.map +1 -1
  22. package/cli/constraint-registry.js +64 -31
  23. package/cli/constraint-registry.ts +67 -31
  24. package/cli/dcv.js +8 -24
  25. package/cli/dcv.ts +8 -20
  26. package/cli/json-output.d.ts +8 -1
  27. package/cli/json-output.d.ts.map +1 -1
  28. package/cli/json-output.js +13 -4
  29. package/cli/json-output.ts +20 -4
  30. package/cli/types.d.ts +2 -0
  31. package/cli/types.d.ts.map +1 -1
  32. package/cli/types.ts +2 -0
  33. package/cli/validate-api.d.ts +40 -0
  34. package/cli/validate-api.d.ts.map +1 -0
  35. package/cli/validate-api.js +85 -0
  36. package/cli/validate-api.ts +126 -0
  37. package/cli/version-banner.d.ts +20 -0
  38. package/cli/version-banner.d.ts.map +1 -0
  39. package/cli/version-banner.js +49 -0
  40. package/cli/version-banner.ts +61 -0
  41. package/core/breakpoints.d.ts +8 -2
  42. package/core/breakpoints.d.ts.map +1 -1
  43. package/core/breakpoints.js +24 -3
  44. package/core/breakpoints.ts +22 -3
  45. package/core/color.js +4 -4
  46. package/core/color.ts +4 -4
  47. package/core/constraints/monotonic-lightness.d.ts.map +1 -1
  48. package/core/constraints/monotonic-lightness.js +9 -5
  49. package/core/constraints/monotonic-lightness.ts +9 -4
  50. package/core/constraints/wcag.d.ts.map +1 -1
  51. package/core/constraints/wcag.js +6 -0
  52. package/core/constraints/wcag.ts +6 -0
  53. package/core/dtcg.d.ts +38 -0
  54. package/core/dtcg.d.ts.map +1 -0
  55. package/core/dtcg.js +88 -0
  56. package/core/dtcg.ts +102 -0
  57. package/core/engine.d.ts +6 -0
  58. package/core/engine.d.ts.map +1 -1
  59. package/core/engine.ts +7 -0
  60. package/core/flatten.d.ts +5 -3
  61. package/core/flatten.d.ts.map +1 -1
  62. package/core/flatten.js +24 -10
  63. package/core/flatten.ts +39 -16
  64. package/core/image-export.d.ts.map +1 -1
  65. package/core/image-export.js +10 -7
  66. package/core/image-export.ts +9 -6
  67. package/core/index.d.ts +2 -0
  68. package/core/index.d.ts.map +1 -1
  69. package/core/index.js +4 -0
  70. package/core/index.ts +6 -0
  71. package/core/why.d.ts +1 -1
  72. package/core/why.d.ts.map +1 -1
  73. package/core/why.ts +1 -1
  74. package/mcp/contracts.d.ts +118 -0
  75. package/mcp/contracts.d.ts.map +1 -0
  76. package/mcp/contracts.js +30 -0
  77. package/mcp/contracts.ts +51 -0
  78. package/mcp/index.d.ts +9 -0
  79. package/mcp/index.d.ts.map +1 -0
  80. package/mcp/index.js +32 -0
  81. package/mcp/index.ts +70 -0
  82. package/mcp/tools.d.ts +52 -0
  83. package/mcp/tools.d.ts.map +1 -0
  84. package/mcp/tools.js +172 -0
  85. package/mcp/tools.ts +254 -0
  86. package/package.json +41 -26
  87. package/server.json +21 -0
  88. package/cli/constraints-loader.d.ts +0 -30
  89. package/cli/constraints-loader.d.ts.map +0 -1
  90. package/cli/constraints-loader.js +0 -58
  91. package/cli/constraints-loader.ts +0 -83
  92. package/cli/engine-helpers.d.ts +0 -41
  93. package/cli/engine-helpers.d.ts.map +0 -1
  94. package/cli/engine-helpers.js +0 -135
  95. package/cli/engine-helpers.ts +0 -133
  96. package/core/cross-axis-config.d.ts +0 -34
  97. package/core/cross-axis-config.d.ts.map +0 -1
  98. package/core/cross-axis-config.js +0 -173
  99. package/core/cross-axis-config.ts +0 -182
@@ -1,58 +0,0 @@
1
- /**
2
- * @deprecated This module is deprecated. Use constraint-registry.ts instead.
3
- *
4
- * Phase 3A (Architectural Cleanup): This file contains legacy runtime constraint
5
- * loading logic that has been replaced by the centralized constraint-registry.ts module.
6
- *
7
- * Migration: Replace attachRuntimeConstraints() with setupConstraints() from constraint-registry.ts
8
- *
9
- * This file will be removed in a future major version.
10
- */
11
- import { loadCrossAxisPlugin } from '../core/cross-axis-config.js';
12
- import { ThresholdPlugin } from '../core/constraints/threshold.js';
13
- /**
14
- * Attach runtime constraints that depend on project files or built-in policies:
15
- * - Cross-axis rules from themes/cross-axis*.rules.json
16
- * - Built-in threshold rules (e.g., control.size.min >= 44px)
17
- *
18
- * @deprecated Use setupConstraints() from constraint-registry.ts instead.
19
- * This function will be removed in a future major version.
20
- */
21
- export function attachRuntimeConstraints(engine, opts) {
22
- const { knownIds, bp, crossAxisDebug, config } = opts;
23
- // Cross-axis rules: global + optional breakpoint-specific
24
- try {
25
- engine.use(loadCrossAxisPlugin('themes/cross-axis.rules.json', bp, {
26
- debug: !!crossAxisDebug,
27
- knownIds,
28
- }));
29
- if (bp) {
30
- const bpRulesPath = `themes/cross-axis.${bp}.rules.json`;
31
- engine.use(loadCrossAxisPlugin(bpRulesPath, bp, {
32
- debug: !!crossAxisDebug,
33
- knownIds,
34
- }));
35
- }
36
- }
37
- catch {
38
- // If cross-axis configuration fails, continue with other constraints.
39
- }
40
- const constraintsCfg = config.constraints ?? {};
41
- // Built-in threshold rule for touch targets (configurable)
42
- const enableBuiltInThreshold = constraintsCfg.enableBuiltInThreshold === undefined ? true : !!constraintsCfg.enableBuiltInThreshold;
43
- if (enableBuiltInThreshold) {
44
- try {
45
- engine.use(ThresholdPlugin([
46
- {
47
- id: 'control.size.min',
48
- op: '>=',
49
- valuePx: 44,
50
- where: 'Touch target (WCAG / Apple HIG)',
51
- },
52
- ], 'threshold'));
53
- }
54
- catch {
55
- // Threshold attachment is best-effort; failures should not abort validation.
56
- }
57
- }
58
- }
@@ -1,83 +0,0 @@
1
- /**
2
- * @deprecated This module is deprecated. Use constraint-registry.ts instead.
3
- *
4
- * Phase 3A (Architectural Cleanup): This file contains legacy runtime constraint
5
- * loading logic that has been replaced by the centralized constraint-registry.ts module.
6
- *
7
- * Migration: Replace attachRuntimeConstraints() with setupConstraints() from constraint-registry.ts
8
- *
9
- * This file will be removed in a future major version.
10
- */
11
-
12
- import type { Engine } from '../core/engine.js';
13
- import { loadCrossAxisPlugin } from '../core/cross-axis-config.js';
14
- import { ThresholdPlugin } from '../core/constraints/threshold.js';
15
- import type { Breakpoint } from '../core/breakpoints.js';
16
- import type { DcvConfig } from './types.js';
17
-
18
- type AttachRuntimeOpts = {
19
- config: DcvConfig;
20
- knownIds: Set<string>;
21
- bp?: Breakpoint;
22
- crossAxisDebug?: boolean;
23
- };
24
-
25
- /**
26
- * Attach runtime constraints that depend on project files or built-in policies:
27
- * - Cross-axis rules from themes/cross-axis*.rules.json
28
- * - Built-in threshold rules (e.g., control.size.min >= 44px)
29
- *
30
- * @deprecated Use setupConstraints() from constraint-registry.ts instead.
31
- * This function will be removed in a future major version.
32
- */
33
- export function attachRuntimeConstraints(engine: Engine, opts: AttachRuntimeOpts): void {
34
- const { knownIds, bp, crossAxisDebug, config } = opts;
35
-
36
- // Cross-axis rules: global + optional breakpoint-specific
37
- try {
38
- engine.use(
39
- loadCrossAxisPlugin('themes/cross-axis.rules.json', bp, {
40
- debug: !!crossAxisDebug,
41
- knownIds,
42
- }),
43
- );
44
-
45
- if (bp) {
46
- const bpRulesPath = `themes/cross-axis.${bp}.rules.json`;
47
- engine.use(
48
- loadCrossAxisPlugin(bpRulesPath, bp, {
49
- debug: !!crossAxisDebug,
50
- knownIds,
51
- }),
52
- );
53
- }
54
- } catch {
55
- // If cross-axis configuration fails, continue with other constraints.
56
- }
57
-
58
- const constraintsCfg = config.constraints ?? {};
59
-
60
- // Built-in threshold rule for touch targets (configurable)
61
- const enableBuiltInThreshold =
62
- constraintsCfg.enableBuiltInThreshold === undefined ? true : !!constraintsCfg.enableBuiltInThreshold;
63
-
64
- if (enableBuiltInThreshold) {
65
- try {
66
- engine.use(
67
- ThresholdPlugin(
68
- [
69
- {
70
- id: 'control.size.min',
71
- op: '>=',
72
- valuePx: 44,
73
- where: 'Touch target (WCAG / Apple HIG)',
74
- },
75
- ],
76
- 'threshold',
77
- ),
78
- );
79
- } catch {
80
- // Threshold attachment is best-effort; failures should not abort validation.
81
- }
82
- }
83
- }
@@ -1,41 +0,0 @@
1
- /**
2
- * @deprecated This module is deprecated. Use constraint-registry.ts instead.
3
- *
4
- * Phase 3A (Architectural Cleanup): This file contains legacy constraint loading logic
5
- * that has been replaced by the centralized constraint-registry.ts module.
6
- *
7
- * Migration guide:
8
- * - Replace createEngine() or createValidationEngine() with:
9
- * ```ts
10
- * import { Engine } from '../core/engine.js';
11
- * import { flattenTokens, type FlatToken } from '../core/flatten.js';
12
- * import { setupConstraints } from './constraint-registry.js';
13
- *
14
- * const { flat, edges } = flattenTokens(tokens);
15
- * const init = {};
16
- * for (const t of Object.values(flat)) {
17
- * init[(t as FlatToken).id] = (t as FlatToken).value;
18
- * }
19
- * const engine = new Engine(init, edges);
20
- * const knownIds = new Set(Object.keys(init));
21
- * setupConstraints(engine, { config, bp }, { knownIds });
22
- * ```
23
- *
24
- * This file will be removed in a future major version.
25
- */
26
- import { type TokenNode } from '../core/flatten.js';
27
- import { Engine } from '../core/engine.js';
28
- import { loadTokensWithBreakpoint, type Breakpoint } from '../core/breakpoints.js';
29
- import type { DcvConfig } from './types.js';
30
- /**
31
- * @deprecated Use constraint-registry.ts setupConstraints() instead.
32
- * This function will be removed in a future major version.
33
- */
34
- export declare function createEngine(tokensRoot: TokenNode, config?: DcvConfig): Engine;
35
- /**
36
- * @deprecated Use constraint-registry.ts setupConstraints() instead.
37
- * This function will be removed in a future major version.
38
- */
39
- export declare function createValidationEngine(tokensRoot: TokenNode, bp: Breakpoint | undefined, config: DcvConfig): Engine;
40
- export { loadTokensWithBreakpoint };
41
- //# sourceMappingURL=engine-helpers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"engine-helpers.d.ts","sourceRoot":"","sources":["engine-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAiB,KAAK,SAAS,EAAkB,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAI3C,OAAO,EAA8B,wBAAwB,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAC/G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAgE5C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,GAAE,SAAc,GAAG,MAAM,CAQlF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,UAAU,GAAG,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,CAgBnH;AAED,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
@@ -1,135 +0,0 @@
1
- /**
2
- * @deprecated This module is deprecated. Use constraint-registry.ts instead.
3
- *
4
- * Phase 3A (Architectural Cleanup): This file contains legacy constraint loading logic
5
- * that has been replaced by the centralized constraint-registry.ts module.
6
- *
7
- * Migration guide:
8
- * - Replace createEngine() or createValidationEngine() with:
9
- * ```ts
10
- * import { Engine } from '../core/engine.js';
11
- * import { flattenTokens, type FlatToken } from '../core/flatten.js';
12
- * import { setupConstraints } from './constraint-registry.js';
13
- *
14
- * const { flat, edges } = flattenTokens(tokens);
15
- * const init = {};
16
- * for (const t of Object.values(flat)) {
17
- * init[(t as FlatToken).id] = (t as FlatToken).value;
18
- * }
19
- * const engine = new Engine(init, edges);
20
- * const knownIds = new Set(Object.keys(init));
21
- * setupConstraints(engine, { config, bp }, { knownIds });
22
- * ```
23
- *
24
- * This file will be removed in a future major version.
25
- */
26
- import { flattenTokens } from '../core/flatten.js';
27
- import { Engine } from '../core/engine.js';
28
- import { MonotonicPlugin, parseSize as parseSizePx } from '../core/constraints/monotonic.js';
29
- import { MonotonicLightness } from '../core/constraints/monotonic-lightness.js';
30
- import { WcagContrastPlugin } from '../core/constraints/wcag.js';
31
- import { loadOrders as loadOrdersBP, loadTokensWithBreakpoint } from '../core/breakpoints.js';
32
- function applyMonotonicPlugins(engine, bp) {
33
- function loadOrders(path) {
34
- try {
35
- // eslint-disable-next-line @typescript-eslint/no-require-imports
36
- return JSON.parse(require('node:fs').readFileSync(path, 'utf8')).order;
37
- }
38
- catch {
39
- return [];
40
- }
41
- }
42
- const suffix = bp ? `.${bp}` : '';
43
- const typOrders = loadOrders(`themes/typography${suffix}.order.json`);
44
- const spacingOrders = loadOrders(`themes/spacing${suffix}.order.json`);
45
- const layoutOrders = loadOrders(`themes/layout${suffix}.order.json`);
46
- const colorOrders = loadOrders(`themes/color${suffix}.order.json`);
47
- if (typOrders.length)
48
- engine.use(MonotonicPlugin(typOrders, parseSizePx, 'monotonic-typography'));
49
- if (spacingOrders.length)
50
- engine.use(MonotonicPlugin(spacingOrders, parseSizePx, 'monotonic-spacing'));
51
- if (layoutOrders.length)
52
- engine.use(MonotonicPlugin(layoutOrders, parseSizePx, 'monotonic-layout'));
53
- if (colorOrders.length)
54
- engine.use(MonotonicLightness(colorOrders));
55
- }
56
- function applyWcagPlugins(engine, config) {
57
- const constraintsCfg = config.constraints ?? {};
58
- if (constraintsCfg.wcag) {
59
- const wcagRules = constraintsCfg.wcag.map((r) => ({
60
- fg: r.foreground,
61
- bg: r.background,
62
- min: r.ratio || 4.5,
63
- where: r.description || 'Unknown',
64
- }));
65
- engine.use(WcagContrastPlugin(wcagRules));
66
- }
67
- const enableDefaults = constraintsCfg.enableBuiltInWcagDefaults === undefined
68
- ? true
69
- : !!constraintsCfg.enableBuiltInWcagDefaults;
70
- if (enableDefaults) {
71
- const defaultWcagPairs = [
72
- {
73
- fg: 'color.role.text.default',
74
- bg: 'color.role.bg.surface',
75
- min: 4.5,
76
- where: 'Body text on surface',
77
- },
78
- {
79
- fg: 'color.role.accent.default',
80
- bg: 'color.role.bg.surface',
81
- min: 3.0,
82
- where: 'Accent on surface',
83
- },
84
- {
85
- fg: 'color.role.focus.ring',
86
- bg: 'color.role.bg.surface',
87
- min: 3.0,
88
- where: 'Focus ring on surface',
89
- backdrop: '#ffffff',
90
- },
91
- ];
92
- engine.use(WcagContrastPlugin(defaultWcagPairs));
93
- }
94
- }
95
- /**
96
- * @deprecated Use constraint-registry.ts setupConstraints() instead.
97
- * This function will be removed in a future major version.
98
- */
99
- export function createEngine(tokensRoot, config = {}) {
100
- const { flat, edges } = flattenTokens(tokensRoot);
101
- const init = {};
102
- for (const [id, token] of Object.entries(flat))
103
- init[id] = token.value;
104
- const engine = new Engine(init, edges);
105
- applyMonotonicPlugins(engine, undefined);
106
- applyWcagPlugins(engine, config);
107
- return engine;
108
- }
109
- /**
110
- * @deprecated Use constraint-registry.ts setupConstraints() instead.
111
- * This function will be removed in a future major version.
112
- */
113
- export function createValidationEngine(tokensRoot, bp, config) {
114
- const { flat, edges } = flattenTokens(tokensRoot);
115
- const init = {};
116
- for (const t of Object.values(flat))
117
- init[t.id] = t.value;
118
- const engine = new Engine(init, edges);
119
- // Use breakpoint-aware order loading where available
120
- const typ = loadOrdersBP('typography', bp);
121
- const spc = loadOrdersBP('spacing', bp);
122
- const lay = loadOrdersBP('layout', bp);
123
- const col = loadOrdersBP('color', bp);
124
- if (typ.length)
125
- engine.use(MonotonicPlugin(typ, parseSizePx, 'monotonic-typography'));
126
- if (spc.length)
127
- engine.use(MonotonicPlugin(spc, parseSizePx, 'monotonic-spacing'));
128
- if (lay.length)
129
- engine.use(MonotonicPlugin(lay, parseSizePx, 'monotonic-layout'));
130
- if (col.length)
131
- engine.use(MonotonicLightness(col));
132
- applyWcagPlugins(engine, config);
133
- return engine;
134
- }
135
- export { loadTokensWithBreakpoint };
@@ -1,133 +0,0 @@
1
- /**
2
- * @deprecated This module is deprecated. Use constraint-registry.ts instead.
3
- *
4
- * Phase 3A (Architectural Cleanup): This file contains legacy constraint loading logic
5
- * that has been replaced by the centralized constraint-registry.ts module.
6
- *
7
- * Migration guide:
8
- * - Replace createEngine() or createValidationEngine() with:
9
- * ```ts
10
- * import { Engine } from '../core/engine.js';
11
- * import { flattenTokens, type FlatToken } from '../core/flatten.js';
12
- * import { setupConstraints } from './constraint-registry.js';
13
- *
14
- * const { flat, edges } = flattenTokens(tokens);
15
- * const init = {};
16
- * for (const t of Object.values(flat)) {
17
- * init[(t as FlatToken).id] = (t as FlatToken).value;
18
- * }
19
- * const engine = new Engine(init, edges);
20
- * const knownIds = new Set(Object.keys(init));
21
- * setupConstraints(engine, { config, bp }, { knownIds });
22
- * ```
23
- *
24
- * This file will be removed in a future major version.
25
- */
26
-
27
- import { flattenTokens, type TokenNode, type FlatToken } from '../core/flatten.js';
28
- import { Engine } from '../core/engine.js';
29
- import { MonotonicPlugin, parseSize as parseSizePx } from '../core/constraints/monotonic.js';
30
- import { MonotonicLightness } from '../core/constraints/monotonic-lightness.js';
31
- import { WcagContrastPlugin } from '../core/constraints/wcag.js';
32
- import { loadOrders as loadOrdersBP, loadTokensWithBreakpoint, type Breakpoint } from '../core/breakpoints.js';
33
- import type { DcvConfig } from './types.js';
34
-
35
- function applyMonotonicPlugins(engine: Engine, bp: Breakpoint | undefined): void {
36
- function loadOrders(path: string) {
37
- try {
38
- // eslint-disable-next-line @typescript-eslint/no-require-imports
39
- return JSON.parse(require('node:fs').readFileSync(path, 'utf8')).order as [string, '<='|'>=', string][];
40
- } catch { return []; }
41
- }
42
- const suffix = bp ? `.${bp}` : '';
43
- const typOrders = loadOrders(`themes/typography${suffix}.order.json`);
44
- const spacingOrders = loadOrders(`themes/spacing${suffix}.order.json`);
45
- const layoutOrders = loadOrders(`themes/layout${suffix}.order.json`);
46
- const colorOrders = loadOrders(`themes/color${suffix}.order.json`);
47
- if (typOrders.length) engine.use(MonotonicPlugin(typOrders, parseSizePx, 'monotonic-typography'));
48
- if (spacingOrders.length) engine.use(MonotonicPlugin(spacingOrders, parseSizePx, 'monotonic-spacing'));
49
- if (layoutOrders.length) engine.use(MonotonicPlugin(layoutOrders, parseSizePx, 'monotonic-layout'));
50
- if (colorOrders.length) engine.use(MonotonicLightness(colorOrders));
51
- }
52
-
53
- function applyWcagPlugins(engine: Engine, config: DcvConfig): void {
54
- const constraintsCfg = config.constraints ?? {};
55
-
56
- if (constraintsCfg.wcag) {
57
- const wcagRules = constraintsCfg.wcag.map((r: any) => ({
58
- fg: r.foreground,
59
- bg: r.background,
60
- min: r.ratio || 4.5,
61
- where: r.description || 'Unknown',
62
- }));
63
- engine.use(WcagContrastPlugin(wcagRules));
64
- }
65
-
66
- const enableDefaults =
67
- constraintsCfg.enableBuiltInWcagDefaults === undefined
68
- ? true
69
- : !!constraintsCfg.enableBuiltInWcagDefaults;
70
-
71
- if (enableDefaults) {
72
- const defaultWcagPairs = [
73
- {
74
- fg: 'color.role.text.default',
75
- bg: 'color.role.bg.surface',
76
- min: 4.5,
77
- where: 'Body text on surface',
78
- },
79
- {
80
- fg: 'color.role.accent.default',
81
- bg: 'color.role.bg.surface',
82
- min: 3.0,
83
- where: 'Accent on surface',
84
- },
85
- {
86
- fg: 'color.role.focus.ring',
87
- bg: 'color.role.bg.surface',
88
- min: 3.0,
89
- where: 'Focus ring on surface',
90
- backdrop: '#ffffff',
91
- },
92
- ];
93
- engine.use(WcagContrastPlugin(defaultWcagPairs));
94
- }
95
- }
96
-
97
- /**
98
- * @deprecated Use constraint-registry.ts setupConstraints() instead.
99
- * This function will be removed in a future major version.
100
- */
101
- export function createEngine(tokensRoot: TokenNode, config: DcvConfig = {}): Engine {
102
- const { flat, edges } = flattenTokens(tokensRoot);
103
- const init: Record<string, string | number> = {};
104
- for (const [id, token] of Object.entries(flat)) init[id] = (token as FlatToken).value;
105
- const engine = new Engine(init, edges);
106
- applyMonotonicPlugins(engine, undefined);
107
- applyWcagPlugins(engine, config);
108
- return engine;
109
- }
110
-
111
- /**
112
- * @deprecated Use constraint-registry.ts setupConstraints() instead.
113
- * This function will be removed in a future major version.
114
- */
115
- export function createValidationEngine(tokensRoot: TokenNode, bp: Breakpoint | undefined, config: DcvConfig): Engine {
116
- const { flat, edges } = flattenTokens(tokensRoot);
117
- const init: Record<string, string | number> = {};
118
- for (const t of Object.values(flat)) init[(t as FlatToken).id] = (t as FlatToken).value;
119
- const engine = new Engine(init, edges);
120
- // Use breakpoint-aware order loading where available
121
- const typ = loadOrdersBP('typography', bp);
122
- const spc = loadOrdersBP('spacing', bp);
123
- const lay = loadOrdersBP('layout', bp);
124
- const col = loadOrdersBP('color', bp);
125
- if (typ.length) engine.use(MonotonicPlugin(typ, parseSizePx, 'monotonic-typography'));
126
- if (spc.length) engine.use(MonotonicPlugin(spc, parseSizePx, 'monotonic-spacing'));
127
- if (lay.length) engine.use(MonotonicPlugin(lay, parseSizePx, 'monotonic-layout'));
128
- if (col.length) engine.use(MonotonicLightness(col));
129
- applyWcagPlugins(engine, config);
130
- return engine;
131
- }
132
-
133
- export { loadTokensWithBreakpoint };
@@ -1,34 +0,0 @@
1
- /**
2
- * @deprecated This module is deprecated. Use cli/cross-axis-loader.ts instead.
3
- *
4
- * Phase 3B (Filesystem Separation): This file contains filesystem access logic
5
- * that has been moved to the CLI layer (cli/cross-axis-loader.ts).
6
- *
7
- * Core modules should not import from node:fs. Instead:
8
- * - CLI code uses cli/cross-axis-loader.ts to read and parse rules
9
- * - Core plugin (core/constraints/cross-axis.ts) accepts pre-parsed rules
10
- *
11
- * Migration:
12
- * ```ts
13
- * // OLD (core reads filesystem):
14
- * import { loadCrossAxisPlugin } from './core/cross-axis-config.js';
15
- * engine.use(loadCrossAxisPlugin(path, bp, { knownIds }));
16
- *
17
- * // NEW (CLI reads, core receives data):
18
- * import { loadCrossAxisRules } from './cli/cross-axis-loader.js';
19
- * import { CrossAxisPlugin } from './core/constraints/cross-axis.js';
20
- * const rules = loadCrossAxisRules(path, { bp, knownIds });
21
- * engine.use(CrossAxisPlugin(rules, bp));
22
- * ```
23
- *
24
- * This file will be removed in a future major version.
25
- */
26
- /**
27
- * @deprecated Use cli/cross-axis-loader.ts loadCrossAxisRules() + CrossAxisPlugin() instead.
28
- * This function will be removed in a future major version.
29
- */
30
- export declare function loadCrossAxisPlugin(path: string, bp?: string, opts?: {
31
- debug?: boolean;
32
- knownIds?: Set<string>;
33
- }): import("./engine.js").ConstraintPlugin;
34
- //# sourceMappingURL=cross-axis-config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cross-axis-config.d.ts","sourceRoot":"","sources":["cross-axis-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAUH;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,EAAE,CAAC,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,0CA2HnD"}
@@ -1,173 +0,0 @@
1
- /**
2
- * @deprecated This module is deprecated. Use cli/cross-axis-loader.ts instead.
3
- *
4
- * Phase 3B (Filesystem Separation): This file contains filesystem access logic
5
- * that has been moved to the CLI layer (cli/cross-axis-loader.ts).
6
- *
7
- * Core modules should not import from node:fs. Instead:
8
- * - CLI code uses cli/cross-axis-loader.ts to read and parse rules
9
- * - Core plugin (core/constraints/cross-axis.ts) accepts pre-parsed rules
10
- *
11
- * Migration:
12
- * ```ts
13
- * // OLD (core reads filesystem):
14
- * import { loadCrossAxisPlugin } from './core/cross-axis-config.js';
15
- * engine.use(loadCrossAxisPlugin(path, bp, { knownIds }));
16
- *
17
- * // NEW (CLI reads, core receives data):
18
- * import { loadCrossAxisRules } from './cli/cross-axis-loader.js';
19
- * import { CrossAxisPlugin } from './core/constraints/cross-axis.js';
20
- * const rules = loadCrossAxisRules(path, { bp, knownIds });
21
- * engine.use(CrossAxisPlugin(rules, bp));
22
- * ```
23
- *
24
- * This file will be removed in a future major version.
25
- */
26
- import fs from "node:fs";
27
- import { CrossAxisPlugin } from "./constraints/cross-axis.js";
28
- /**
29
- * @deprecated Use cli/cross-axis-loader.ts loadCrossAxisRules() + CrossAxisPlugin() instead.
30
- * This function will be removed in a future major version.
31
- */
32
- export function loadCrossAxisPlugin(path, bp, opts) {
33
- const debug = !!opts?.debug;
34
- const known = opts?.knownIds ?? new Set();
35
- const log = (...args) => { if (debug)
36
- console.log("[cross-axis]", ...args); };
37
- if (!fs.existsSync(path)) {
38
- log(`no rules file at ${path} (bp=${bp ?? "global"})`);
39
- return CrossAxisPlugin([], bp);
40
- }
41
- const raw = JSON.parse(fs.readFileSync(path, "utf8"));
42
- const rules = [];
43
- const unknownIds = new Set();
44
- const skipped = [];
45
- // Fuzzy suggestion helpers (lightweight Levenshtein)
46
- function levenshtein(a, b) {
47
- const dp = Array(b.length + 1).fill(0).map((_, j) => j);
48
- for (let i = 1; i <= a.length; i++) {
49
- let prev = i - 1, cur = i;
50
- for (let j = 1; j <= b.length; j++) {
51
- const tmp = cur;
52
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
53
- cur = Math.min(dp[j] + 1, cur + 1, prev + cost);
54
- dp[j] = tmp;
55
- prev = tmp;
56
- }
57
- dp[b.length] = cur;
58
- }
59
- return dp[b.length];
60
- }
61
- function suggest(id, k = 3) {
62
- return [...known].map(c => ({ id: c, d: levenshtein(id, c) }))
63
- .sort((a, b) => a.d - b.d)
64
- .slice(0, k);
65
- }
66
- const needId = (id) => {
67
- if (!id)
68
- return false;
69
- if (!known.has(id)) {
70
- unknownIds.add(id);
71
- }
72
- return true;
73
- };
74
- for (const r of raw.rules || []) {
75
- if (r.bp && bp && r.bp !== bp) {
76
- continue;
77
- }
78
- if (r.bp && !bp) { // rule targets specific breakpoint; skip in global run
79
- continue;
80
- }
81
- try {
82
- if (r.when && r.require) {
83
- // Validate IDs
84
- needId(r.when.id);
85
- needId(r.require.id);
86
- if (r.require.ref)
87
- needId(r.require.ref);
88
- rules.push({
89
- id: r.id, level: r.level, where: r.where,
90
- when: { id: r.when.id, test: makeOp(r.when.op, r.when.value) },
91
- require: {
92
- id: r.require.id,
93
- test: (v, ctx) => {
94
- const rhs = valueOrRef(ctx, r.require.ref, r.require.fallback);
95
- return cmp(v, rhs, r.require.op);
96
- },
97
- msg: (v, ctx) => {
98
- const rhs = valueOrRef(ctx, r.require.ref, r.require.fallback);
99
- return `${r.require.id} ${prettyFail(r.require.op)} ${fmt(rhs)} (was ${fmt(v)})`;
100
- }
101
- }
102
- });
103
- }
104
- else if (r.compare) {
105
- needId(r.compare.a);
106
- needId(r.compare.b);
107
- rules.push({
108
- id: r.id, level: r.level, where: r.where,
109
- when: { id: r.compare.a, test: () => true },
110
- require: {
111
- id: r.compare.a,
112
- test: (_, ctx) => {
113
- const a = ctx.getPx(r.compare.a) ?? NaN;
114
- const b = ctx.getPx(r.compare.b) ?? NaN;
115
- const delta = px(r.compare.delta ?? 0);
116
- if (Number.isNaN(a) || Number.isNaN(b))
117
- return true; // skip check if missing
118
- return cmp(a, b + delta, r.compare.op);
119
- },
120
- msg: (_, ctx) => {
121
- const a = ctx.getPx(r.compare.a);
122
- const b = ctx.getPx(r.compare.b);
123
- const delta = px(r.compare.delta ?? 0);
124
- return `${r.compare.a} ${prettyFail(r.compare.op)} ${fmt((b ?? 0) + delta)} (was ${fmt(a ?? NaN)})`;
125
- }
126
- }
127
- });
128
- }
129
- else {
130
- skipped.push({ id: r.id, reason: "neither when+require nor compare present" });
131
- }
132
- }
133
- catch (e) {
134
- skipped.push({ id: r.id, reason: `exception: ${e?.message ?? e}` });
135
- }
136
- }
137
- log(`loaded ${rules.length} rule(s) from ${path}${bp ? ` [bp=${bp}]` : ""}`);
138
- if (unknownIds.size) {
139
- log(`unknown ids referenced:`, [...unknownIds].join(", "));
140
- for (const u of unknownIds) {
141
- const s = suggest(u, 3);
142
- if (s.length)
143
- log(` did you mean: ${s.map(x => `${x.id} (d=${x.d})`).join(', ')}`);
144
- }
145
- }
146
- if (skipped.length) {
147
- for (const s of skipped)
148
- log(`skipped rule ${s.id ?? "(no id)"} — ${s.reason}`);
149
- }
150
- // Extra hint for common anchor pitfall
151
- for (const r of raw.rules || []) {
152
- if (r.require?.ref && !known.has(r.require.ref)) {
153
- log(`anchor missing: ${r.require.ref} → will use fallback=${JSON.stringify(r.require.fallback)} when evaluating`);
154
- }
155
- }
156
- return CrossAxisPlugin(rules, bp);
157
- }
158
- // helpers
159
- const px = (v) => typeof v === "number" ? v : parseFloat(String(v)) * (String(v).trim().endsWith("rem") ? 16 : 1);
160
- const cmp = (a, b, op) => op === ">=" ? a >= b : op === ">" ? a > b : op === "<=" ? a <= b : op === "<" ? a < b : op === "==" ? a === b : a !== b;
161
- const prettyFail = (op) => ({ ">=": "<", ">": "≤", "<=": ">", "<": "≥", "==": "≠", "!=": "=" }[op] || "≠");
162
- const fmt = (v) => Number.isFinite(Number(v)) ? `${Number(v)}px` : String(v);
163
- function valueOrRef(ctx, ref, fallback) {
164
- if (ref) {
165
- const v = ctx.getPx(ref);
166
- if (v != null)
167
- return v;
168
- }
169
- return typeof fallback === "number" ? fallback : px(fallback ?? 0);
170
- }
171
- function makeOp(op, rhs) {
172
- return (v) => cmp(v, rhs, op);
173
- }