@fragments-sdk/cli 0.15.10 → 0.16.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 (78) hide show
  1. package/dist/bin.js +896 -787
  2. package/dist/bin.js.map +1 -1
  3. package/dist/{chunk-6SQPP47U.js → chunk-77AAP6R6.js} +532 -31
  4. package/dist/chunk-77AAP6R6.js.map +1 -0
  5. package/dist/{chunk-5JF26E55.js → chunk-ACFVKMVZ.js} +11 -11
  6. package/dist/{chunk-BJE3425I.js → chunk-ACX7YWZW.js} +2 -2
  7. package/dist/{chunk-ONUP6Z4W.js → chunk-G6UVWMFU.js} +8 -8
  8. package/dist/{chunk-2WXKALIG.js → chunk-OZZ4SVZX.js} +2 -2
  9. package/dist/{chunk-32LIWN2P.js → chunk-SJFSG7QF.js} +582 -261
  10. package/dist/chunk-SJFSG7QF.js.map +1 -0
  11. package/dist/{chunk-HQ6A6DTV.js → chunk-XRADMHMV.js} +315 -1089
  12. package/dist/chunk-XRADMHMV.js.map +1 -0
  13. package/dist/core/index.js +53 -1
  14. package/dist/{create-EXURTBKK.js → create-3ZFYQB3T.js} +2 -2
  15. package/dist/{doctor-BDPMYYE6.js → doctor-4IDUM7HI.js} +2 -2
  16. package/dist/{generate-PVOLUAAC.js → generate-VNUUWVWQ.js} +4 -4
  17. package/dist/{govern-scan-DW4QUAYD.js → govern-scan-HTACKYPF.js} +158 -120
  18. package/dist/govern-scan-HTACKYPF.js.map +1 -0
  19. package/dist/index.js +6 -7
  20. package/dist/index.js.map +1 -1
  21. package/dist/{init-SSGUSP7Z.js → init-PXFRAQ64.js} +5 -5
  22. package/dist/mcp-bin.js +2 -2
  23. package/dist/{scan-PKSYSTRR.js → scan-L4GWGEZX.js} +5 -6
  24. package/dist/{scan-generate-VY27PIOX.js → scan-generate-74EYSAGH.js} +4 -4
  25. package/dist/{service-QJGWUIVL.js → service-VELQHEWV.js} +12 -14
  26. package/dist/{snapshot-WIJMEIFT.js → snapshot-DT4B6DPR.js} +2 -2
  27. package/dist/{static-viewer-7QIBQZRC.js → static-viewer-E4OJWFDJ.js} +3 -3
  28. package/dist/{test-64Z5BKBA.js → test-QJY2QO4X.js} +3 -3
  29. package/dist/{token-normalizer-TEPOVBPV.js → token-normalizer-56H4242J.js} +2 -2
  30. package/dist/{tokens-NZWFQIAB.js → tokens-K6URXFPK.js} +7 -8
  31. package/dist/{tokens-NZWFQIAB.js.map → tokens-K6URXFPK.js.map} +1 -1
  32. package/dist/{tokens-generate-5JQSJ27E.js → tokens-generate-EL6IN536.js} +2 -2
  33. package/package.json +7 -6
  34. package/src/bin.ts +49 -88
  35. package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.contract.json +1 -1
  36. package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.contract.json +1 -1
  37. package/src/commands/__tests__/context-cloud.test.ts +291 -0
  38. package/src/commands/__tests__/govern-scan.test.ts +185 -0
  39. package/src/commands/__tests__/govern.test.ts +1 -0
  40. package/src/commands/context-cloud.ts +355 -0
  41. package/src/commands/govern-scan-report.ts +170 -0
  42. package/src/commands/govern-scan.ts +42 -147
  43. package/src/commands/govern.ts +0 -157
  44. package/dist/chunk-32LIWN2P.js.map +0 -1
  45. package/dist/chunk-6SQPP47U.js.map +0 -1
  46. package/dist/chunk-HQ6A6DTV.js.map +0 -1
  47. package/dist/chunk-MHIBEEW4.js +0 -511
  48. package/dist/chunk-MHIBEEW4.js.map +0 -1
  49. package/dist/govern-scan-DW4QUAYD.js.map +0 -1
  50. package/dist/init-cloud-3DNKPWFB.js +0 -304
  51. package/dist/init-cloud-3DNKPWFB.js.map +0 -1
  52. package/dist/node-37AUE74M.js +0 -65
  53. package/dist/push-contracts-WY32TFP6.js +0 -84
  54. package/dist/push-contracts-WY32TFP6.js.map +0 -1
  55. package/dist/static-viewer-7QIBQZRC.js.map +0 -1
  56. package/dist/token-parser-32KOIOFN.js +0 -22
  57. package/dist/token-parser-32KOIOFN.js.map +0 -1
  58. package/dist/tokens-push-HY3KO36V.js +0 -148
  59. package/dist/tokens-push-HY3KO36V.js.map +0 -1
  60. package/src/commands/init-cloud.ts +0 -382
  61. package/src/commands/push-contracts.ts +0 -112
  62. package/src/commands/tokens-push.ts +0 -199
  63. /package/dist/{chunk-5JF26E55.js.map → chunk-ACFVKMVZ.js.map} +0 -0
  64. /package/dist/{chunk-BJE3425I.js.map → chunk-ACX7YWZW.js.map} +0 -0
  65. /package/dist/{chunk-ONUP6Z4W.js.map → chunk-G6UVWMFU.js.map} +0 -0
  66. /package/dist/{chunk-2WXKALIG.js.map → chunk-OZZ4SVZX.js.map} +0 -0
  67. /package/dist/{create-EXURTBKK.js.map → create-3ZFYQB3T.js.map} +0 -0
  68. /package/dist/{doctor-BDPMYYE6.js.map → doctor-4IDUM7HI.js.map} +0 -0
  69. /package/dist/{generate-PVOLUAAC.js.map → generate-VNUUWVWQ.js.map} +0 -0
  70. /package/dist/{init-SSGUSP7Z.js.map → init-PXFRAQ64.js.map} +0 -0
  71. /package/dist/{node-37AUE74M.js.map → scan-L4GWGEZX.js.map} +0 -0
  72. /package/dist/{scan-generate-VY27PIOX.js.map → scan-generate-74EYSAGH.js.map} +0 -0
  73. /package/dist/{scan-PKSYSTRR.js.map → service-VELQHEWV.js.map} +0 -0
  74. /package/dist/{snapshot-WIJMEIFT.js.map → snapshot-DT4B6DPR.js.map} +0 -0
  75. /package/dist/{service-QJGWUIVL.js.map → static-viewer-E4OJWFDJ.js.map} +0 -0
  76. /package/dist/{test-64Z5BKBA.js.map → test-QJY2QO4X.js.map} +0 -0
  77. /package/dist/{token-normalizer-TEPOVBPV.js.map → token-normalizer-56H4242J.js.map} +0 -0
  78. /package/dist/{tokens-generate-5JQSJ27E.js.map → tokens-generate-EL6IN536.js.map} +0 -0
