@mseep/dembrandt 0.19.5

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 (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +408 -0
  3. package/dist/index.d.ts +8 -0
  4. package/dist/index.js +532 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/browser.d.ts +16 -0
  7. package/dist/lib/browser.js +27 -0
  8. package/dist/lib/browser.js.map +1 -0
  9. package/dist/lib/colors.d.ts +101 -0
  10. package/dist/lib/colors.js +405 -0
  11. package/dist/lib/colors.js.map +1 -0
  12. package/dist/lib/compare.d.ts +31 -0
  13. package/dist/lib/compare.js +46 -0
  14. package/dist/lib/compare.js.map +1 -0
  15. package/dist/lib/discovery.d.ts +31 -0
  16. package/dist/lib/discovery.js +243 -0
  17. package/dist/lib/discovery.js.map +1 -0
  18. package/dist/lib/drift.d.ts +64 -0
  19. package/dist/lib/drift.js +383 -0
  20. package/dist/lib/drift.js.map +1 -0
  21. package/dist/lib/dtcg/validate.d.ts +51 -0
  22. package/dist/lib/dtcg/validate.js +1403 -0
  23. package/dist/lib/dtcg/validate.js.map +1 -0
  24. package/dist/lib/exit-codes.d.ts +29 -0
  25. package/dist/lib/exit-codes.js +26 -0
  26. package/dist/lib/exit-codes.js.map +1 -0
  27. package/dist/lib/extractors/breakpoints.d.ts +5 -0
  28. package/dist/lib/extractors/breakpoints.js +450 -0
  29. package/dist/lib/extractors/breakpoints.js.map +1 -0
  30. package/dist/lib/extractors/colors.d.ts +2 -0
  31. package/dist/lib/extractors/colors.js +657 -0
  32. package/dist/lib/extractors/colors.js.map +1 -0
  33. package/dist/lib/extractors/components.d.ts +4 -0
  34. package/dist/lib/extractors/components.js +370 -0
  35. package/dist/lib/extractors/components.js.map +1 -0
  36. package/dist/lib/extractors/index.d.ts +9 -0
  37. package/dist/lib/extractors/index.js +1257 -0
  38. package/dist/lib/extractors/index.js.map +1 -0
  39. package/dist/lib/extractors/logo.d.ts +2 -0
  40. package/dist/lib/extractors/logo.js +626 -0
  41. package/dist/lib/extractors/logo.js.map +1 -0
  42. package/dist/lib/extractors/spacing.d.ts +4 -0
  43. package/dist/lib/extractors/spacing.js +163 -0
  44. package/dist/lib/extractors/spacing.js.map +1 -0
  45. package/dist/lib/extractors/teach.d.ts +1 -0
  46. package/dist/lib/extractors/teach.js +66 -0
  47. package/dist/lib/extractors/teach.js.map +1 -0
  48. package/dist/lib/extractors/typography.d.ts +1 -0
  49. package/dist/lib/extractors/typography.js +163 -0
  50. package/dist/lib/extractors/typography.js.map +1 -0
  51. package/dist/lib/findings.d.ts +34 -0
  52. package/dist/lib/findings.js +166 -0
  53. package/dist/lib/findings.js.map +1 -0
  54. package/dist/lib/formatters/dtcg.d.ts +10 -0
  55. package/dist/lib/formatters/dtcg.js +416 -0
  56. package/dist/lib/formatters/dtcg.js.map +1 -0
  57. package/dist/lib/formatters/html.d.ts +25 -0
  58. package/dist/lib/formatters/html.js +479 -0
  59. package/dist/lib/formatters/html.js.map +1 -0
  60. package/dist/lib/formatters/markdown.d.ts +5 -0
  61. package/dist/lib/formatters/markdown.js +568 -0
  62. package/dist/lib/formatters/markdown.js.map +1 -0
  63. package/dist/lib/formatters/pdf.d.ts +12 -0
  64. package/dist/lib/formatters/pdf.js +1121 -0
  65. package/dist/lib/formatters/pdf.js.map +1 -0
  66. package/dist/lib/formatters/terminal.d.ts +6 -0
  67. package/dist/lib/formatters/terminal.js +954 -0
  68. package/dist/lib/formatters/terminal.js.map +1 -0
  69. package/dist/lib/formatters/theme.d.ts +35 -0
  70. package/dist/lib/formatters/theme.js +37 -0
  71. package/dist/lib/formatters/theme.js.map +1 -0
  72. package/dist/lib/merger.d.ts +14 -0
  73. package/dist/lib/merger.js +362 -0
  74. package/dist/lib/merger.js.map +1 -0
  75. package/dist/lib/normalize.d.ts +29 -0
  76. package/dist/lib/normalize.js +59 -0
  77. package/dist/lib/normalize.js.map +1 -0
  78. package/dist/lib/robots.d.ts +12 -0
  79. package/dist/lib/robots.js +110 -0
  80. package/dist/lib/robots.js.map +1 -0
  81. package/dist/lib/run-summary.d.ts +40 -0
  82. package/dist/lib/run-summary.js +64 -0
  83. package/dist/lib/run-summary.js.map +1 -0
  84. package/dist/lib/types.d.ts +329 -0
  85. package/dist/lib/types.js +7 -0
  86. package/dist/lib/types.js.map +1 -0
  87. package/dist/lib/version.d.ts +134 -0
  88. package/dist/lib/version.js +153 -0
  89. package/dist/lib/version.js.map +1 -0
  90. package/dist/mcp-server.d.ts +11 -0
  91. package/dist/mcp-server.js +311 -0
  92. package/dist/mcp-server.js.map +1 -0
  93. package/dist/package.json +106 -0
  94. package/dist/test/_vitest-shim.d.ts +13 -0
  95. package/dist/test/_vitest-shim.js +23 -0
  96. package/dist/test/_vitest-shim.js.map +1 -0
  97. package/dist/test/cli.test.d.ts +1 -0
  98. package/dist/test/cli.test.js +24 -0
  99. package/dist/test/cli.test.js.map +1 -0
  100. package/dist/test/colors.test.d.ts +1 -0
  101. package/dist/test/colors.test.js +64 -0
  102. package/dist/test/colors.test.js.map +1 -0
  103. package/dist/test/compare.test.d.ts +1 -0
  104. package/dist/test/compare.test.js +57 -0
  105. package/dist/test/compare.test.js.map +1 -0
  106. package/dist/test/drift.test.d.ts +1 -0
  107. package/dist/test/drift.test.js +53 -0
  108. package/dist/test/drift.test.js.map +1 -0
  109. package/dist/test/dtcg-formatter.test.d.ts +1 -0
  110. package/dist/test/dtcg-formatter.test.js +48 -0
  111. package/dist/test/dtcg-formatter.test.js.map +1 -0
  112. package/dist/test/dtcg-validate.test.d.ts +1 -0
  113. package/dist/test/dtcg-validate.test.js +2129 -0
  114. package/dist/test/dtcg-validate.test.js.map +1 -0
  115. package/dist/test/exit-codes.test.d.ts +1 -0
  116. package/dist/test/exit-codes.test.js +53 -0
  117. package/dist/test/exit-codes.test.js.map +1 -0
  118. package/dist/test/findings.test.d.ts +1 -0
  119. package/dist/test/findings.test.js +77 -0
  120. package/dist/test/findings.test.js.map +1 -0
  121. package/dist/test/html.test.d.ts +1 -0
  122. package/dist/test/html.test.js +95 -0
  123. package/dist/test/html.test.js.map +1 -0
  124. package/dist/test/markdown.test.d.ts +1 -0
  125. package/dist/test/markdown.test.js +145 -0
  126. package/dist/test/markdown.test.js.map +1 -0
  127. package/dist/test/merger.test.d.ts +1 -0
  128. package/dist/test/merger.test.js +98 -0
  129. package/dist/test/merger.test.js.map +1 -0
  130. package/dist/test/normalize.test.d.ts +1 -0
  131. package/dist/test/normalize.test.js +47 -0
  132. package/dist/test/normalize.test.js.map +1 -0
  133. package/dist/test/run-summary.test.d.ts +1 -0
  134. package/dist/test/run-summary.test.js +45 -0
  135. package/dist/test/run-summary.test.js.map +1 -0
  136. package/dist/test/version.test.d.ts +1 -0
  137. package/dist/test/version.test.js +73 -0
  138. package/dist/test/version.test.js.map +1 -0
  139. package/package.json +106 -0
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Design-system findings — the honest, computable audits that back the report's
3
+ * summary scores. Every gauge number traces to a concrete finding here; nothing
4
+ * is a vanity metric. These are the decay signals product-strategy names: a hex
5
+ * off by a hair (ΔE), a role with no visual hierarchy, a brand colour that fails
6
+ * contrast, an off-scale spacing value. Pure and deterministic — given the same
7
+ * extraction it always returns the same findings, so it is safe to gate on.
8
+ *
9
+ * This mirrors the documented `--lint` categories (development-prompts.md): each
10
+ * finding has a severity, and the consistency score is derived from them.
11
+ */
12
+ import { deltaE2000, relativeLuminance } from "./colors.js";
13
+ /** Parse a hex or rgb()/rgba() string to #rrggbb, or null if unparseable. */
14
+ function toHex(input) {
15
+ if (!input)
16
+ return null;
17
+ const s = String(input).trim();
18
+ if (/^#[0-9a-f]{6}$/i.test(s))
19
+ return s.toLowerCase();
20
+ if (/^#[0-9a-f]{3}$/i.test(s)) {
21
+ return ("#" + s.slice(1).split("").map((c) => c + c).join("")).toLowerCase();
22
+ }
23
+ const m = s.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);
24
+ if (m) {
25
+ const h = (n) => Math.max(0, Math.min(255, Number(n))).toString(16).padStart(2, "0");
26
+ return ("#" + h(m[1]) + h(m[2]) + h(m[3])).toLowerCase();
27
+ }
28
+ return null;
29
+ }
30
+ /** WCAG contrast ratio between two colours (any parseable form), or null. */
31
+ function contrastRatio(a, b) {
32
+ const ha = toHex(a);
33
+ const hb = toHex(b);
34
+ if (!ha || !hb)
35
+ return null;
36
+ const la = relativeLuminance(ha);
37
+ const lb = relativeLuminance(hb);
38
+ if (la == null || lb == null)
39
+ return null;
40
+ const hi = Math.max(la, lb);
41
+ const lo = Math.min(la, lb);
42
+ return (hi + 0.05) / (lo + 0.05);
43
+ }
44
+ /** Leading pixel value of a size string like "40px (2.50rem)", or null. */
45
+ function pxOf(size) {
46
+ if (!size)
47
+ return null;
48
+ const m = String(size).match(/(-?\d+(?:\.\d+)?)\s*px/);
49
+ return m ? Number(m[1]) : null;
50
+ }
51
+ export function computeFindings(result) {
52
+ const findings = [];
53
+ // 1. Near-duplicate palette colours (ΔE2000 < just-noticeable). The "#133074
54
+ // where #133174 should be" decay — two tokens that are visually one colour.
55
+ const palette = (result.colors?.palette ?? [])
56
+ .map((c) => (c.normalized || c.color || "").toLowerCase())
57
+ .filter((h) => /^#[0-9a-f]{6}$/i.test(h));
58
+ const seenDup = new Set();
59
+ for (let i = 0; i < palette.length; i++) {
60
+ for (let j = i + 1; j < palette.length; j++) {
61
+ const d = deltaE2000(palette[i], palette[j]);
62
+ // < 1.0 = indistinguishable. Looser (the 2.3 JND) flags intentional
63
+ // surface tokens (e.g. #fff vs #f6f6f7 at ΔE 1.9) and creates noise.
64
+ if (d < 1.0) {
65
+ const key = [palette[i], palette[j]].sort().join("|");
66
+ if (seenDup.has(key))
67
+ continue;
68
+ seenDup.add(key);
69
+ findings.push({
70
+ category: "duplication",
71
+ group: "Color",
72
+ severity: "warn",
73
+ message: `${palette[i]} and ${palette[j]} are perceptually identical (ΔE ${d.toFixed(1)}) — likely one token split in two.`,
74
+ });
75
+ }
76
+ }
77
+ }
78
+ // 2. Type roles with no hierarchy — two distinct roles sharing size + weight.
79
+ // Only flag where hierarchy is *expected*: two heading levels that collide,
80
+ // or a heading sharing a size with body. Body/link/ui sharing a size is the
81
+ // convention, not a smell, so those groups are skipped.
82
+ const isHierarchy = (r) => /heading|display|title|^h[1-6]$/i.test(r);
83
+ const isText = (r) => /body|text|paragraph|^p$/i.test(r);
84
+ const styles = result.typography?.styles ?? [];
85
+ const byKey = new Map();
86
+ for (const s of styles) {
87
+ const px = pxOf(s.size);
88
+ if (px == null || !s.context)
89
+ continue;
90
+ const rounded = Math.round(px);
91
+ const weight = String(s.weight ?? "");
92
+ const wmap = byKey.get(rounded) ?? new Map();
93
+ const arr = wmap.get(weight) ?? [];
94
+ if (!arr.includes(s.context))
95
+ arr.push(s.context);
96
+ wmap.set(weight, arr);
97
+ byKey.set(rounded, wmap);
98
+ }
99
+ for (const [px, wmap] of byKey) {
100
+ for (const [weight, roles] of wmap) {
101
+ if (roles.length < 2)
102
+ continue;
103
+ const relevant = roles.filter(isHierarchy).length >= 2 || (roles.some(isHierarchy) && roles.some(isText));
104
+ if (!relevant)
105
+ continue;
106
+ findings.push({
107
+ category: "consistency",
108
+ group: "Typography",
109
+ severity: "warn",
110
+ message: `${roles.slice(0, 4).join(", ")} share ${px}px${weight ? ` / ${weight}` : ""} — no visual hierarchy between them.`,
111
+ });
112
+ }
113
+ }
114
+ // 3. Brand colour contrast on white — the default canvas. A primary that can't
115
+ // meet AA as text on white is the "brand colour fails contrast" decay. Warn
116
+ // (not error): it may be used only as a fill behind white text, which we
117
+ // can't confirm here. Checked against white only — every colour trivially
118
+ // clears one of pure black/white, so "best of the two" would never fire.
119
+ const primary = result.colors?.semantic?.primary;
120
+ if (primary) {
121
+ const onWhite = contrastRatio(primary, "#ffffff");
122
+ if (onWhite != null && onWhite < 4.5) {
123
+ findings.push({
124
+ category: "contrast",
125
+ group: "Contrast",
126
+ severity: "warn",
127
+ message: `Primary ${primary} has low contrast on white (${onWhite.toFixed(1)}:1) — fails WCAG AA for text.`,
128
+ });
129
+ }
130
+ }
131
+ // 4. Off-scale spacing — values that break the detected base grid.
132
+ const scaleType = result.spacing?.scaleType ?? "";
133
+ const base = scaleType === "base-8" ? 8 : scaleType === "base-4" ? 4 : 0;
134
+ if (base) {
135
+ const off = (result.spacing?.commonValues ?? [])
136
+ .map((v) => v.px)
137
+ .filter((px) => typeof px === "number" && px >= base && px % base !== 0);
138
+ if (off.length) {
139
+ findings.push({
140
+ category: "consistency",
141
+ group: "Spacing",
142
+ severity: "warn",
143
+ message: `${off.slice(0, 5).map((p) => `${p}px`).join(", ")} ${off.length === 1 ? "is" : "are"} off the ${scaleType} spacing grid.`,
144
+ });
145
+ }
146
+ }
147
+ // Two scores, each derived from its own findings — never invented. Errors
148
+ // cost more than warnings. Consistency = type/spacing/duplication; Contrast =
149
+ // accessibility. Both are always computable, so the header is never one lone
150
+ // gauge.
151
+ const cost = (f) => (f.severity === "error" ? 12 : 6);
152
+ const sum = (cat) => Math.max(0, 100 - findings.filter(cat).reduce((n, f) => n + cost(f), 0));
153
+ const consistency = sum((f) => f.category !== "contrast");
154
+ const contrast = sum((f) => f.category === "contrast");
155
+ // Coverage: how complete the captured token set is.
156
+ const present = [
157
+ (result.colors?.palette?.length ?? 0) > 0,
158
+ (result.typography?.styles?.length ?? 0) > 0,
159
+ (result.spacing?.commonValues?.length ?? 0) > 0,
160
+ (result.borderRadius?.values?.length ?? 0) > 0,
161
+ (result.shadows?.length ?? 0) > 0,
162
+ (result.breakpoints?.length ?? 0) > 0,
163
+ ].filter(Boolean).length;
164
+ return { findings, consistency, contrast, coverage: { present, total: 6 } };
165
+ }
166
+ //# sourceMappingURL=findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.js","sourceRoot":"","sources":["../../lib/findings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * DTCG (W3C Design Tokens CG) format exporter
3
+ * Converts dembrandt extraction output to W3C DTCG format
4
+ * Spec: https://www.designtokens.org/TR/2025.10/format/
5
+ */
6
+ import type { BrandingResult } from '../types.js';
7
+ /**
8
+ * Main export function - converts dembrandt output to W3C Design Tokens format
9
+ */
10
+ export declare function toDtcgTokens(extractionResult: BrandingResult): Record<string, any>;
@@ -0,0 +1,416 @@
1
+ /**
2
+ * DTCG (W3C Design Tokens CG) format exporter
3
+ * Converts dembrandt extraction output to W3C DTCG format
4
+ * Spec: https://www.designtokens.org/TR/2025.10/format/
5
+ */
6
+ import { buildDembrandtProvenance, EXTENSION_KEY } from '../version.js';
7
+ /**
8
+ * Convert color value to DTCG color format
9
+ * Spec: https://www.designtokens.org/TR/2025.10/format/#color
10
+ *
11
+ * Based on spec examples (Example 7, 45, 54), color format includes:
12
+ * - colorSpace: "srgb"
13
+ * - components: [r, g, b] (normalized 0-1)
14
+ * - hex: "#rrggbb"
15
+ * - alpha: 0-1 (optional, for transparency)
16
+ */
17
+ function hexToDtcgColor(color, alpha = 1) {
18
+ let r, g, b;
19
+ // Handle rgba(r, g, b, a) format
20
+ if (typeof color === 'string' && color.includes('rgba')) {
21
+ const match = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
22
+ if (match) {
23
+ r = parseInt(match[1]) / 255;
24
+ g = parseInt(match[2]) / 255;
25
+ b = parseInt(match[3]) / 255;
26
+ alpha = match[4] ? parseFloat(match[4]) : 1;
27
+ const hexR = parseInt(match[1]).toString(16).padStart(2, '0');
28
+ const hexG = parseInt(match[2]).toString(16).padStart(2, '0');
29
+ const hexB = parseInt(match[3]).toString(16).padStart(2, '0');
30
+ const hexValue = `#${hexR}${hexG}${hexB}`;
31
+ const result = {
32
+ colorSpace: 'srgb',
33
+ components: [
34
+ Math.round(r * 1000) / 1000,
35
+ Math.round(g * 1000) / 1000,
36
+ Math.round(b * 1000) / 1000
37
+ ],
38
+ hex: hexValue
39
+ };
40
+ // Include alpha only if it's not 1 (fully opaque)
41
+ if (alpha !== 1) {
42
+ result.alpha = Math.round(alpha * 1000) / 1000;
43
+ }
44
+ return result;
45
+ }
46
+ }
47
+ // Handle rgb(r, g, b) format
48
+ if (typeof color === 'string' && color.includes('rgb')) {
49
+ const match = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
50
+ if (match) {
51
+ r = parseInt(match[1]) / 255;
52
+ g = parseInt(match[2]) / 255;
53
+ b = parseInt(match[3]) / 255;
54
+ const hexR = parseInt(match[1]).toString(16).padStart(2, '0');
55
+ const hexG = parseInt(match[2]).toString(16).padStart(2, '0');
56
+ const hexB = parseInt(match[3]).toString(16).padStart(2, '0');
57
+ const hexValue = `#${hexR}${hexG}${hexB}`;
58
+ return {
59
+ colorSpace: 'srgb',
60
+ components: [
61
+ Math.round(r * 1000) / 1000,
62
+ Math.round(g * 1000) / 1000,
63
+ Math.round(b * 1000) / 1000
64
+ ],
65
+ hex: hexValue
66
+ };
67
+ }
68
+ }
69
+ // Handle hex format
70
+ const cleanHex = color.replace('#', '');
71
+ // Ensure it's 6 characters
72
+ if (cleanHex.length !== 6) {
73
+ return {
74
+ colorSpace: 'srgb',
75
+ components: [0, 0, 0],
76
+ hex: '#000000'
77
+ };
78
+ }
79
+ // Parse RGB components
80
+ r = parseInt(cleanHex.substring(0, 2), 16) / 255;
81
+ g = parseInt(cleanHex.substring(2, 4), 16) / 255;
82
+ b = parseInt(cleanHex.substring(4, 6), 16) / 255;
83
+ const result = {
84
+ colorSpace: 'srgb',
85
+ components: [
86
+ Math.round(r * 1000) / 1000,
87
+ Math.round(g * 1000) / 1000,
88
+ Math.round(b * 1000) / 1000
89
+ ],
90
+ hex: `#${cleanHex}`
91
+ };
92
+ // Include alpha only if it's not 1 (fully opaque)
93
+ if (alpha !== 1) {
94
+ result.alpha = Math.round(alpha * 1000) / 1000;
95
+ }
96
+ return result;
97
+ }
98
+ /**
99
+ * Convert a dimension value to W3C DTCG dimension format.
100
+ *
101
+ * DTCG restricts dimensions to px or rem. We normalize what we can (em → rem,
102
+ * 1:1, the closest valid unit) and return null for anything inexpressible
103
+ * (%, vw, vh, unitless). Callers must skip the token/field on null rather than
104
+ * emit an invalid dimension. The value stays in the native output regardless.
105
+ *
106
+ * @param {string | number | { px?: number } | null | undefined} value
107
+ * @returns {{ value: number, unit: 'px' | 'rem' } | null}
108
+ */
109
+ function toDtcgDimension(value) {
110
+ let num;
111
+ let unit = 'px';
112
+ if (typeof value === 'string') {
113
+ // Ignore anything in parentheses, e.g. "16px (1.00rem)"
114
+ const cleanValue = value.split('(')[0].trim();
115
+ const match = cleanValue.match(/^([-\d.]+)\s*([a-z%]*)$/i);
116
+ if (!match)
117
+ return null;
118
+ num = parseFloat(match[1]);
119
+ unit = (match[2] || 'px').toLowerCase();
120
+ }
121
+ else if (typeof value === 'number') {
122
+ num = value;
123
+ }
124
+ else if (value && typeof value === 'object' && value.px !== undefined) {
125
+ num = value.px;
126
+ }
127
+ else {
128
+ num = parseFloat(value);
129
+ }
130
+ if (!Number.isFinite(num))
131
+ return null;
132
+ if (unit === 'em')
133
+ unit = 'rem'; // closest valid DTCG unit; 1em ≈ 1rem at root
134
+ if (unit !== 'px' && unit !== 'rem')
135
+ return null; // %, vw, vh, etc.: inexpressible
136
+ return { value: num, unit };
137
+ }
138
+ /**
139
+ * Sanitize token names to be W3C compliant
140
+ * - Cannot start with $
141
+ * - Cannot contain {, }, or .
142
+ */
143
+ function sanitizeTokenName(name) {
144
+ return name
145
+ .replace(/^\$/, '')
146
+ .replace(/[{}.]/g, '-')
147
+ .replace(/\s+/g, '-')
148
+ .toLowerCase();
149
+ }
150
+ /**
151
+ * Export colors to DTCG format
152
+ */
153
+ function exportColors(colors) {
154
+ if (!colors || !colors.palette || colors.palette.length === 0) {
155
+ return null;
156
+ }
157
+ const colorTokens = {};
158
+ // Add semantic colors if available
159
+ if (colors.semantic) {
160
+ const semantic = {};
161
+ for (const [key, value] of Object.entries(colors.semantic)) {
162
+ if (value) {
163
+ // Handle both direct color values and objects with color property
164
+ const colorValue = typeof value === 'string' ? value : value.color;
165
+ if (colorValue) {
166
+ semantic[sanitizeTokenName(key)] = {
167
+ $type: 'color',
168
+ $value: hexToDtcgColor(colorValue)
169
+ };
170
+ }
171
+ }
172
+ }
173
+ if (Object.keys(semantic).length > 0) {
174
+ colorTokens.semantic = semantic;
175
+ }
176
+ }
177
+ // Add palette colors (only high and medium confidence)
178
+ const palette = {};
179
+ colors.palette
180
+ .filter(colorEntry => colorEntry.confidence !== 'low')
181
+ .slice(0, 30) // Limit to top 30 colors
182
+ .forEach((colorEntry, index) => {
183
+ const name = `palette-${index + 1}`; // Use numbered names with prefix
184
+ palette[name] = {
185
+ $type: 'color',
186
+ $value: hexToDtcgColor(colorEntry.color),
187
+ $description: `Count: ${colorEntry.count || 0}, Confidence: ${colorEntry.confidence || 'unknown'}`
188
+ };
189
+ });
190
+ if (Object.keys(palette).length > 0) {
191
+ colorTokens.palette = palette;
192
+ }
193
+ return Object.keys(colorTokens).length > 0 ? colorTokens : null;
194
+ }
195
+ /**
196
+ * Export typography to DTCG format
197
+ */
198
+ function exportTypography(typography) {
199
+ if (!typography || !typography.styles || typography.styles.length === 0) {
200
+ return null;
201
+ }
202
+ const typographyTokens = {};
203
+ // Export font families
204
+ const uniqueFamilies = new Set();
205
+ typography.styles.forEach(style => {
206
+ if (style.family) {
207
+ uniqueFamilies.add(style.family);
208
+ }
209
+ });
210
+ if (uniqueFamilies.size > 0) {
211
+ const fontFamilies = {};
212
+ Array.from(uniqueFamilies).forEach((family, index) => {
213
+ const name = sanitizeTokenName(family) || `font-${index + 1}`;
214
+ fontFamilies[name] = {
215
+ $type: 'fontFamily',
216
+ $value: family
217
+ };
218
+ });
219
+ typographyTokens['font-family'] = fontFamilies;
220
+ }
221
+ // Export text styles as composite typography tokens
222
+ const textStyles = {};
223
+ typography.styles.slice(0, 10).forEach((style, index) => {
224
+ // fontFamily and fontSize identify the style; without them a DTCG typography
225
+ // token cannot be both valid and honest, so skip rather than fabricate.
226
+ if (!style.family || !style.size)
227
+ return;
228
+ // fontSize must be expressible as a px/rem dimension; skip the token if not
229
+ // (e.g. a "%" size) rather than emit an invalid one.
230
+ const fontSize = toDtcgDimension(style.size);
231
+ if (!fontSize)
232
+ return;
233
+ const name = style.context
234
+ ? `text-${sanitizeTokenName(style.context)}`
235
+ : `text-${index + 1}`;
236
+ const familyName = sanitizeTokenName(style.family) || `font-${index + 1}`;
237
+ // DTCG typography is a composite that requires all five sub-fields. weight,
238
+ // lineHeight and letterSpacing have legitimate CSS-normal defaults (400, 1.5,
239
+ // 0px), so fill them when the source did not capture one. That is the
240
+ // computed-normal value, not invented brand data.
241
+ // DTCG composite typography (§9.8): each sub-field is a RAW value of its
242
+ // type (or a reference), NOT a nested {$type,$value} token. fontFamily is a
243
+ // reference to the font-family token; the rest are raw dimension/number values.
244
+ textStyles[name] = {
245
+ $type: 'typography',
246
+ $value: {
247
+ fontFamily: `{typography.font-family.${familyName}}`,
248
+ fontSize,
249
+ fontWeight: typeof style.weight === 'number' ? style.weight : parseInt(style.weight) || 400,
250
+ lineHeight: style.lineHeight ? (parseFloat(style.lineHeight) || 1.5) : 1.5,
251
+ letterSpacing: (style.letterSpacing && toDtcgDimension(style.letterSpacing)) || { value: 0, unit: 'px' }
252
+ }
253
+ };
254
+ });
255
+ if (Object.keys(textStyles).length > 0) {
256
+ typographyTokens.style = textStyles;
257
+ }
258
+ return Object.keys(typographyTokens).length > 0 ? typographyTokens : null;
259
+ }
260
+ /**
261
+ * Export spacing to DTCG format
262
+ */
263
+ function exportSpacing(spacing) {
264
+ if (!spacing || !spacing.commonValues || spacing.commonValues.length === 0) {
265
+ return null;
266
+ }
267
+ const spacingTokens = {};
268
+ spacing.commonValues.slice(0, 12).forEach((value, index) => {
269
+ const dim = toDtcgDimension(value.px || value);
270
+ if (!dim)
271
+ return; // inexpressible unit (%, vw, …): omit from DTCG output
272
+ spacingTokens[`spacing-${index + 1}`] = { $type: 'dimension', $value: dim };
273
+ });
274
+ return Object.keys(spacingTokens).length > 0 ? spacingTokens : null;
275
+ }
276
+ /**
277
+ * Export border radius to W3C format
278
+ */
279
+ function exportBorderRadius(borderRadius) {
280
+ if (!borderRadius || !borderRadius.values || borderRadius.values.length === 0) {
281
+ return null;
282
+ }
283
+ const radiusTokens = {};
284
+ borderRadius.values
285
+ .filter(entry => entry.confidence !== 'low')
286
+ .slice(0, 6)
287
+ .forEach((entry, index) => {
288
+ const dim = toDtcgDimension(entry.value);
289
+ if (!dim)
290
+ return; // e.g. a "50%" pill radius: no valid px/rem form, omit
291
+ radiusTokens[`radius-${index + 1}`] = { $type: 'dimension', $value: dim };
292
+ });
293
+ return Object.keys(radiusTokens).length > 0 ? radiusTokens : null;
294
+ }
295
+ /**
296
+ * Export borders to DTCG format
297
+ */
298
+ function exportBorders(borders) {
299
+ if (!borders || !borders.combinations || borders.combinations.length === 0) {
300
+ return null;
301
+ }
302
+ const borderTokens = {};
303
+ const widths = {};
304
+ const colors = {};
305
+ const seenWidths = new Set();
306
+ const seenColors = new Set();
307
+ // Extract unique widths and colors from combinations
308
+ borders.combinations
309
+ .filter(combo => combo.confidence !== 'low')
310
+ .slice(0, 10)
311
+ .forEach((combo) => {
312
+ // Add width if not seen and expressible as px/rem
313
+ if (combo.width && !seenWidths.has(combo.width)) {
314
+ const dim = toDtcgDimension(combo.width);
315
+ if (dim) {
316
+ widths[`border-width-${seenWidths.size + 1}`] = { $type: 'dimension', $value: dim };
317
+ seenWidths.add(combo.width);
318
+ }
319
+ }
320
+ // Add color if not seen and valid
321
+ if (combo.color && !seenColors.has(combo.color)) {
322
+ const colorIndex = seenColors.size + 1;
323
+ colors[`border-color-${colorIndex}`] = {
324
+ $type: 'color',
325
+ $value: hexToDtcgColor(combo.color)
326
+ };
327
+ seenColors.add(combo.color);
328
+ }
329
+ });
330
+ if (Object.keys(widths).length > 0) {
331
+ borderTokens.width = widths;
332
+ }
333
+ if (Object.keys(colors).length > 0) {
334
+ borderTokens.color = colors;
335
+ }
336
+ return Object.keys(borderTokens).length > 0 ? borderTokens : null;
337
+ }
338
+ /**
339
+ * Export shadows to DTCG format
340
+ */
341
+ function exportShadows(shadows) {
342
+ if (!shadows || shadows.length === 0) {
343
+ return null;
344
+ }
345
+ const shadowTokens = {};
346
+ shadows
347
+ .filter(entry => entry.confidence !== 'low')
348
+ .slice(0, 6)
349
+ .forEach((entry, index) => {
350
+ const name = `shadow-${index + 1}`;
351
+ // Parse shadow string (simplified parsing)
352
+ // Format: offsetX offsetY blur spread color
353
+ const parts = entry.shadow.trim().split(/\s+/);
354
+ // Parse shadow (W3C format requires proper color object)
355
+ const shadowColor = parts[4] && parts[4].match(/^#[0-9a-fA-F]{6}$/)
356
+ ? parts[4]
357
+ : '#000000';
358
+ const zero = { value: 0, unit: 'px' };
359
+ const dim = (v) => toDtcgDimension(v) || zero;
360
+ shadowTokens[name] = {
361
+ $type: 'shadow',
362
+ $value: {
363
+ offsetX: dim(parts[0]),
364
+ offsetY: dim(parts[1]),
365
+ blur: dim(parts[2]),
366
+ spread: dim(parts[3]),
367
+ color: hexToDtcgColor(shadowColor)
368
+ }
369
+ };
370
+ });
371
+ return Object.keys(shadowTokens).length > 0 ? shadowTokens : null;
372
+ }
373
+ /**
374
+ * Main export function - converts dembrandt output to W3C Design Tokens format
375
+ */
376
+ export function toDtcgTokens(extractionResult) {
377
+ const w3cTokens = {};
378
+ // Document-level provenance + version contract. The DTCG $extensions mechanism
379
+ // is the only sanctioned channel for vendor data, and the spec requires other
380
+ // tools to preserve it across a round-trip. Single source of truth: version.js.
381
+ w3cTokens.$extensions = {
382
+ [EXTENSION_KEY]: buildDembrandtProvenance(extractionResult),
383
+ };
384
+ // Export colors
385
+ const colors = exportColors(extractionResult.colors);
386
+ if (colors) {
387
+ w3cTokens.color = colors;
388
+ }
389
+ // Export typography
390
+ const typography = exportTypography(extractionResult.typography);
391
+ if (typography) {
392
+ w3cTokens.typography = typography;
393
+ }
394
+ // Export spacing
395
+ const spacing = exportSpacing(extractionResult.spacing);
396
+ if (spacing) {
397
+ w3cTokens.spacing = spacing;
398
+ }
399
+ // Export border radius
400
+ const borderRadius = exportBorderRadius(extractionResult.borderRadius);
401
+ if (borderRadius) {
402
+ w3cTokens.radius = borderRadius;
403
+ }
404
+ // Export borders
405
+ const borders = exportBorders(extractionResult.borders);
406
+ if (borders) {
407
+ w3cTokens.border = borders;
408
+ }
409
+ // Export shadows
410
+ const shadows = exportShadows(extractionResult.shadows);
411
+ if (shadows) {
412
+ w3cTokens.shadow = shadows;
413
+ }
414
+ return w3cTokens;
415
+ }
416
+ //# sourceMappingURL=dtcg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dtcg.js","sourceRoot":"","sources":["../../../lib/formatters/dtcg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * HTML report formatter — a single self-contained HTML file (inline CSS, no
3
+ * external fetches) that renders an extraction and, optionally, a drift diff.
4
+ *
5
+ * This is the pre-platform bridge (DEM-94): a CI artifact you can open offline
6
+ * and attach to a PR, before the hosted dashboard exists. It is a *view* over
7
+ * the same deterministic data the platform will later diff server-side — it
8
+ * renders structured tokens and single-render contrast only, never re-derives
9
+ * drift from rendered CSS. Mode B reuses the canonical `computeDrift` engine.
10
+ *
11
+ * The summary header is Lighthouse-style: big score gauges, each backed by a
12
+ * concrete finding (lib/findings.ts) so no number is a vanity metric. The file
13
+ * is the rendered view only — the machine-readable form is `--json-only`.
14
+ */
15
+ import type { BrandingResult } from "../types.js";
16
+ import type { DriftReport } from "../drift.js";
17
+ export interface HtmlReportOptions {
18
+ /** When present, render a drift banner + changes at the top of the report. */
19
+ drift?: DriftReport;
20
+ /** Label for the baseline the drift was computed against (e.g. a filename). */
21
+ baselineLabel?: string;
22
+ /** CLI version, surfaced in the footer. */
23
+ version?: string;
24
+ }
25
+ export declare function generateHtmlReport(result: BrandingResult, options?: HtmlReportOptions): string;