@caelo-cms/shared 0.10.22 → 0.10.24

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 (249) hide show
  1. package/dist/ai-tools.d.ts +289 -273
  2. package/dist/ai-tools.d.ts.map +1 -1
  3. package/dist/ai-tools.js +342 -323
  4. package/dist/ai-tools.js.map +1 -1
  5. package/dist/auth-forms.d.ts.map +1 -1
  6. package/dist/auth-forms.js +4 -1
  7. package/dist/auth-forms.js.map +1 -1
  8. package/dist/base-css.d.ts +35 -0
  9. package/dist/base-css.d.ts.map +1 -0
  10. package/dist/base-css.js +40 -0
  11. package/dist/base-css.js.map +1 -0
  12. package/dist/build-page.d.ts +330 -0
  13. package/dist/build-page.d.ts.map +1 -0
  14. package/dist/build-page.js +282 -0
  15. package/dist/build-page.js.map +1 -0
  16. package/dist/content.d.ts +322 -9
  17. package/dist/content.d.ts.map +1 -1
  18. package/dist/content.js +354 -11
  19. package/dist/content.js.map +1 -1
  20. package/dist/css-gradient-scan.d.ts +14 -0
  21. package/dist/css-gradient-scan.d.ts.map +1 -0
  22. package/dist/css-gradient-scan.js +81 -0
  23. package/dist/css-gradient-scan.js.map +1 -0
  24. package/dist/css-var-scan.d.ts +56 -0
  25. package/dist/css-var-scan.d.ts.map +1 -0
  26. package/dist/css-var-scan.js +97 -0
  27. package/dist/css-var-scan.js.map +1 -0
  28. package/dist/design-draft-shell.d.ts +21 -0
  29. package/dist/design-draft-shell.d.ts.map +1 -0
  30. package/dist/design-draft-shell.js +81 -0
  31. package/dist/design-draft-shell.js.map +1 -0
  32. package/dist/design-manifest.d.ts +36 -0
  33. package/dist/design-manifest.d.ts.map +1 -0
  34. package/dist/design-manifest.js +90 -0
  35. package/dist/design-manifest.js.map +1 -0
  36. package/dist/fonts.d.ts +89 -0
  37. package/dist/fonts.d.ts.map +1 -0
  38. package/dist/fonts.js +241 -0
  39. package/dist/fonts.js.map +1 -0
  40. package/dist/genesis-inventory.d.ts +32 -0
  41. package/dist/genesis-inventory.d.ts.map +1 -0
  42. package/dist/genesis-inventory.js +186 -0
  43. package/dist/genesis-inventory.js.map +1 -0
  44. package/dist/genesis.d.ts +102 -0
  45. package/dist/genesis.d.ts.map +1 -0
  46. package/dist/genesis.js +145 -0
  47. package/dist/genesis.js.map +1 -0
  48. package/dist/i18n.d.ts +29 -36
  49. package/dist/i18n.d.ts.map +1 -1
  50. package/dist/i18n.js +53 -128
  51. package/dist/i18n.js.map +1 -1
  52. package/dist/index.d.ts +28 -1
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +28 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/interactions.d.ts +23 -0
  57. package/dist/interactions.d.ts.map +1 -0
  58. package/dist/interactions.js +44 -0
  59. package/dist/interactions.js.map +1 -0
  60. package/dist/media.d.ts +101 -16
  61. package/dist/media.d.ts.map +1 -1
  62. package/dist/media.js +126 -15
  63. package/dist/media.js.map +1 -1
  64. package/dist/page-log.d.ts +94 -0
  65. package/dist/page-log.d.ts.map +1 -0
  66. package/dist/page-log.js +111 -0
  67. package/dist/page-log.js.map +1 -0
  68. package/dist/preview-compose.d.ts +85 -12
  69. package/dist/preview-compose.d.ts.map +1 -1
  70. package/dist/preview-compose.js +157 -67
  71. package/dist/preview-compose.js.map +1 -1
  72. package/dist/proposal-status.d.ts +40 -0
  73. package/dist/proposal-status.d.ts.map +1 -0
  74. package/dist/proposal-status.js +34 -0
  75. package/dist/proposal-status.js.map +1 -0
  76. package/dist/responsive-images.d.ts +64 -0
  77. package/dist/responsive-images.d.ts.map +1 -0
  78. package/dist/responsive-images.js +98 -0
  79. package/dist/responsive-images.js.map +1 -0
  80. package/dist/safe-keys.d.ts +9 -0
  81. package/dist/safe-keys.d.ts.map +1 -0
  82. package/dist/safe-keys.js +20 -0
  83. package/dist/safe-keys.js.map +1 -0
  84. package/dist/seo.d.ts +11 -16
  85. package/dist/seo.d.ts.map +1 -1
  86. package/dist/seo.js +7 -23
  87. package/dist/seo.js.map +1 -1
  88. package/dist/skills.d.ts +14 -68
  89. package/dist/skills.d.ts.map +1 -1
  90. package/dist/skills.js +19 -113
  91. package/dist/skills.js.map +1 -1
  92. package/dist/strip-cdata.d.ts +7 -0
  93. package/dist/strip-cdata.d.ts.map +1 -0
  94. package/dist/strip-cdata.js +48 -0
  95. package/dist/strip-cdata.js.map +1 -0
  96. package/dist/structured-sets.d.ts +6 -52
  97. package/dist/structured-sets.d.ts.map +1 -1
  98. package/dist/structured-sets.js +6 -68
  99. package/dist/structured-sets.js.map +1 -1
  100. package/dist/subagents.d.ts +105 -3
  101. package/dist/subagents.d.ts.map +1 -1
  102. package/dist/subagents.js +224 -41
  103. package/dist/subagents.js.map +1 -1
  104. package/dist/template-engine.d.ts +85 -0
  105. package/dist/template-engine.d.ts.map +1 -0
  106. package/dist/template-engine.js +403 -0
  107. package/dist/template-engine.js.map +1 -0
  108. package/dist/theme-importers/auto-detect.d.ts +26 -0
  109. package/dist/theme-importers/auto-detect.d.ts.map +1 -0
  110. package/dist/theme-importers/auto-detect.js +42 -0
  111. package/dist/theme-importers/auto-detect.js.map +1 -0
  112. package/dist/theme-importers/css-comments.d.ts +12 -0
  113. package/dist/theme-importers/css-comments.d.ts.map +1 -0
  114. package/dist/theme-importers/css-comments.js +15 -0
  115. package/dist/theme-importers/css-comments.js.map +1 -0
  116. package/dist/theme-importers/dtcg.d.ts +46 -0
  117. package/dist/theme-importers/dtcg.d.ts.map +1 -0
  118. package/dist/theme-importers/dtcg.js +111 -0
  119. package/dist/theme-importers/dtcg.js.map +1 -0
  120. package/dist/theme-importers/loose.d.ts +3 -0
  121. package/dist/theme-importers/loose.d.ts.map +1 -0
  122. package/dist/theme-importers/loose.js +76 -0
  123. package/dist/theme-importers/loose.js.map +1 -0
  124. package/dist/theme-importers/shadcn.d.ts +24 -0
  125. package/dist/theme-importers/shadcn.d.ts.map +1 -0
  126. package/dist/theme-importers/shadcn.js +135 -0
  127. package/dist/theme-importers/shadcn.js.map +1 -0
  128. package/dist/theme-importers/style-dictionary.d.ts +17 -0
  129. package/dist/theme-importers/style-dictionary.d.ts.map +1 -0
  130. package/dist/theme-importers/style-dictionary.js +125 -0
  131. package/dist/theme-importers/style-dictionary.js.map +1 -0
  132. package/dist/theme-importers/tailwind.d.ts +3 -0
  133. package/dist/theme-importers/tailwind.d.ts.map +1 -0
  134. package/dist/theme-importers/tailwind.js +218 -0
  135. package/dist/theme-importers/tailwind.js.map +1 -0
  136. package/dist/theme-literal-binding.d.ts +37 -0
  137. package/dist/theme-literal-binding.d.ts.map +1 -0
  138. package/dist/theme-literal-binding.js +138 -0
  139. package/dist/theme-literal-binding.js.map +1 -0
  140. package/dist/theme-normalize.d.ts +31 -0
  141. package/dist/theme-normalize.d.ts.map +1 -0
  142. package/dist/theme-normalize.js +587 -0
  143. package/dist/theme-normalize.js.map +1 -0
  144. package/dist/theme-ramp.d.ts +55 -0
  145. package/dist/theme-ramp.d.ts.map +1 -0
  146. package/dist/theme-ramp.js +149 -0
  147. package/dist/theme-ramp.js.map +1 -0
  148. package/dist/theme-render.d.ts +105 -0
  149. package/dist/theme-render.d.ts.map +1 -0
  150. package/dist/theme-render.js +441 -0
  151. package/dist/theme-render.js.map +1 -0
  152. package/dist/themes-errors.d.ts +109 -0
  153. package/dist/themes-errors.d.ts.map +1 -0
  154. package/dist/themes-errors.js +170 -0
  155. package/dist/themes-errors.js.map +1 -0
  156. package/dist/themes.d.ts +343 -0
  157. package/dist/themes.d.ts.map +1 -0
  158. package/dist/themes.js +697 -0
  159. package/dist/themes.js.map +1 -0
  160. package/dist/version.d.ts +7 -4
  161. package/dist/version.d.ts.map +1 -1
  162. package/dist/version.js +6 -3
  163. package/dist/version.js.map +1 -1
  164. package/package.json +10 -2
  165. package/src/__tests__/redos-hardening.test.ts +160 -0
  166. package/src/ai-tools-add-module-modes.test.ts +106 -0
  167. package/src/ai-tools-position.test.ts +134 -0
  168. package/src/ai-tools.test.ts +81 -0
  169. package/src/ai-tools.ts +1105 -0
  170. package/src/auth-forms.ts +36 -0
  171. package/src/base-css.ts +42 -0
  172. package/src/build-page.test.ts +228 -0
  173. package/src/build-page.ts +319 -0
  174. package/src/cap-failures.ts +67 -0
  175. package/src/content.test.ts +170 -0
  176. package/src/content.ts +620 -0
  177. package/src/context.ts +43 -0
  178. package/src/css-gradient-scan.ts +88 -0
  179. package/src/css-var-scan.test.ts +96 -0
  180. package/src/css-var-scan.ts +144 -0
  181. package/src/derive-module-type.test.ts +80 -0
  182. package/src/design-draft-shell.test.ts +85 -0
  183. package/src/design-draft-shell.ts +109 -0
  184. package/src/design-manifest.ts +93 -0
  185. package/src/fonts.test.ts +157 -0
  186. package/src/fonts.ts +296 -0
  187. package/src/genesis-inventory.test.ts +86 -0
  188. package/src/genesis-inventory.ts +215 -0
  189. package/src/genesis-sanitize.test.ts +35 -0
  190. package/src/genesis.ts +158 -0
  191. package/src/i18n.test.ts +58 -0
  192. package/src/i18n.ts +91 -0
  193. package/src/index.test.ts +10 -0
  194. package/src/index.ts +59 -0
  195. package/src/interactions.ts +48 -0
  196. package/src/logger.ts +147 -0
  197. package/src/media.test.ts +160 -0
  198. package/src/media.ts +355 -0
  199. package/src/page-log.test.ts +163 -0
  200. package/src/page-log.ts +124 -0
  201. package/src/preview-compose.test.ts +637 -0
  202. package/src/preview-compose.ts +656 -0
  203. package/src/preview-scanner.test.ts +96 -0
  204. package/src/preview-scanner.ts +214 -0
  205. package/src/proposal-status.test.ts +69 -0
  206. package/src/proposal-status.ts +40 -0
  207. package/src/responsive-images.test.ts +104 -0
  208. package/src/responsive-images.ts +151 -0
  209. package/src/result.ts +29 -0
  210. package/src/safe-keys.ts +21 -0
  211. package/src/seo.test.ts +194 -0
  212. package/src/seo.ts +233 -0
  213. package/src/skills.ts +48 -0
  214. package/src/snapshots.test.ts +80 -0
  215. package/src/snapshots.ts +81 -0
  216. package/src/strip-cdata.test.ts +41 -0
  217. package/src/strip-cdata.ts +50 -0
  218. package/src/structured-sets.ts +114 -0
  219. package/src/subagents.test.ts +262 -0
  220. package/src/subagents.ts +432 -0
  221. package/src/template-engine.test.ts +379 -0
  222. package/src/template-engine.ts +520 -0
  223. package/src/theme-gradient.test.ts +92 -0
  224. package/src/theme-importers/__tests__/proto-pollution.test.ts +54 -0
  225. package/src/theme-importers/auto-detect.ts +84 -0
  226. package/src/theme-importers/css-comments.ts +15 -0
  227. package/src/theme-importers/dtcg.ts +106 -0
  228. package/src/theme-importers/loose.ts +76 -0
  229. package/src/theme-importers/shadcn.ts +133 -0
  230. package/src/theme-importers/style-dictionary.ts +125 -0
  231. package/src/theme-importers/tailwind.ts +217 -0
  232. package/src/theme-literal-binding.test.ts +71 -0
  233. package/src/theme-literal-binding.ts +159 -0
  234. package/src/theme-motion.test.ts +115 -0
  235. package/src/theme-normalize-envelope.test.ts +43 -0
  236. package/src/theme-normalize-gradient.test.ts +135 -0
  237. package/src/theme-normalize.ts +661 -0
  238. package/src/theme-ramp.ts +187 -0
  239. package/src/theme-render-sanitize.test.ts +45 -0
  240. package/src/theme-render.test.ts +119 -0
  241. package/src/theme-render.ts +487 -0
  242. package/src/theme-shadow.test.ts +56 -0
  243. package/src/themes-errors.ts +199 -0
  244. package/src/themes.ts +842 -0
  245. package/src/version.ts +66 -0
  246. package/dist/translation.d.ts +0 -127
  247. package/dist/translation.d.ts.map +0 -1
  248. package/dist/translation.js +0 -208
  249. package/dist/translation.js.map +0 -1