@@ -1,511 +0,0 @@
1
- import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
-
3
- // src/service/token-parser.ts
4
- import { readFile } from "fs/promises";
5
- import { readFileSync } from "fs";
6
- import { relative } from "path";
7
- import fastGlob from "fast-glob";
8
-
9
- // src/service/tailwind-v4-parser.ts
10
- var CATEGORY_PATTERNS = [
11
- { pattern: /color|bg|background|border-color|fill|stroke/i, category: "color" },
12
- { pattern: /spacing|margin|padding|gap|space|inset/i, category: "spacing" },
13
- { pattern: /font|text|line-height|letter-spacing|typography/i, category: "typography" },
14
- { pattern: /radius|rounded|corner/i, category: "radius" },
15
- { pattern: /shadow|elevation/i, category: "shadow" },
16
- { pattern: /size|width|height|min|max/i, category: "sizing" },
17
- { pattern: /border(?!-color)|stroke-width|outline/i, category: "border" },
18
- { pattern: /animation|transition|duration|timing|delay/i, category: "animation" },
19
- { pattern: /z-index|layer|stack/i, category: "z-index" }
20
- ];
21
- function inferCategory(name) {
22
- const lowerName = name.toLowerCase();
23
- for (const { pattern, category } of CATEGORY_PATTERNS) {
24
- if (pattern.test(lowerName)) {
25
- return category;
26
- }
27
- }
28
- return "other";
29
- }
30
- function inferLevel(rawValue) {
31
- if (/var\(/.test(rawValue)) {
32
- return 2;
33
- }
34
- return 1;
35
- }
36
- function stripBlockComments(css) {
37
- return css.replace(/\/\*[\s\S]*?\*\//g, "");
38
- }
39
- var CUSTOM_PROPERTY_PATTERN = /^\s*(--[\w-]+)\s*:\s*(.+?)\s*;?\s*$/;
40
- function parseTailwindV4Theme(cssContent, filePath) {
41
- const startTime = performance.now();
42
- const tokens = [];
43
- const errors = [];
44
- const warnings = [];
45
- const source = filePath ?? "unknown";
46
- const cleaned = stripBlockComments(cssContent);
47
- const lines = cleaned.split("\n");
48
- let insideTheme = false;
49
- let themeDepth = 0;
50
- let pendingTheme = false;
51
- for (let i = 0; i < lines.length; i++) {
52
- let line = lines[i];
53
- const lineNumber = i + 1;
54
- const singleCommentIdx = line.indexOf("//");
55
- if (singleCommentIdx !== -1) {
56
- const beforeComment = line.slice(0, singleCommentIdx);
57
- const singleQuotes = (beforeComment.match(/'/g) || []).length;
58
- const doubleQuotes = (beforeComment.match(/"/g) || []).length;
59
- if (singleQuotes % 2 === 0 && doubleQuotes % 2 === 0) {
60
- line = beforeComment;
61
- }
62
- }
63
- const trimmed = line.trim();
64
- if (trimmed === "") {
65
- continue;
66
- }
67
- if (!insideTheme && !pendingTheme) {
68
- if (/^@theme\b/.test(trimmed)) {
69
- pendingTheme = true;
70
- const braceIdx = trimmed.indexOf("{");
71
- if (braceIdx !== -1) {
72
- pendingTheme = false;
73
- insideTheme = true;
74
- themeDepth = 1;
75
- const afterBrace = trimmed.slice(braceIdx + 1);
76
- for (const ch of afterBrace) {
77
- if (ch === "{") themeDepth++;
78
- else if (ch === "}") themeDepth--;
79
- }
80
- const inlineContent = afterBrace.trim();
81
- if (inlineContent && themeDepth > 0) {
82
- processThemeLine(inlineContent, lineNumber, source, tokens, warnings);
83
- }
84
- if (themeDepth <= 0) {
85
- insideTheme = false;
86
- }
87
- }
88
- continue;
89
- }
90
- }
91
- if (pendingTheme) {
92
- const braceIdx = trimmed.indexOf("{");
93
- if (braceIdx !== -1) {
94
- pendingTheme = false;
95
- insideTheme = true;
96
- themeDepth = 1;
97
- const afterBrace = trimmed.slice(braceIdx + 1);
98
- for (const ch of afterBrace) {
99
- if (ch === "{") themeDepth++;
100
- else if (ch === "}") themeDepth--;
101
- }
102
- const inlineContent = afterBrace.trim();
103
- if (inlineContent && themeDepth > 0) {
104
- processThemeLine(inlineContent, lineNumber, source, tokens, warnings);
105
- }
106
- if (themeDepth <= 0) {
107
- insideTheme = false;
108
- }
109
- }
110
- continue;
111
- }
112
- if (insideTheme) {
113
- for (const ch of trimmed) {
114
- if (ch === "{") {
115
- themeDepth++;
116
- } else if (ch === "}") {
117
- themeDepth--;
118
- if (themeDepth <= 0) {
119
- insideTheme = false;
120
- break;
121
- }
122
- }
123
- }
124
- if (insideTheme || themeDepth > 0) {
125
- const contentLine = trimmed.replace(/\}/g, "").trim();
126
- if (contentLine) {
127
- processThemeLine(contentLine, lineNumber, source, tokens, warnings);
128
- }
129
- }
130
- }
131
- }
132
- if (pendingTheme) {
133
- warnings.push(
134
- `@theme keyword found but no opening brace \u2014 incomplete block in ${source}`
135
- );
136
- }
137
- if (insideTheme) {
138
- warnings.push(
139
- `Unclosed @theme block \u2014 missing closing brace in ${source}`
140
- );
141
- }
142
- return {
143
- tokens,
144
- errors,
145
- warnings,
146
- parseTimeMs: performance.now() - startTime
147
- };
148
- }
149
- function processThemeLine(line, lineNumber, source, tokens, warnings) {
150
- const match = line.match(CUSTOM_PROPERTY_PATTERN);
151
- if (!match) {
152
- const partialMatch = line.match(/^\s*(--[\w-]+)\s*:\s*(.+?)\s*$/);
153
- if (partialMatch) {
154
- const [, name2, rawValue2] = partialMatch;
155
- tokens.push(buildToken(name2, rawValue2, lineNumber, source));
156
- return;
157
- }
158
- if (/^\s*--/.test(line)) {
159
- warnings.push(
160
- `Line ${lineNumber}: Could not parse custom property declaration: ${line.trim()}`
161
- );
162
- }
163
- return;
164
- }
165
- const [, name, rawValue] = match;
166
- tokens.push(buildToken(name, rawValue, lineNumber, source));
167
- }
168
- function buildToken(name, rawValue, lineNumber, source) {
169
- const value = rawValue.trim();
170
- return {
171
- name,
172
- rawValue: value,
173
- resolvedValue: value,
174
- category: inferCategory(name),
175
- level: inferLevel(value),
176
- referenceChain: [],
177
- sourceFile: source,
178
- lineNumber,
179
- theme: "default",
180
- selector: "@theme"
181
- };
182
- }
183
-
184
- // src/service/token-parser.ts
185
- var TOKEN_DECLARATION_PATTERN = /--([a-zA-Z0-9_-]+)\s*:\s*([^;]+);/g;
186
- var CATEGORY_PATTERNS2 = [
187
- { pattern: /color|bg|background|border-color|fill|stroke/i, category: "color" },
188
- { pattern: /spacing|margin|padding|gap|space|inset/i, category: "spacing" },
189
- { pattern: /font|text|line-height|letter-spacing|typography/i, category: "typography" },
190
- { pattern: /radius|rounded|corner/i, category: "radius" },
191
- { pattern: /shadow|elevation/i, category: "shadow" },
192
- { pattern: /size|width|height|min|max/i, category: "sizing" },
193
- { pattern: /border(?!-color)|stroke-width|outline/i, category: "border" },
194
- { pattern: /animation|transition|duration|timing|delay/i, category: "animation" },
195
- { pattern: /z-index|layer|stack/i, category: "z-index" }
196
- ];
197
- async function parseTokenFile(filePath, themeSelectors = { ":root": "default" }, projectRoot) {
198
- const startTime = performance.now();
199
- const tokens = [];
200
- const errors = [];
201
- const warnings = [];
202
- try {
203
- const content = await readFile(filePath, "utf-8");
204
- const relativePath = projectRoot ? relative(projectRoot, filePath) : filePath;
205
- if (containsTailwindV4Theme(content)) {
206
- const v4Result = parseTailwindV4Theme(content, relativePath);
207
- tokens.push(...v4Result.tokens);
208
- warnings.push(...v4Result.warnings);
209
- for (const err of v4Result.errors) {
210
- errors.push({ message: err, file: filePath });
211
- }
212
- }
213
- const tokensByName = /* @__PURE__ */ new Map();
214
- let lineNumber = 1;
215
- const lines = content.split("\n");
216
- let currentSelector = ":root";
217
- let braceDepth = 0;
218
- const selectorStack = [];
219
- for (let i = 0; i < lines.length; i++) {
220
- const line = lines[i];
221
- lineNumber = i + 1;
222
- const openBraces = (line.match(/\{/g) || []).length;
223
- const closeBraces = (line.match(/\}/g) || []).length;
224
- if (openBraces > closeBraces) {
225
- const selectorMatch = line.match(/^\s*([^{]+)\s*\{/);
226
- if (selectorMatch) {
227
- selectorStack.push(selectorMatch[1].trim());
228
- currentSelector = selectorStack[selectorStack.length - 1];
229
- }
230
- braceDepth += openBraces - closeBraces;
231
- } else if (closeBraces > openBraces) {
232
- braceDepth -= closeBraces - openBraces;
233
- if (braceDepth >= 0 && selectorStack.length > 0) {
234
- selectorStack.pop();
235
- currentSelector = selectorStack.length > 0 ? selectorStack[selectorStack.length - 1] : ":root";
236
- }
237
- }
238
- const tokenMatches = [...line.matchAll(TOKEN_DECLARATION_PATTERN)];
239
- for (const match of tokenMatches) {
240
- const [, name, rawValue] = match;
241
- const fullName = `--${name}`;
242
- tokensByName.set(fullName, { rawValue: rawValue.trim(), line: lineNumber });
243
- }
244
- }
245
- for (const [name, { rawValue, line }] of tokensByName) {
246
- const selector = findSelectorForLine(content, line || 1);
247
- const theme = themeSelectors[selector] || "default";
248
- const { resolvedValue, chain, hasCircular, unresolvedRef } = resolveValue(
249
- rawValue,
250
- tokensByName
251
- );
252
- if (hasCircular) {
253
- warnings.push(
254
- `Circular reference detected for ${name} at line ${line}`
255
- );
256
- }
257
- if (unresolvedRef) {
258
- warnings.push(
259
- `Unresolved reference in ${name}: ${unresolvedRef}`
260
- );
261
- }
262
- const category = inferCategory2(name);
263
- const level = inferLevel2(name, rawValue, chain);
264
- const description = extractDescription(content, line || 1);
265
- tokens.push({
266
- name,
267
- rawValue,
268
- resolvedValue,
269
- category,
270
- level,
271
- referenceChain: chain,
272
- sourceFile: relativePath,
273
- lineNumber: line,
274
- theme,
275
- selector,
276
- description
277
- });
278
- }
279
- } catch (error) {
280
- errors.push({
281
- message: error instanceof Error ? error.message : "Unknown error",
282
- file: filePath
283
- });
284
- }
285
- return {
286
- tokens,
287
- errors,
288
- warnings,
289
- parseTimeMs: performance.now() - startTime
290
- };
291
- }
292
- async function parseTokenFiles(config, projectRoot) {
293
- const startTime = performance.now();
294
- const allTokens = [];
295
- const allErrors = [];
296
- const allWarnings = [];
297
- const files = await fastGlob(config.include, {
298
- cwd: projectRoot,
299
- ignore: config.exclude || ["**/node_modules/**"],
300
- absolute: true
301
- });
302
- if (files.length === 0) {
303
- allWarnings.push(
304
- `No token files found matching: ${config.include.join(", ")}`
305
- );
306
- }
307
- for (const file of files) {
308
- const result = await parseTokenFile(
309
- file,
310
- config.themeSelectors,
311
- projectRoot
312
- );
313
- allTokens.push(...result.tokens);
314
- allErrors.push(...result.errors);
315
- allWarnings.push(...result.warnings);
316
- }
317
- return {
318
- tokens: allTokens,
319
- errors: allErrors,
320
- warnings: allWarnings,
321
- parseTimeMs: performance.now() - startTime
322
- };
323
- }
324
- function resolveValue(rawValue, tokensByName, visited = /* @__PURE__ */ new Set()) {
325
- const chain = [];
326
- let current = rawValue;
327
- let hasCircular = false;
328
- let unresolvedRef;
329
- const maxIterations = 20;
330
- let iterations = 0;
331
- while (iterations < maxIterations) {
332
- iterations++;
333
- const varMatch = current.match(/var\(\s*--([a-zA-Z0-9_-]+)(?:\s*,\s*([^)]+))?\s*\)/);
334
- if (!varMatch) {
335
- break;
336
- }
337
- const [, refName, fallback] = varMatch;
338
- const fullRefName = `--${refName}`;
339
- if (visited.has(fullRefName)) {
340
- hasCircular = true;
341
- break;
342
- }
343
- visited.add(fullRefName);
344
- chain.push(fullRefName);
345
- const refToken = tokensByName.get(fullRefName);
346
- if (refToken) {
347
- current = current.replace(
348
- varMatch[0],
349
- refToken.rawValue
350
- );
351
- } else if (fallback) {
352
- current = current.replace(varMatch[0], fallback.trim());
353
- } else {
354
- unresolvedRef = fullRefName;
355
- break;
356
- }
357
- }
358
- return {
359
- resolvedValue: normalizeValue(current.trim()),
360
- chain,
361
- hasCircular,
362
- unresolvedRef
363
- };
364
- }
365
- function normalizeValue(value) {
366
- value = value.replace(/#[0-9a-fA-F]+/g, (match) => match.toLowerCase());
367
- value = value.replace(/\s+/g, " ").trim();
368
- value = value.replace(
369
- /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/g,
370
- (_, r, g, b, a) => a !== void 0 ? `rgba(${r}, ${g}, ${b}, ${a})` : `rgb(${r}, ${g}, ${b})`
371
- );
372
- return value;
373
- }
374
- function inferCategory2(name) {
375
- const lowerName = name.toLowerCase();
376
- for (const { pattern, category } of CATEGORY_PATTERNS2) {
377
- if (pattern.test(lowerName)) {
378
- return category;
379
- }
380
- }
381
- return "other";
382
- }
383
- function inferLevel2(name, rawValue, referenceChain) {
384
- const lowerName = name.toLowerCase();
385
- if (/btn|button|input|card|modal|dialog|menu|nav|header|footer|table|form/i.test(
386
- lowerName
387
- )) {
388
- return 3;
389
- }
390
- if (referenceChain.length > 0) {
391
- return 2;
392
- }
393
- if (rawValue.match(/^#[0-9a-fA-F]+$/) || rawValue.match(/^\d+(\.\d+)?(px|rem|em|%|vh|vw)?$/)) {
394
- return 1;
395
- }
396
- return 2;
397
- }
398
- function findSelectorForLine(content, targetLine) {
399
- const lines = content.split("\n");
400
- let currentSelector = ":root";
401
- let braceDepth = 0;
402
- for (let i = 0; i < Math.min(targetLine, lines.length); i++) {
403
- const line = lines[i];
404
- const selectorMatch = line.match(/^\s*([^{]+)\s*\{/);
405
- if (selectorMatch) {
406
- const selector = selectorMatch[1].trim();
407
- if ((line.match(/\{/g) || []).length > (line.match(/\}/g) || []).length) {
408
- currentSelector = selector;
409
- }
410
- }
411
- braceDepth += (line.match(/\{/g) || []).length;
412
- braceDepth -= (line.match(/\}/g) || []).length;
413
- if (braceDepth === 0) {
414
- currentSelector = ":root";
415
- }
416
- }
417
- return currentSelector;
418
- }
419
- function extractDescription(content, line) {
420
- const lines = content.split("\n");
421
- if (line <= 1) return void 0;
422
- const prevLine = lines[line - 2]?.trim();
423
- const singleLineMatch = prevLine?.match(/\/\/\s*(.+)$/);
424
- if (singleLineMatch) {
425
- return singleLineMatch[1].trim();
426
- }
427
- const multiLineMatch = prevLine?.match(/\*\s*(.+)\s*\*\//);
428
- if (multiLineMatch) {
429
- return multiLineMatch[1].trim();
430
- }
431
- const inlineMatch = prevLine?.match(/\/\*\s*(.+)\s*\*\//);
432
- if (inlineMatch) {
433
- return inlineMatch[1].trim();
434
- }
435
- return void 0;
436
- }
437
- function hexToRgb(hex) {
438
- const match = hex.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);
439
- if (!match) return null;
440
- return {
441
- r: parseInt(match[1], 16),
442
- g: parseInt(match[2], 16),
443
- b: parseInt(match[3], 16)
444
- };
445
- }
446
- function rgbToHex(r, g, b) {
447
- return `#${[r, g, b].map((x) => Math.round(x).toString(16).padStart(2, "0")).join("")}`;
448
- }
449
- function parseRgb(color) {
450
- const match = color.match(
451
- /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/
452
- );
453
- if (!match) return null;
454
- return {
455
- r: parseInt(match[1], 10),
456
- g: parseInt(match[2], 10),
457
- b: parseInt(match[3], 10),
458
- a: match[4] ? parseFloat(match[4]) : void 0
459
- };
460
- }
461
- function normalizeColor(color) {
462
- if (color.startsWith("#")) {
463
- return color.toLowerCase();
464
- }
465
- const rgb = parseRgb(color);
466
- if (rgb) {
467
- return rgbToHex(rgb.r, rgb.g, rgb.b);
468
- }
469
- return color.toLowerCase();
470
- }
471
- function parseTailwindV4File(filePath) {
472
- const startTime = performance.now();
473
- try {
474
- const content = readFileSync(filePath, "utf-8");
475
- const result = parseTailwindV4Theme(content, filePath);
476
- return {
477
- tokens: result.tokens,
478
- errors: result.errors.map((message) => ({ message, file: filePath })),
479
- warnings: result.warnings,
480
- parseTimeMs: result.parseTimeMs
481
- };
482
- } catch (error) {
483
- return {
484
- tokens: [],
485
- errors: [
486
- {
487
- message: error instanceof Error ? error.message : "Unknown error",
488
- file: filePath
489
- }
490
- ],
491
- warnings: [],
492
- parseTimeMs: performance.now() - startTime
493
- };
494
- }
495
- }
496
- function containsTailwindV4Theme(content) {
497
- return /^@theme\b/m.test(content);
498
- }
499
-
500
- export {
501
- parseTailwindV4Theme,
502
- parseTokenFile,
503
- parseTokenFiles,
504
- hexToRgb,
505
- rgbToHex,
506
- parseRgb,
507
- normalizeColor,
508
- parseTailwindV4File,
509
- containsTailwindV4Theme
510
- };
511
- //# sourceMappingURL=chunk-MHIBEEW4.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/service/token-parser.ts","../src/service/tailwind-v4-parser.ts"],"sourcesContent":["/**\n * Token Parser\n *\n * Parses CSS/SCSS files to extract CSS custom properties (design tokens).\n * Handles:\n * - CSS custom property declarations (--token-name: value)\n * - Reference resolution (var(--other-token))\n * - Theme detection via selectors\n * - Category inference from naming conventions\n * - Tailwind v4 @theme blocks (via tailwind-v4-parser)\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { readFileSync } from \"node:fs\";\nimport { resolve, relative } from \"node:path\";\nimport fastGlob from \"fast-glob\";\nimport type {\n DesignToken,\n TokenCategory,\n TokenConfig,\n TokenParseResult,\n TokenParseError,\n} from \"../core/index.js\";\nimport { parseTailwindV4Theme } from \"./tailwind-v4-parser.js\";\n\n/**\n * Pattern to match CSS custom property declarations\n * Captures: [full match, property name, value]\n * Example: \"--color-primary: var(--color-cobalt-50);\"\n */\nconst TOKEN_DECLARATION_PATTERN =\n /--([a-zA-Z0-9_-]+)\\s*:\\s*([^;]+);/g;\n\n/**\n * Pattern to match var() references\n * Captures: [full match, token name, fallback value?]\n * Example: \"var(--color-cobalt-50)\" or \"var(--color-primary, #fff)\"\n */\nconst VAR_REFERENCE_PATTERN =\n /var\\(\\s*--([a-zA-Z0-9_-]+)(?:\\s*,\\s*([^)]+))?\\s*\\)/g;\n\n/**\n * Pattern to match CSS selectors (to detect theme blocks)\n */\nconst SELECTOR_PATTERN = /([^{]+)\\s*\\{/g;\n\n/**\n * Category inference patterns - maps naming conventions to categories\n */\nconst CATEGORY_PATTERNS: Array<{\n pattern: RegExp;\n category: TokenCategory;\n}> = [\n { pattern: /color|bg|background|border-color|fill|stroke/i, category: \"color\" },\n { pattern: /spacing|margin|padding|gap|space|inset/i, category: \"spacing\" },\n { pattern: /font|text|line-height|letter-spacing|typography/i, category: \"typography\" },\n { pattern: /radius|rounded|corner/i, category: \"radius\" },\n { pattern: /shadow|elevation/i, category: \"shadow\" },\n { pattern: /size|width|height|min|max/i, category: \"sizing\" },\n { pattern: /border(?!-color)|stroke-width|outline/i, category: \"border\" },\n { pattern: /animation|transition|duration|timing|delay/i, category: \"animation\" },\n { pattern: /z-index|layer|stack/i, category: \"z-index\" },\n];\n\n/**\n * Parse a single CSS/SCSS file for tokens\n */\nexport async function parseTokenFile(\n filePath: string,\n themeSelectors: Record<string, string> = { \":root\": \"default\" },\n projectRoot?: string\n): Promise<TokenParseResult> {\n const startTime = performance.now();\n const tokens: DesignToken[] = [];\n const errors: TokenParseError[] = [];\n const warnings: string[] = [];\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n const relativePath = projectRoot\n ? relative(projectRoot, filePath)\n : filePath;\n\n // If the file contains @theme blocks, also extract tokens via the v4 parser\n if (containsTailwindV4Theme(content)) {\n const v4Result = parseTailwindV4Theme(content, relativePath);\n tokens.push(...v4Result.tokens);\n warnings.push(...v4Result.warnings);\n for (const err of v4Result.errors) {\n errors.push({ message: err, file: filePath });\n }\n }\n\n // Track which tokens we've seen for reference resolution\n const tokensByName = new Map<string, { rawValue: string; line?: number }>();\n\n // First pass: collect all token declarations\n let lineNumber = 1;\n const lines = content.split(\"\\n\");\n\n // Track current selector/theme context\n let currentSelector = \":root\";\n let braceDepth = 0;\n const selectorStack: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n lineNumber = i + 1;\n\n // Track brace depth for selector context\n const openBraces = (line.match(/\\{/g) || []).length;\n const closeBraces = (line.match(/\\}/g) || []).length;\n\n // Check for selector at start of line (simple heuristic)\n if (openBraces > closeBraces) {\n // Entering a new block\n const selectorMatch = line.match(/^\\s*([^{]+)\\s*\\{/);\n if (selectorMatch) {\n selectorStack.push(selectorMatch[1].trim());\n currentSelector = selectorStack[selectorStack.length - 1];\n }\n braceDepth += openBraces - closeBraces;\n } else if (closeBraces > openBraces) {\n braceDepth -= closeBraces - openBraces;\n if (braceDepth >= 0 && selectorStack.length > 0) {\n selectorStack.pop();\n currentSelector = selectorStack.length > 0\n ? selectorStack[selectorStack.length - 1]\n : \":root\";\n }\n }\n\n // Find token declarations in this line\n const tokenMatches = [...line.matchAll(TOKEN_DECLARATION_PATTERN)];\n for (const match of tokenMatches) {\n const [, name, rawValue] = match;\n const fullName = `--${name}`;\n tokensByName.set(fullName, { rawValue: rawValue.trim(), line: lineNumber });\n }\n }\n\n // Second pass: resolve references and build token objects\n for (const [name, { rawValue, line }] of tokensByName) {\n // Find the selector context for this token\n // Re-parse to get correct selector (simplified - uses last found)\n const selector = findSelectorForLine(content, line || 1);\n const theme = themeSelectors[selector] || \"default\";\n\n // Resolve the value\n const { resolvedValue, chain, hasCircular, unresolvedRef } = resolveValue(\n rawValue,\n tokensByName\n );\n\n if (hasCircular) {\n warnings.push(\n `Circular reference detected for ${name} at line ${line}`\n );\n }\n\n if (unresolvedRef) {\n warnings.push(\n `Unresolved reference in ${name}: ${unresolvedRef}`\n );\n }\n\n // Infer category from name\n const category = inferCategory(name);\n\n // Infer token level\n const level = inferLevel(name, rawValue, chain);\n\n // Extract description from preceding comment (if any)\n const description = extractDescription(content, line || 1);\n\n tokens.push({\n name,\n rawValue,\n resolvedValue,\n category,\n level,\n referenceChain: chain,\n sourceFile: relativePath,\n lineNumber: line,\n theme,\n selector,\n description,\n });\n }\n } catch (error) {\n errors.push({\n message: error instanceof Error ? error.message : \"Unknown error\",\n file: filePath,\n });\n }\n\n return {\n tokens,\n errors,\n warnings,\n parseTimeMs: performance.now() - startTime,\n };\n}\n\n/**\n * Parse multiple files based on config\n */\nexport async function parseTokenFiles(\n config: TokenConfig,\n projectRoot: string\n): Promise<TokenParseResult> {\n const startTime = performance.now();\n const allTokens: DesignToken[] = [];\n const allErrors: TokenParseError[] = [];\n const allWarnings: string[] = [];\n\n // Discover files\n const files = await fastGlob(config.include, {\n cwd: projectRoot,\n ignore: config.exclude || [\"**/node_modules/**\"],\n absolute: true,\n });\n\n if (files.length === 0) {\n allWarnings.push(\n `No token files found matching: ${config.include.join(\", \")}`\n );\n }\n\n // Parse each file\n for (const file of files) {\n const result = await parseTokenFile(\n file,\n config.themeSelectors,\n projectRoot\n );\n\n allTokens.push(...result.tokens);\n allErrors.push(...result.errors);\n allWarnings.push(...result.warnings);\n }\n\n return {\n tokens: allTokens,\n errors: allErrors,\n warnings: allWarnings,\n parseTimeMs: performance.now() - startTime,\n };\n}\n\n/**\n * Resolve a token value, following var() references\n */\nfunction resolveValue(\n rawValue: string,\n tokensByName: Map<string, { rawValue: string; line?: number }>,\n visited = new Set<string>()\n): {\n resolvedValue: string;\n chain: string[];\n hasCircular: boolean;\n unresolvedRef?: string;\n} {\n const chain: string[] = [];\n let current = rawValue;\n let hasCircular = false;\n let unresolvedRef: string | undefined;\n\n // Maximum iterations to prevent infinite loops\n const maxIterations = 20;\n let iterations = 0;\n\n while (iterations < maxIterations) {\n iterations++;\n\n // Check for var() reference\n const varMatch = current.match(/var\\(\\s*--([a-zA-Z0-9_-]+)(?:\\s*,\\s*([^)]+))?\\s*\\)/);\n\n if (!varMatch) {\n // No more var() references, we have the resolved value\n break;\n }\n\n const [, refName, fallback] = varMatch;\n const fullRefName = `--${refName}`;\n\n // Check for circular reference\n if (visited.has(fullRefName)) {\n hasCircular = true;\n break;\n }\n\n visited.add(fullRefName);\n chain.push(fullRefName);\n\n // Look up the referenced token\n const refToken = tokensByName.get(fullRefName);\n\n if (refToken) {\n // Replace var() with the referenced value\n current = current.replace(\n varMatch[0],\n refToken.rawValue\n );\n } else if (fallback) {\n // Use fallback value\n current = current.replace(varMatch[0], fallback.trim());\n } else {\n // Unresolved reference\n unresolvedRef = fullRefName;\n break;\n }\n }\n\n return {\n resolvedValue: normalizeValue(current.trim()),\n chain,\n hasCircular,\n unresolvedRef,\n };\n}\n\n/**\n * Normalize a CSS value for consistent comparison\n */\nfunction normalizeValue(value: string): string {\n // Lowercase hex colors\n value = value.replace(/#[0-9a-fA-F]+/g, (match) => match.toLowerCase());\n\n // Normalize whitespace\n value = value.replace(/\\s+/g, \" \").trim();\n\n // Normalize rgb/rgba spacing\n value = value.replace(\n /rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(?:,\\s*([\\d.]+))?\\s*\\)/g,\n (_, r, g, b, a) => a !== undefined ? `rgba(${r}, ${g}, ${b}, ${a})` : `rgb(${r}, ${g}, ${b})`\n );\n\n return value;\n}\n\n/**\n * Infer token category from name\n */\nfunction inferCategory(name: string): TokenCategory {\n const lowerName = name.toLowerCase();\n\n for (const { pattern, category } of CATEGORY_PATTERNS) {\n if (pattern.test(lowerName)) {\n return category;\n }\n }\n\n return \"other\";\n}\n\n/**\n * Infer token level (1=base, 2=semantic, 3=component)\n */\nfunction inferLevel(\n name: string,\n rawValue: string,\n referenceChain: string[]\n): 1 | 2 | 3 {\n const lowerName = name.toLowerCase();\n\n // Component-specific tokens (often contain component names)\n if (\n /btn|button|input|card|modal|dialog|menu|nav|header|footer|table|form/i.test(\n lowerName\n )\n ) {\n return 3;\n }\n\n // Semantic tokens (references other tokens)\n if (referenceChain.length > 0) {\n return 2;\n }\n\n // Base tokens (raw values like hex colors, numbers)\n if (\n rawValue.match(/^#[0-9a-fA-F]+$/) ||\n rawValue.match(/^\\d+(\\.\\d+)?(px|rem|em|%|vh|vw)?$/)\n ) {\n return 1;\n }\n\n // Default to semantic if unclear\n return 2;\n}\n\n/**\n * Find the CSS selector that contains a given line\n */\nfunction findSelectorForLine(content: string, targetLine: number): string {\n const lines = content.split(\"\\n\");\n let currentSelector = \":root\";\n let braceDepth = 0;\n\n for (let i = 0; i < Math.min(targetLine, lines.length); i++) {\n const line = lines[i];\n\n // Check for selector at start of block\n const selectorMatch = line.match(/^\\s*([^{]+)\\s*\\{/);\n if (selectorMatch) {\n const selector = selectorMatch[1].trim();\n // Only update if entering a new block\n if ((line.match(/\\{/g) || []).length > (line.match(/\\}/g) || []).length) {\n currentSelector = selector;\n }\n }\n\n // Track brace depth\n braceDepth += (line.match(/\\{/g) || []).length;\n braceDepth -= (line.match(/\\}/g) || []).length;\n\n // If we close all braces, reset to root\n if (braceDepth === 0) {\n currentSelector = \":root\";\n }\n }\n\n return currentSelector;\n}\n\n/**\n * Extract description from comment preceding the token\n */\nfunction extractDescription(content: string, line: number): string | undefined {\n const lines = content.split(\"\\n\");\n\n // Look at the line before\n if (line <= 1) return undefined;\n\n const prevLine = lines[line - 2]?.trim();\n\n // Check for single-line comment\n const singleLineMatch = prevLine?.match(/\\/\\/\\s*(.+)$/);\n if (singleLineMatch) {\n return singleLineMatch[1].trim();\n }\n\n // Check for multi-line comment ending\n const multiLineMatch = prevLine?.match(/\\*\\s*(.+)\\s*\\*\\//);\n if (multiLineMatch) {\n return multiLineMatch[1].trim();\n }\n\n // Check for simple /* comment */\n const inlineMatch = prevLine?.match(/\\/\\*\\s*(.+)\\s*\\*\\//);\n if (inlineMatch) {\n return inlineMatch[1].trim();\n }\n\n return undefined;\n}\n\n/**\n * Convert a hex color to RGB\n */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n const match = hex.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);\n if (!match) return null;\n\n return {\n r: parseInt(match[1], 16),\n g: parseInt(match[2], 16),\n b: parseInt(match[3], 16),\n };\n}\n\n/**\n * Convert RGB to hex\n */\nexport function rgbToHex(r: number, g: number, b: number): string {\n return `#${[r, g, b]\n .map((x) => Math.round(x).toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n\n/**\n * Parse an RGB/RGBA string\n */\nexport function parseRgb(\n color: string\n): { r: number; g: number; b: number; a?: number } | null {\n const match = color.match(\n /rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(?:,\\s*([\\d.]+))?\\s*\\)/\n );\n if (!match) return null;\n\n return {\n r: parseInt(match[1], 10),\n g: parseInt(match[2], 10),\n b: parseInt(match[3], 10),\n a: match[4] ? parseFloat(match[4]) : undefined,\n };\n}\n\n/**\n * Normalize a color value to lowercase hex\n */\nexport function normalizeColor(color: string): string {\n // Already hex\n if (color.startsWith(\"#\")) {\n return color.toLowerCase();\n }\n\n // RGB/RGBA to hex\n const rgb = parseRgb(color);\n if (rgb) {\n return rgbToHex(rgb.r, rgb.g, rgb.b);\n }\n\n return color.toLowerCase();\n}\n\n// ─── Tailwind v4 @theme Parser Integration ──────────────────────────────────\n\n/**\n * Parse a CSS file containing Tailwind v4 @theme blocks.\n *\n * Reads the file synchronously and delegates to parseTailwindV4Theme.\n * Returns a TokenParseResult compatible with the rest of the token pipeline.\n */\nexport function parseTailwindV4File(filePath: string): TokenParseResult {\n const startTime = performance.now();\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const result = parseTailwindV4Theme(content, filePath);\n\n return {\n tokens: result.tokens,\n errors: result.errors.map((message) => ({ message, file: filePath })),\n warnings: result.warnings,\n parseTimeMs: result.parseTimeMs,\n };\n } catch (error) {\n return {\n tokens: [],\n errors: [\n {\n message: error instanceof Error ? error.message : \"Unknown error\",\n file: filePath,\n },\n ],\n warnings: [],\n parseTimeMs: performance.now() - startTime,\n };\n }\n}\n\n/**\n * Check whether a CSS file contains Tailwind v4 @theme blocks.\n */\nexport function containsTailwindV4Theme(content: string): boolean {\n return /^@theme\\b/m.test(content);\n}\n","/**\n * Tailwind v4 @theme Block Parser\n *\n * Extracts CSS custom properties (--name: value;) from Tailwind v4 @theme {}\n * blocks. Tailwind v4 moves token definitions from tailwind.config.js into\n * CSS @theme blocks, declaring design tokens as standard custom properties.\n *\n * Handles:\n * - Multiple @theme blocks in one file\n * - @theme inline { ... } variant\n * - Empty @theme {} blocks\n * - Comments (// single-line and multi-line)\n * - Nested blocks inside @theme (tracks brace depth correctly)\n * - Lines without semicolons (skipped with warning)\n */\n\nimport type {\n DesignToken,\n TokenCategory,\n} from \"../core/index.js\";\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface ThemeParserResult {\n tokens: DesignToken[];\n errors: string[];\n warnings: string[];\n parseTimeMs: number;\n}\n\n// ─── Category Inference ──────────────────────────────────────────────────────\n\n/**\n * Category inference patterns — same logic as token-parser.ts CATEGORY_PATTERNS\n * to keep categorization consistent across all parsers.\n */\nconst CATEGORY_PATTERNS: Array<{\n pattern: RegExp;\n category: TokenCategory;\n}> = [\n { pattern: /color|bg|background|border-color|fill|stroke/i, category: \"color\" },\n { pattern: /spacing|margin|padding|gap|space|inset/i, category: \"spacing\" },\n { pattern: /font|text|line-height|letter-spacing|typography/i, category: \"typography\" },\n { pattern: /radius|rounded|corner/i, category: \"radius\" },\n { pattern: /shadow|elevation/i, category: \"shadow\" },\n { pattern: /size|width|height|min|max/i, category: \"sizing\" },\n { pattern: /border(?!-color)|stroke-width|outline/i, category: \"border\" },\n { pattern: /animation|transition|duration|timing|delay/i, category: \"animation\" },\n { pattern: /z-index|layer|stack/i, category: \"z-index\" },\n];\n\n/**\n * Infer token category from a CSS custom property name.\n */\nfunction inferCategory(name: string): TokenCategory {\n const lowerName = name.toLowerCase();\n\n for (const { pattern, category } of CATEGORY_PATTERNS) {\n if (pattern.test(lowerName)) {\n return category;\n }\n }\n\n return \"other\";\n}\n\n/**\n * Infer token level:\n * - 1 (base) for raw values (hex colors, numbers, named CSS values)\n * - 2 (semantic) for var() references\n */\nfunction inferLevel(rawValue: string): 1 | 2 | 3 {\n if (/var\\(/.test(rawValue)) {\n return 2;\n }\n return 1;\n}\n\n// ─── Comment Stripping ───────────────────────────────────────────────────────\n\n/**\n * Remove block comments from a CSS string, handling multi-line spans.\n * Returns the cleaned string.\n */\nfunction stripBlockComments(css: string): string {\n return css.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n}\n\n// ─── Parser ──────────────────────────────────────────────────────────────────\n\n/** Regex to match a CSS custom property declaration inside a @theme block */\nconst CUSTOM_PROPERTY_PATTERN = /^\\s*(--[\\w-]+)\\s*:\\s*(.+?)\\s*;?\\s*$/;\n\n/**\n * Parse Tailwind v4 @theme blocks from CSS content and extract design tokens.\n *\n * @param cssContent - Raw CSS file content (may contain @theme blocks)\n * @param filePath - Optional source file path for diagnostics\n * @returns ThemeParserResult with extracted tokens, errors, and warnings\n */\nexport function parseTailwindV4Theme(\n cssContent: string,\n filePath?: string,\n): ThemeParserResult {\n const startTime = performance.now();\n const tokens: DesignToken[] = [];\n const errors: string[] = [];\n const warnings: string[] = [];\n const source = filePath ?? \"unknown\";\n\n // Strip block comments first so they don't interfere with parsing\n const cleaned = stripBlockComments(cssContent);\n\n const lines = cleaned.split(\"\\n\");\n\n let insideTheme = false;\n let themeDepth = 0; // brace depth relative to the @theme block\n let pendingTheme = false; // saw @theme keyword, waiting for opening brace\n\n for (let i = 0; i < lines.length; i++) {\n let line = lines[i];\n const lineNumber = i + 1;\n\n // Strip single-line comments (// ...)\n const singleCommentIdx = line.indexOf(\"//\");\n if (singleCommentIdx !== -1) {\n // Make sure // is not inside a string (simple heuristic: not inside quotes)\n const beforeComment = line.slice(0, singleCommentIdx);\n const singleQuotes = (beforeComment.match(/'/g) || []).length;\n const doubleQuotes = (beforeComment.match(/\"/g) || []).length;\n // If both quote counts are even, the // is not inside a string\n if (singleQuotes % 2 === 0 && doubleQuotes % 2 === 0) {\n line = beforeComment;\n }\n }\n\n const trimmed = line.trim();\n\n // Skip empty lines\n if (trimmed === \"\") {\n continue;\n }\n\n // Detect @theme keyword (with optional modifiers like \"inline\")\n if (!insideTheme && !pendingTheme) {\n // Match @theme, @theme inline, @theme { ... }, etc.\n if (/^@theme\\b/.test(trimmed)) {\n pendingTheme = true;\n // Check if the opening brace is on the same line\n const braceIdx = trimmed.indexOf(\"{\");\n if (braceIdx !== -1) {\n pendingTheme = false;\n insideTheme = true;\n themeDepth = 1;\n\n // Count any additional braces on this same line\n const afterBrace = trimmed.slice(braceIdx + 1);\n for (const ch of afterBrace) {\n if (ch === \"{\") themeDepth++;\n else if (ch === \"}\") themeDepth--;\n }\n\n // If there are declarations on the same line as @theme {\n // (e.g., @theme { --color-primary: #000; })\n const inlineContent = afterBrace.trim();\n if (inlineContent && themeDepth > 0) {\n processThemeLine(inlineContent, lineNumber, source, tokens, warnings);\n }\n\n if (themeDepth <= 0) {\n insideTheme = false;\n }\n }\n continue;\n }\n }\n\n // If we saw @theme but haven't found the opening brace yet\n if (pendingTheme) {\n const braceIdx = trimmed.indexOf(\"{\");\n if (braceIdx !== -1) {\n pendingTheme = false;\n insideTheme = true;\n themeDepth = 1;\n\n // Count additional braces on this line\n const afterBrace = trimmed.slice(braceIdx + 1);\n for (const ch of afterBrace) {\n if (ch === \"{\") themeDepth++;\n else if (ch === \"}\") themeDepth--;\n }\n\n // Process any inline content after the brace\n const inlineContent = afterBrace.trim();\n if (inlineContent && themeDepth > 0) {\n processThemeLine(inlineContent, lineNumber, source, tokens, warnings);\n }\n\n if (themeDepth <= 0) {\n insideTheme = false;\n }\n }\n // If no brace found, keep waiting (could be multi-line @theme declaration)\n continue;\n }\n\n // Inside a @theme block — track braces and extract declarations\n if (insideTheme) {\n // Count braces to track depth\n for (const ch of trimmed) {\n if (ch === \"{\") {\n themeDepth++;\n } else if (ch === \"}\") {\n themeDepth--;\n if (themeDepth <= 0) {\n insideTheme = false;\n break;\n }\n }\n }\n\n // Only extract declarations at depth 1 (directly inside @theme)\n // or if we're still inside the theme block\n if (insideTheme || themeDepth > 0) {\n // Remove any closing braces from the line content before matching\n const contentLine = trimmed.replace(/\\}/g, \"\").trim();\n if (contentLine) {\n processThemeLine(contentLine, lineNumber, source, tokens, warnings);\n }\n }\n }\n }\n\n // If we ended while still expecting a @theme block, warn\n if (pendingTheme) {\n warnings.push(\n `@theme keyword found but no opening brace — incomplete block in ${source}`,\n );\n }\n\n if (insideTheme) {\n warnings.push(\n `Unclosed @theme block — missing closing brace in ${source}`,\n );\n }\n\n return {\n tokens,\n errors,\n warnings,\n parseTimeMs: performance.now() - startTime,\n };\n}\n\n/**\n * Process a single line inside a @theme block, attempting to extract a\n * CSS custom property declaration.\n */\nfunction processThemeLine(\n line: string,\n lineNumber: number,\n source: string,\n tokens: DesignToken[],\n warnings: string[],\n): void {\n const match = line.match(CUSTOM_PROPERTY_PATTERN);\n\n if (!match) {\n // If the line looks like it has a custom property but is missing a semicolon\n const partialMatch = line.match(/^\\s*(--[\\w-]+)\\s*:\\s*(.+?)\\s*$/);\n if (partialMatch) {\n // It matched without semicolon — treat as valid (CSS tolerates missing trailing semicolons)\n const [, name, rawValue] = partialMatch;\n tokens.push(buildToken(name, rawValue, lineNumber, source));\n return;\n }\n\n // Lines that contain -- but couldn't be parsed\n if (/^\\s*--/.test(line)) {\n warnings.push(\n `Line ${lineNumber}: Could not parse custom property declaration: ${line.trim()}`,\n );\n }\n return;\n }\n\n const [, name, rawValue] = match;\n tokens.push(buildToken(name, rawValue, lineNumber, source));\n}\n\n/**\n * Build a DesignToken from a parsed custom property declaration.\n */\nfunction buildToken(\n name: string,\n rawValue: string,\n lineNumber: number,\n source: string,\n): DesignToken {\n const value = rawValue.trim();\n\n return {\n name,\n rawValue: value,\n resolvedValue: value,\n category: inferCategory(name),\n level: inferLevel(value),\n referenceChain: [],\n sourceFile: source,\n lineNumber,\n theme: \"default\",\n selector: \"@theme\",\n };\n}\n"],"mappings":"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","names":["name","rawValue","CATEGORY_PATTERNS","inferCategory","inferLevel"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/govern-scan.ts"],"sourcesContent":["/**\n * govern scan / govern watch — Zero-config governance scanning\n *\n * Parses real JSX/TSX files via the existing codebase scanner, converts\n * component usages to UISpec, and runs governance checks per file.\n * Optionally submits results to Fragments Cloud.\n */\n\nimport pc from 'picocolors';\nimport { resolve, relative } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { BRAND } from '../core/index.js';\nimport type { ComponentUsage } from '../service/enhance/types.js';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface GovernScanOptions {\n /** Root directory to scan (default: auto-detect) */\n dir?: string;\n /** Path to govern.config.ts */\n config?: string;\n /** Output format */\n format?: 'summary' | 'json' | 'sarif';\n /** Suppress non-error output */\n quiet?: boolean;\n}\n\nexport interface GovernWatchOptions extends GovernScanOptions {\n /** Debounce interval in ms (default: 300) */\n debounce?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Scan defaults — applied when no config file exists\n// ---------------------------------------------------------------------------\n\nconst SCAN_DEFAULT_RULES: Record<string, boolean | object> = {\n 'safety/block-event-handlers': true,\n 'safety/block-dangerous-props': true,\n 'safety/block-controlled-props': true,\n 'safety/block-function-props': true,\n 'safety/sanitize-hrefs': true,\n 'tokens/require-design-tokens': true,\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Auto-detect root directory by looking for common React project dirs\n */\nfunction detectRootDir(cwd: string): string {\n const candidates = ['src', 'app', 'pages', 'components'];\n for (const dir of candidates) {\n if (existsSync(resolve(cwd, dir))) {\n return cwd;\n }\n }\n return cwd;\n}\n\n/**\n * Group component usages by their source file\n */\nfunction groupByFile(usages: ComponentUsage[]): Map<string, ComponentUsage[]> {\n const grouped = new Map<string, ComponentUsage[]>();\n for (const usage of usages) {\n const existing = grouped.get(usage.filePath);\n if (existing) {\n existing.push(usage);\n } else {\n grouped.set(usage.filePath, [usage]);\n }\n }\n return grouped;\n}\n\n// ---------------------------------------------------------------------------\n// governScan\n// ---------------------------------------------------------------------------\n\nexport async function governScan(\n options: GovernScanOptions = {},\n): Promise<{ exitCode: number }> {\n const {\n loadPolicy,\n createEngine,\n buildAdaptersFromConfig,\n createCloudAdapter,\n formatVerdict,\n computeComponentHealth,\n } = await import('@fragments-sdk/govern');\n\n const { scanCodebase } = await import(\n '../service/enhance/codebase-scanner.js'\n );\n const { usagesToSpec } = await import(\n '../service/enhance/converter.js'\n );\n\n const format = options.format ?? 'summary';\n const quiet = options.quiet ?? false;\n\n if (!quiet) {\n console.log(pc.cyan(`\\n${BRAND.name} Governance Scan\\n`));\n }\n\n // 1. Resolve root directory\n const rootDir = resolve(options.dir ?? detectRootDir(process.cwd()));\n if (!quiet) {\n console.log(pc.dim(` Root: ${rootDir}\\n`));\n }\n\n // 2. Load policy — use scan defaults if no config exists\n let policy = await loadPolicy(options.config);\n const hasRules = Object.keys(policy.rules).length > 0;\n\n if (!hasRules) {\n policy = { ...policy, rules: SCAN_DEFAULT_RULES };\n if (!quiet) {\n console.log(pc.dim(' No config found — using scan defaults (safety + tokens)\\n'));\n }\n }\n\n // 3. Extract code tokens for cloud ingest\n let codeTokens: string | undefined;\n if (process.env.FRAGMENTS_API_KEY) {\n codeTokens = await extractCodeTokens(rootDir, options.config, quiet);\n }\n\n // 3b. Load contract registry for governance + cloud ingest (if fragments.json exists)\n let contractRegistry: string | undefined;\n let registryMap: Record<string, unknown> | undefined;\n {\n const { readFileSync, existsSync } = await import('node:fs');\n const fragmentsJsonPath = resolve(rootDir, 'fragments.json');\n if (existsSync(fragmentsJsonPath)) {\n try {\n const raw = readFileSync(fragmentsJsonPath, 'utf-8');\n const parsed = JSON.parse(raw);\n if (parsed.fragments && Array.isArray(parsed.fragments)) {\n // Build name-keyed map for engine registry injection\n const map: Record<string, unknown> = {};\n for (const f of parsed.fragments) {\n if (f.meta?.name) {\n map[f.meta.name] = f;\n }\n }\n registryMap = map;\n\n if (process.env.FRAGMENTS_API_KEY) {\n contractRegistry = JSON.stringify({ fragments: parsed.fragments });\n }\n if (!quiet) {\n console.log(pc.dim(` Contract registry loaded (${parsed.fragments.length} components)\\n`));\n }\n }\n } catch {\n // Invalid fragments.json — skip\n }\n }\n }\n\n // 4. Build adapters. Auto-add cloud if FRAGMENTS_API_KEY is set\n const adapters = buildAdaptersFromConfig(policy.audit);\n const hasCloudAdapter = adapters.length > 0 && policy.audit?.cloud;\n if (!hasCloudAdapter && process.env.FRAGMENTS_API_KEY) {\n adapters.push(createCloudAdapter({ codeTokens, contractRegistry }));\n if (!quiet) {\n console.log(pc.dim(' Cloud audit enabled (FRAGMENTS_API_KEY detected)\\n'));\n }\n }\n\n // 5. Create engine (with registry for contract-aware validators)\n const engine = createEngine(\n policy,\n adapters,\n registryMap\n ? { registry: { fragments: registryMap as Record<string, Record<string, unknown>> } }\n : undefined,\n );\n\n // 6. Scan codebase\n if (!quiet) {\n console.log(pc.dim(' Scanning files...\\n'));\n }\n\n const analysis = await scanCodebase({\n rootDir,\n useCache: true,\n onProgress: quiet\n ? undefined\n : (progress) => {\n if (progress.phase === 'scanning') {\n process.stdout.write(\n `\\r ${pc.dim(`[${progress.current}/${progress.total}]`)} ${pc.dim(relative(rootDir, progress.currentFile))}`,\n );\n }\n },\n });\n\n if (!quiet) {\n // Clear progress line\n process.stdout.write('\\r' + ' '.repeat(80) + '\\r');\n console.log(\n pc.dim(` Scanned ${analysis.totalFiles} files, found ${analysis.totalComponents} component types\\n`),\n );\n }\n\n // 7. Collect all usages across components\n const allUsages: ComponentUsage[] = [];\n for (const comp of Object.values(analysis.components)) {\n allUsages.push(...comp.usages);\n }\n\n if (allUsages.length === 0) {\n if (!quiet) {\n console.log(pc.yellow(' No component usages found.\\n'));\n }\n return { exitCode: 0 };\n }\n\n // 8. Group by file and run checks\n const grouped = groupByFile(allUsages);\n let totalFiles = 0;\n let passedFiles = 0;\n let totalViolations = 0;\n const violationCounts = new Map<string, number>();\n const allVerdicts: Awaited<ReturnType<typeof engine.check>>[] = [];\n\n // Build per-file usage snapshot for cloud\n const usageSnapshot: Array<{\n file: string;\n components: Array<{\n name: string;\n line: number;\n props: { static: Record<string, unknown>; dynamic: string[] };\n }>;\n }> = [];\n\n for (const [filePath, usages] of grouped) {\n const spec = usagesToSpec(usages, filePath, rootDir);\n const relPath = relative(rootDir, filePath);\n\n const verdict = await engine.check(spec, {\n runner: 'cli',\n input: relPath,\n });\n allVerdicts.push(verdict);\n\n // Collect per-file usage snapshot\n usageSnapshot.push({\n file: relPath,\n components: usages.map((u) => ({\n name: u.componentName,\n line: u.line,\n props: {\n static: u.props.static,\n dynamic: u.props.dynamic,\n },\n })),\n });\n\n totalFiles++;\n\n if (verdict.passed) {\n passedFiles++;\n } else {\n if (!quiet) {\n console.log(pc.red(` ✗ ${relPath}`));\n if (format === 'summary') {\n for (const result of verdict.results) {\n for (const v of result.violations) {\n const count = violationCounts.get(v.rule) ?? 0;\n violationCounts.set(v.rule, count + 1);\n totalViolations++;\n console.log(\n pc.dim(` ${v.severity} `) +\n pc.yellow(v.rule) +\n pc.dim(` — ${v.message}`),\n );\n if (v.nodeId) {\n console.log(pc.dim(` at ${v.nodeId}`));\n }\n }\n }\n }\n }\n }\n\n if (verdict.passed && !quiet && format === 'summary') {\n console.log(pc.green(` ✓ ${relPath}`) + pc.dim(` (${usages.length} components, score: ${verdict.score}/100)`));\n }\n\n // JSON/SARIF: print per-file\n if (format === 'json' || format === 'sarif') {\n const output = formatVerdict(verdict, format);\n console.log(output);\n }\n }\n\n // 8b. Compute component health\n const health = computeComponentHealth(allVerdicts, registryMap ?? {});\n\n // 9. Summary\n if (!quiet && format === 'summary') {\n console.log(pc.dim('\\n ─────────────────────────────────────\\n'));\n console.log(` Files checked: ${totalFiles}`);\n console.log(` Passed: ${passedFiles}/${totalFiles}`);\n console.log(` Violations: ${totalViolations}`);\n\n if (violationCounts.size > 0) {\n console.log(pc.dim('\\n Top violations:'));\n const sorted = [...violationCounts.entries()].sort((a, b) => b[1] - a[1]);\n for (const [rule, count] of sorted.slice(0, 5)) {\n console.log(pc.dim(` ${count}× `) + pc.yellow(rule));\n }\n }\n\n // Component health\n console.log(pc.dim('\\n Component Health:'));\n console.log(` Contract coverage: ${health.contractCoverage}% (${health.contractedComponents}/${health.totalComponents})`);\n console.log(` Compliance rate: ${health.overallCompliance}%`);\n\n if (health.uncontracted.length > 0) {\n console.log(pc.dim(` Uncontracted: ${health.uncontracted.slice(0, 5).join(', ')}${health.uncontracted.length > 5 ? ` (+${health.uncontracted.length - 5} more)` : ''}`));\n }\n\n console.log();\n\n if (passedFiles === totalFiles) {\n console.log(pc.green(` ✓ All files passed governance checks\\n`));\n } else {\n console.log(\n pc.red(` ✗ ${totalFiles - passedFiles} file(s) failed governance checks\\n`),\n );\n }\n }\n\n // 10. Push component usage snapshot + health to Cloud (if API key set)\n if (process.env.FRAGMENTS_API_KEY && usageSnapshot.length > 0) {\n try {\n const apiKey = process.env.FRAGMENTS_API_KEY;\n const url = process.env.FRAGMENTS_URL ?? 'https://app.usefragments.com';\n await fetch(`${url}/api/ingest`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n componentUsage: JSON.stringify(usageSnapshot),\n componentHealth: JSON.stringify(health),\n }),\n });\n } catch {\n // Non-critical — don't fail the scan\n }\n }\n\n return { exitCode: passedFiles === totalFiles ? 0 : 1 };\n}\n\n// ---------------------------------------------------------------------------\n// Token extraction for cloud ingest\n// ---------------------------------------------------------------------------\n\n/**\n * Auto-detect and extract code tokens to send alongside governance verdicts.\n * Tries: 1) tokens config from fragments.config.ts, 2) Tailwind config.\n * Returns a flat JSON string of token name → value, or undefined if nothing found.\n */\nasync function extractCodeTokens(\n rootDir: string,\n configPath?: string,\n quiet?: boolean,\n): Promise<string | undefined> {\n try {\n // 1. Try fragments.config.ts tokens config\n try {\n const { loadConfig } = await import('../core/node.js');\n const { parseTokenFiles } = await import('../service/index.js');\n\n const { config, configDir } = await loadConfig(configPath);\n if (config.tokens?.include?.length) {\n const result = await parseTokenFiles(config.tokens, configDir);\n if (result.tokens.length > 0) {\n const flat: Record<string, string> = {};\n for (const token of result.tokens) {\n flat[token.name] = token.resolvedValue;\n }\n if (!quiet) {\n console.log(\n pc.dim(` Extracted ${result.tokens.length} code tokens from config\\n`),\n );\n }\n return JSON.stringify(flat);\n }\n }\n } catch {\n // No config or no tokens section — fall through\n }\n\n // 2. Try Tailwind config\n const {\n findTailwindConfig,\n loadTailwindConfig,\n } = await import('../service/token-normalizer.js');\n\n const tailwindPath = findTailwindConfig(rootDir);\n if (tailwindPath) {\n const tokens = await loadTailwindConfig(tailwindPath);\n if (tokens.length > 0) {\n const flat: Record<string, string> = {};\n for (const token of tokens) {\n flat[token.name] = token.value;\n }\n if (!quiet) {\n console.log(\n pc.dim(` Extracted ${tokens.length} tokens from Tailwind config\\n`),\n );\n }\n return JSON.stringify(flat);\n }\n }\n } catch (error) {\n if (!quiet) {\n console.log(\n pc.dim(\n ` Token extraction skipped: ${error instanceof Error ? error.message : 'unknown error'}\\n`,\n ),\n );\n }\n }\n\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// governWatch\n// ---------------------------------------------------------------------------\n\nexport async function governWatch(\n options: GovernWatchOptions = {},\n): Promise<void> {\n const {\n loadPolicy,\n createEngine,\n buildAdaptersFromConfig,\n createCloudAdapter,\n formatVerdict,\n } = await import('@fragments-sdk/govern');\n\n const { scanFile } = await import('../service/enhance/scanner.js');\n const { usagesToSpec } = await import(\n '../service/enhance/converter.js'\n );\n\n const quiet = options.quiet ?? false;\n const debounceMs = options.debounce ?? 300;\n const format = options.format ?? 'summary';\n\n // 1. Run initial scan\n console.log(pc.cyan(`\\n${BRAND.name} Governance Watch\\n`));\n\n const { exitCode } = await governScan(options);\n if (!quiet) {\n console.log(\n pc.dim(` Initial scan ${exitCode === 0 ? 'passed' : 'completed with violations'}\\n`),\n );\n }\n\n // 2. Set up engine for incremental checks\n const rootDir = resolve(options.dir ?? detectRootDir(process.cwd()));\n let policy = await loadPolicy(options.config);\n if (Object.keys(policy.rules).length === 0) {\n policy = { ...policy, rules: SCAN_DEFAULT_RULES };\n }\n const adapters = buildAdaptersFromConfig(policy.audit);\n if (!adapters.some(() => policy.audit?.cloud) && process.env.FRAGMENTS_API_KEY) {\n adapters.push(createCloudAdapter());\n }\n const engine = createEngine(policy, adapters);\n\n // 3. Watch for changes\n console.log(pc.dim(' Watching for changes... (Ctrl+C to stop)\\n'));\n\n const chokidar = await import('chokidar');\n\n const watcher = chokidar.watch(\n ['**/*.tsx', '**/*.ts', '**/*.jsx', '**/*.js'],\n {\n cwd: rootDir,\n ignoreInitial: true,\n ignored: [\n '**/node_modules/**',\n '**/dist/**',\n '**/build/**',\n '**/.next/**',\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*',\n ],\n awaitWriteFinish: { stabilityThreshold: debounceMs },\n },\n );\n\n const handleChange = async (changedRelPath: string) => {\n const absolutePath = resolve(rootDir, changedRelPath);\n\n try {\n const { usages } = await scanFile(absolutePath);\n\n if (usages.length === 0) {\n if (!quiet) {\n console.log(pc.dim(` ○ ${changedRelPath} — no component usages`));\n }\n return;\n }\n\n const spec = usagesToSpec(usages, absolutePath, rootDir);\n const verdict = await engine.check(spec, {\n runner: 'cli',\n input: changedRelPath,\n });\n\n if (verdict.passed) {\n console.log(\n pc.green(` ✓ ${changedRelPath}`) +\n pc.dim(` (${usages.length} components, score: ${verdict.score}/100)`),\n );\n } else {\n console.log(pc.red(` ✗ ${changedRelPath}`));\n if (format === 'summary') {\n for (const result of verdict.results) {\n for (const v of result.violations) {\n console.log(\n pc.dim(` ${v.severity} `) +\n pc.yellow(v.rule) +\n pc.dim(` — ${v.message}`),\n );\n }\n }\n } else {\n console.log(formatVerdict(verdict, format));\n }\n }\n } catch (error) {\n if (!quiet) {\n console.log(\n pc.dim(` ⚠ ${changedRelPath} — `) +\n pc.yellow(error instanceof Error ? error.message : 'parse error'),\n );\n }\n }\n };\n\n watcher.on('change', handleChange);\n watcher.on('add', handleChange);\n\n // Keep process alive\n await new Promise(() => {});\n}\n"],"mappings":"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","names":["existsSync"]}