@@ -0,0 +1,218 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * v0.11.1 (issue #76) — Tailwind 4 `@theme { … }` block importer.
4
+ *
5
+ * Tailwind 4 defines theme tokens in a `@theme` (or `@theme inline`) at-rule:
6
+ *
7
+ * @theme {
8
+ * --color-primary: #ff6600;
9
+ * --spacing-md: 1rem;
10
+ * --font-sans: Inter, system-ui;
11
+ * }
12
+ *
13
+ * The importer extracts each `--<namespace>-<rest>: <value>;` line from
14
+ * the brace pair and maps it onto a DTCG path via the inverse of
15
+ * `theme-render.ts`'s namespace table (`color.<rest>`, `spacing.<rest>`,
16
+ * etc.). The result is validated by `validateThemeTokens`.
17
+ *
18
+ * Deliberately forgiving — handles `@theme inline`, single-line / block
19
+ * comments, blank lines. Hard-fails (TailwindImportError) on calc() /
20
+ * nested at-rules so the operator gets a concrete fix-it message
21
+ * instead of silently-truncated output.
22
+ */
23
+ import { isUnsafeKey } from "../safe-keys.js";
24
+ import { validateThemeTokens } from "../themes.js";
25
+ import { NotTailwindShape, TailwindImportError } from "../themes-errors.js";
26
+ import { stripCssComments } from "./css-comments.js";
27
+ export function importTailwind(body) {
28
+ const block = extractAtThemeBlock(body);
29
+ if (block === null) {
30
+ throw new NotTailwindShape();
31
+ }
32
+ const entries = parseCssVarBlock(block);
33
+ if (entries.length === 0) {
34
+ throw new NotTailwindShape("@theme block found but no `--name: value;` pairs inside");
35
+ }
36
+ const doc = mapEntriesToDtcg(entries);
37
+ return validateThemeTokens(doc);
38
+ }
39
+ /**
40
+ * Locate the body of the first `@theme` (or `@theme inline`) at-rule.
41
+ * Returns the contents inside the matching `{ … }` (no braces, no
42
+ * outer whitespace) or null when no block is present.
43
+ */
44
+ function extractAtThemeBlock(body) {
45
+ const stripped = stripCssComments(body);
46
+ const match = /@theme\s+(?:inline\s+)?\{/i.exec(stripped);
47
+ if (!match)
48
+ return null;
49
+ const start = match.index + match[0].length;
50
+ let depth = 1;
51
+ let i = start;
52
+ while (i < stripped.length && depth > 0) {
53
+ const ch = stripped[i];
54
+ if (ch === "{")
55
+ depth += 1;
56
+ else if (ch === "}")
57
+ depth -= 1;
58
+ if (depth === 0)
59
+ break;
60
+ i += 1;
61
+ }
62
+ if (depth !== 0)
63
+ return null;
64
+ return stripped.slice(start, i);
65
+ }
66
+ function parseCssVarBlock(block) {
67
+ const entries = [];
68
+ // Split on `;` so each entry is one declaration. Skip empty
69
+ // fragments and any line that doesn't start with `--`.
70
+ for (const raw of block.split(";")) {
71
+ const line = raw.trim();
72
+ if (line.length === 0)
73
+ continue;
74
+ if (line.startsWith("//"))
75
+ continue;
76
+ if (!line.startsWith("--")) {
77
+ // Catch nested at-rules; the importer doesn't handle them.
78
+ if (line.startsWith("@")) {
79
+ throw new TailwindImportError("nested @-rule", line);
80
+ }
81
+ // Tolerate plain identifiers (`color-scheme: dark` etc.) — skip silently.
82
+ continue;
83
+ }
84
+ const colonIdx = line.indexOf(":");
85
+ if (colonIdx <= 0)
86
+ continue;
87
+ const name = line.slice(0, colonIdx).trim();
88
+ const value = line.slice(colonIdx + 1).trim();
89
+ if (value.length === 0)
90
+ continue;
91
+ if (/\bcalc\s*\(/i.test(value)) {
92
+ throw new TailwindImportError("calc()", line);
93
+ }
94
+ if (/\bvar\s*\(/i.test(value)) {
95
+ throw new TailwindImportError("var()", line);
96
+ }
97
+ entries.push({ name, value });
98
+ }
99
+ return entries;
100
+ }
101
+ /**
102
+ * Map each `--<namespace>-<rest>` entry to a DTCG group. The namespace
103
+ * table mirrors theme-render.ts's emit table inverted.
104
+ */
105
+ function mapEntriesToDtcg(entries) {
106
+ const out = {};
107
+ for (const entry of entries) {
108
+ // Strip the leading `--` and split on the first hyphen.
109
+ const stripped = entry.name.slice(2);
110
+ const firstHyphen = stripped.indexOf("-");
111
+ if (firstHyphen <= 0)
112
+ continue; // no category prefix → skip
113
+ const ns = stripped.slice(0, firstHyphen);
114
+ const rest = stripped.slice(firstHyphen + 1);
115
+ let category;
116
+ let leafName;
117
+ let extraSubField = null;
118
+ switch (ns) {
119
+ case "color":
120
+ category = "color";
121
+ leafName = rest;
122
+ break;
123
+ case "spacing":
124
+ category = "spacing";
125
+ leafName = rest;
126
+ break;
127
+ case "radius":
128
+ category = "radius";
129
+ leafName = rest;
130
+ break;
131
+ case "shadow":
132
+ category = "shadow";
133
+ leafName = rest;
134
+ break;
135
+ case "breakpoint":
136
+ category = "breakpoint";
137
+ leafName = rest;
138
+ break;
139
+ case "duration":
140
+ category = "duration";
141
+ leafName = rest;
142
+ break;
143
+ case "ease":
144
+ category = "ease";
145
+ leafName = rest;
146
+ break;
147
+ case "font":
148
+ // --font-sans → typography.sans.fontFamily
149
+ category = "typography";
150
+ leafName = rest;
151
+ extraSubField = "fontFamily";
152
+ break;
153
+ case "text":
154
+ // --text-base → typography.base.fontSize
155
+ category = "typography";
156
+ leafName = rest;
157
+ extraSubField = "fontSize";
158
+ break;
159
+ default:
160
+ // Unknown namespace — bucket under its own root so the renderer
161
+ // still emits the var (forward-compat).
162
+ category = ns;
163
+ leafName = rest;
164
+ }
165
+ // `category` and `leafName` are derived from the imported CSS variable
166
+ // name, so a hostile token like `--__proto__-x` could otherwise pollute
167
+ // the prototype chain via `out[category]` / `group[leafName]` (CodeQL
168
+ // js/prototype-polluting-assignment). Skip the entry on any unsafe key.
169
+ if (isUnsafeKey(category) || isUnsafeKey(leafName))
170
+ continue;
171
+ if (!out[category])
172
+ out[category] = {};
173
+ const group = out[category] ?? {};
174
+ if (extraSubField !== null) {
175
+ // Typography composite: merge into the existing leaf's $value.
176
+ const existing = group[leafName];
177
+ const baseObj = existing && typeof existing === "object" && "$value" in existing
178
+ ? existing.$value
179
+ : {};
180
+ group[leafName] = {
181
+ $value: { ...baseObj, [extraSubField]: entry.value },
182
+ $type: "typography",
183
+ };
184
+ }
185
+ else {
186
+ // v0.11.1 (issue #76 Copilot review #4): if `leafName` looks like
187
+ // a Tailwind ramp suffix (`primary-50` … `primary-900`,
188
+ // `primary-DEFAULT`), nest it as `<group>.<stop>` so the result
189
+ // matches the OKLCh ramp's DTCG group shape. Without this,
190
+ // `--color-primary-50` would land at the flat key `color['primary-50']`
191
+ // and downstream ramp-aware logic (DEFAULT-alias resolver, the
192
+ // ColorEditor's color.primary swatch, the propose-create explicit-
193
+ // stop override path) wouldn't see the stops as a group.
194
+ const rampMatch = /^(.+)-(50|100|200|300|400|500|600|700|800|900|DEFAULT)$/.exec(leafName);
195
+ const tokenLeaf = {
196
+ $value: entry.value,
197
+ $type: category === "color" ? "color" : category === "duration" ? "duration" : "dimension",
198
+ };
199
+ if (rampMatch && category === "color") {
200
+ const [, baseName, stop] = rampMatch;
201
+ // `baseName` is the ramp prefix parsed from the token name; guard it
202
+ // before it becomes a `group[baseName]` assignment target. `stop` is
203
+ // a fixed enum (50…900|DEFAULT), so it needs no guard.
204
+ if (isUnsafeKey(baseName))
205
+ continue;
206
+ if (!group[baseName] || typeof group[baseName] !== "object") {
207
+ group[baseName] = {};
208
+ }
209
+ group[baseName][stop] = tokenLeaf;
210
+ }
211
+ else {
212
+ group[leafName] = tokenLeaf;
213
+ }
214
+ }
215
+ }
216
+ return out;
217
+ }
218
+ //# sourceMappingURL=tailwind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tailwind.js","sourceRoot":"","sources":["../../src/theme-importers/tailwind.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { ThemeDocument } from "./themes.js";
2
+ export interface ThemeValueMap {
3
+ /** normalized color value → var name (first-declared wins). */
4
+ readonly colors: ReadonlyMap<string, string>;
5
+ /** exact gradient string (normalized whitespace) → var name. */
6
+ readonly gradients: ReadonlyMap<string, string>;
7
+ /** dimension value → var name (suggestion-only tier). */
8
+ readonly dimensions: ReadonlyMap<string, string>;
9
+ }
10
+ /**
11
+ * Parse the light-branch declarations the renderer emits for this
12
+ * document into value → var-name maps.
13
+ */
14
+ export declare function buildThemeValueMap(tokens: ThemeDocument): ThemeValueMap;
15
+ export interface LiteralBindingResult {
16
+ readonly css: string;
17
+ /** Applied rewrites: literal → var name, with occurrence counts. */
18
+ readonly rewrites: readonly {
19
+ from: string;
20
+ to: string;
21
+ count: number;
22
+ }[];
23
+ /** Dimension matches left in place (too ambiguous to auto-rewrite). */
24
+ readonly suggestions: readonly {
25
+ literal: string;
26
+ varName: string;
27
+ }[];
28
+ }
29
+ /**
30
+ * Rewrite color/gradient literals that equal theme token values to
31
+ * `var(--name)`. Longest-first (gradients before their stop colors) so
32
+ * a gradient binds as a whole instead of stop-by-stop.
33
+ */
34
+ export declare function applyThemeLiteralBinding(css: string, tokens: ThemeDocument): LiteralBindingResult;
35
+ /** Tool-result suffix describing what binding did. Null on no-op. */
36
+ export declare function formatBindingReport(result: LiteralBindingResult): string | null;
37
+ //# sourceMappingURL=theme-literal-binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-literal-binding.d.ts","sourceRoot":"","sources":["../src/theme-literal-binding.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKjD,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,gEAAgE;IAChE,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,yDAAyD;IACzD,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClD;AASD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CA8BvE;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1E,uEAAuE;IACvE,QAAQ,CAAC,WAAW,EAAE,SAAS;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,oBAAoB,CA2CjG;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,GAAG,IAAI,CAkB/E"}
@@ -0,0 +1,138 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * issue #164 slice 2 — mechanical token binding ("AI decides, code
4
+ * executes"). During Genesis materialisation the theme is created FROM
5
+ * the draft's palette, so module CSS copied from the draft contains
6
+ * literals that EQUAL theme token values. Hand-translating them to
7
+ * `var(--…)` is transcription work the model can get subtly wrong;
8
+ * this module does it mechanically:
9
+ *
10
+ * - colors + gradients whose literal value equals an emitted token's
11
+ * value are rewritten to `var(--name)` (unambiguous: the value IS
12
+ * the token's value);
13
+ * - dimension-ish matches (a `6rem` that equals `--spacing-2xl`) are
14
+ * reported as SUGGESTIONS only — generic lengths are too ambiguous
15
+ * to rewrite silently.
16
+ *
17
+ * The value map is parsed from `renderThemeCss` output so binding uses
18
+ * exactly what the renderer emits (aliases resolved, ramps included) —
19
+ * no second resolution path to drift.
20
+ */
21
+ import { replaceCssGradients } from "./css-gradient-scan.js";
22
+ import { renderThemeCss } from "./theme-render.js";
23
+ const COLOR_LITERAL_RE = /#[0-9a-fA-F]{3,8}\b|(?:oklch|rgba?|hsla?|lab|lch|hwb)\([^()]*\)/g;
24
+ const DIMENSION_VALUE_RE = /^-?\d+(\.\d+)?(rem|em|px|%)$/;
25
+ function normalizeColor(v) {
26
+ return v.trim().toLowerCase();
27
+ }
28
+ function normalizeGradient(v) {
29
+ return v.trim().toLowerCase().replace(/\s+/g, " ");
30
+ }
31
+ /**
32
+ * Parse the light-branch declarations the renderer emits for this
33
+ * document into value → var-name maps.
34
+ */
35
+ export function buildThemeValueMap(tokens) {
36
+ const css = renderThemeCss(tokens);
37
+ // Only the light branch: `.dark` overrides carry the same names.
38
+ const lightEnd = css.indexOf(".dark{");
39
+ const light = lightEnd === -1 ? css : css.slice(0, lightEnd);
40
+ const colors = new Map();
41
+ const gradients = new Map();
42
+ const dimensions = new Map();
43
+ // Regex-free declaration split (a `(--name):(value);` regex is the
44
+ // #113 polynomial shape on adversarial dash runs). The light block
45
+ // is `:root{--a:v;--b:v;}` — split on `;`, take name:value pairs.
46
+ for (const rawSeg of light.split(";")) {
47
+ const seg = rawSeg.slice(rawSeg.lastIndexOf("{") + 1);
48
+ const colon = seg.indexOf(":");
49
+ if (colon <= 0)
50
+ continue;
51
+ const name = seg.slice(0, colon).trim();
52
+ const value = seg.slice(colon + 1).trim();
53
+ if (!name.startsWith("--") || value.length === 0)
54
+ continue;
55
+ if (name.startsWith("--gradient-")) {
56
+ const key = normalizeGradient(value);
57
+ if (!gradients.has(key))
58
+ gradients.set(key, name);
59
+ }
60
+ else if (name.startsWith("--color-")) {
61
+ const key = normalizeColor(value);
62
+ if (!colors.has(key))
63
+ colors.set(key, name);
64
+ }
65
+ else if (DIMENSION_VALUE_RE.test(value)) {
66
+ if (!dimensions.has(value))
67
+ dimensions.set(value, name);
68
+ }
69
+ }
70
+ return { colors, gradients, dimensions };
71
+ }
72
+ /**
73
+ * Rewrite color/gradient literals that equal theme token values to
74
+ * `var(--name)`. Longest-first (gradients before their stop colors) so
75
+ * a gradient binds as a whole instead of stop-by-stop.
76
+ */
77
+ export function applyThemeLiteralBinding(css, tokens) {
78
+ const map = buildThemeValueMap(tokens);
79
+ const counts = new Map();
80
+ let out = css;
81
+ out = replaceCssGradients(out, (literal) => {
82
+ const varName = map.gradients.get(normalizeGradient(literal));
83
+ if (varName === undefined)
84
+ return literal;
85
+ const entry = counts.get(literal) ?? { to: varName, count: 0 };
86
+ entry.count += 1;
87
+ counts.set(literal, entry);
88
+ return `var(${varName})`;
89
+ });
90
+ out = out.replace(COLOR_LITERAL_RE, (literal, offset) => {
91
+ // Never rewrite inside an already-produced var(...) fallback or a
92
+ // remaining gradient (a gradient that did NOT match stays literal
93
+ // by decision — rebinding its stops would half-tokenise it).
94
+ const before = out.slice(Math.max(0, offset - 64), offset);
95
+ if (/gradient\([^()]*$/i.test(before))
96
+ return literal;
97
+ const varName = map.colors.get(normalizeColor(literal));
98
+ if (varName === undefined)
99
+ return literal;
100
+ const entry = counts.get(literal) ?? { to: varName, count: 0 };
101
+ entry.count += 1;
102
+ counts.set(literal, entry);
103
+ return `var(${varName})`;
104
+ });
105
+ const suggestions = [];
106
+ const seen = new Set();
107
+ for (const m of out.matchAll(/-?\d+(?:\.\d+)?(?:rem|em|px|%)\b/g)) {
108
+ const literal = m[0];
109
+ if (seen.has(literal))
110
+ continue;
111
+ seen.add(literal);
112
+ const varName = map.dimensions.get(literal);
113
+ if (varName !== undefined)
114
+ suggestions.push({ literal, varName });
115
+ }
116
+ return {
117
+ css: out,
118
+ rewrites: [...counts.entries()].map(([from, e]) => ({ from, to: e.to, count: e.count })),
119
+ suggestions,
120
+ };
121
+ }
122
+ /** Tool-result suffix describing what binding did. Null on no-op. */
123
+ export function formatBindingReport(result) {
124
+ const parts = [];
125
+ if (result.rewrites.length > 0) {
126
+ const total = result.rewrites.reduce((n, r) => n + r.count, 0);
127
+ parts.push(`🔗 bound ${total} literal(s) to theme vars: ${result.rewrites
128
+ .map((r) => `${r.from}→var(${r.to})${r.count > 1 ? `×${r.count}` : ""}`)
129
+ .join(", ")}`);
130
+ }
131
+ if (result.suggestions.length > 0) {
132
+ parts.push(`consider tokens for: ${result.suggestions
133
+ .map((s) => `${s.literal}≈var(${s.varName})`)
134
+ .join(", ")} (dimensions are never auto-rewritten)`);
135
+ }
136
+ return parts.length > 0 ? ` ${parts.join(". ")}.` : null;
137
+ }
138
+ //# sourceMappingURL=theme-literal-binding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-literal-binding.js","sourceRoot":"","sources":["../src/theme-literal-binding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export type CanonicalPath = string;
2
+ export interface NormalizeResult {
3
+ /**
4
+ * Map from canonical DTCG path (e.g. "color.primary") to the value
5
+ * the caller supplied. The ops layer rebuilds the DTCG leaf
6
+ * (`{$value: <value>, $type: <inferred>}`) from this.
7
+ */
8
+ readonly set: Record<CanonicalPath, unknown>;
9
+ /**
10
+ * Inferred `$type` per canonical path. The renderer also knows the
11
+ * category from the path prefix, but the ops layer uses this to set
12
+ * `$type` on the stored token.
13
+ */
14
+ readonly types: Record<CanonicalPath, "color" | "dimension" | "typography" | "shadow" | "duration" | "cubicBezier" | "gradient">;
15
+ /** Echo-back list for the AI tool's result content. */
16
+ readonly canonicalPaths: readonly CanonicalPath[];
17
+ }
18
+ /**
19
+ * Normalize a record of loose-name → value pairs into canonical DTCG
20
+ * paths. Throws `UnknownTokenName` on the first ambiguous entry so the
21
+ * AI gets a single concrete next-step rather than a wall of partial
22
+ * results.
23
+ */
24
+ export declare function normalizeTokens(input: Record<string, unknown>): NormalizeResult;
25
+ /**
26
+ * Closest-match suggestions for an unknown input. Cheap edit-distance
27
+ * over the canonical-paths set — good enough that the AI gets a useful
28
+ * "did you mean X?" without pulling a fuzzy-search dep.
29
+ */
30
+ export declare function didYouMean(input: string): readonly string[];
31
+ //# sourceMappingURL=theme-normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-normalize.d.ts","sourceRoot":"","sources":["../src/theme-normalize.ts"],"names":[],"mappings":"AAgCA,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AAEnC,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CACpB,aAAa,EACb,OAAO,GAAG,WAAW,GAAG,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAC1F,CAAC;IACF,uDAAuD;IACvD,QAAQ,CAAC,cAAc,EAAE,SAAS,aAAa,EAAE,CAAC;CACnD;AA+JD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,CA8D/E;AAoWD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAO3D"}