@fragments-sdk/cli 0.15.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/{ai-client-I6MDWNYA.js → ai-client-LSLQGOMM.js} +1 -2
  2. package/dist/bin.js +463 -71
  3. package/dist/bin.js.map +1 -1
  4. package/dist/chunk-5JF26E55.js +1255 -0
  5. package/dist/chunk-5JF26E55.js.map +1 -0
  6. package/dist/{chunk-XJQ5BIWI.js → chunk-6SQPP47U.js} +30 -314
  7. package/dist/chunk-6SQPP47U.js.map +1 -0
  8. package/dist/{chunk-65WSVDV5.js → chunk-HQ6A6DTV.js} +1386 -1097
  9. package/dist/chunk-HQ6A6DTV.js.map +1 -0
  10. package/dist/chunk-MHIBEEW4.js +511 -0
  11. package/dist/chunk-MHIBEEW4.js.map +1 -0
  12. package/dist/{chunk-CZD3AD4Q.js → chunk-ONUP6Z4W.js} +17 -6
  13. package/dist/chunk-ONUP6Z4W.js.map +1 -0
  14. package/dist/{codebase-scanner-VOTPXRYW.js → codebase-scanner-MQHUZC2G.js} +1 -2
  15. package/dist/{converter-JLINP7CJ.js → converter-7XM3Y6NJ.js} +1 -2
  16. package/dist/{converter-JLINP7CJ.js.map → converter-7XM3Y6NJ.js.map} +1 -1
  17. package/dist/core/index.js +0 -1
  18. package/dist/create-IH4R45GE.js +806 -0
  19. package/dist/create-IH4R45GE.js.map +1 -0
  20. package/dist/{generate-A4FP5426.js → generate-PVOLUAAC.js} +3 -4
  21. package/dist/{generate-A4FP5426.js.map → generate-PVOLUAAC.js.map} +1 -1
  22. package/dist/{govern-scan-UCBZR6D6.js → govern-scan-OYFZYOQW.js} +142 -9
  23. package/dist/govern-scan-OYFZYOQW.js.map +1 -0
  24. package/dist/index.d.ts +2 -22
  25. package/dist/index.js +8 -7
  26. package/dist/index.js.map +1 -1
  27. package/dist/{init-HGSM35XA.js → init-SSGUSP7Z.js} +3 -4
  28. package/dist/{init-HGSM35XA.js.map → init-SSGUSP7Z.js.map} +1 -1
  29. package/dist/{init-cloud-MQ6GRJAZ.js → init-cloud-3DNKPWFB.js} +29 -4
  30. package/dist/{init-cloud-MQ6GRJAZ.js.map → init-cloud-3DNKPWFB.js.map} +1 -1
  31. package/dist/mcp-bin.js +1 -2
  32. package/dist/mcp-bin.js.map +1 -1
  33. package/dist/node-37AUE74M.js +65 -0
  34. package/dist/push-contracts-WY32TFP6.js +84 -0
  35. package/dist/push-contracts-WY32TFP6.js.map +1 -0
  36. package/dist/{scan-VNNKACG2.js → scan-PKSYSTRR.js} +5 -5
  37. package/dist/{scan-generate-TWRHNU5M.js → scan-generate-VY27PIOX.js} +8 -9
  38. package/dist/scan-generate-VY27PIOX.js.map +1 -0
  39. package/dist/{scanner-7LAZYPWZ.js → scanner-4KZNOXAK.js} +1 -2
  40. package/dist/{service-FHQU7YS7.js → service-QJGWUIVL.js} +16 -9
  41. package/dist/{snapshot-KQEQ6XHL.js → snapshot-WIJMEIFT.js} +1 -2
  42. package/dist/{snapshot-KQEQ6XHL.js.map → snapshot-WIJMEIFT.js.map} +1 -1
  43. package/dist/{static-viewer-63PG6FWY.js → static-viewer-7QIBQZRC.js} +1 -2
  44. package/dist/{test-UQYUCZIS.js → test-64Z5BKBA.js} +2 -3
  45. package/dist/{test-UQYUCZIS.js.map → test-64Z5BKBA.js.map} +1 -1
  46. package/dist/token-normalizer-TEPOVBPV.js +312 -0
  47. package/dist/token-normalizer-TEPOVBPV.js.map +1 -0
  48. package/dist/token-parser-32KOIOFN.js +22 -0
  49. package/dist/token-parser-32KOIOFN.js.map +1 -0
  50. package/dist/{tokens-6GYKDV6U.js → tokens-NZWFQIAB.js} +7 -7
  51. package/dist/{tokens-generate-VTZV5EEW.js → tokens-generate-5JQSJ27E.js} +1 -2
  52. package/dist/{tokens-generate-VTZV5EEW.js.map → tokens-generate-5JQSJ27E.js.map} +1 -1
  53. package/dist/tokens-push-HY3KO36V.js +148 -0
  54. package/dist/tokens-push-HY3KO36V.js.map +1 -0
  55. package/package.json +5 -3
  56. package/src/bin.ts +90 -0
  57. package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.contract.json +1 -1
  58. package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.contract.json +1 -1
  59. package/src/commands/__tests__/build-freshness.test.ts +231 -0
  60. package/src/commands/__tests__/create.test.ts +71 -0
  61. package/src/commands/__tests__/drift-sync.test.ts +1 -1
  62. package/src/commands/__tests__/govern.test.ts +258 -0
  63. package/src/commands/__tests__/init.test.ts +1 -1
  64. package/src/commands/__tests__/scan-generate.test.ts +1 -1
  65. package/src/commands/build.ts +54 -1
  66. package/src/commands/context.ts +1 -1
  67. package/src/commands/create.ts +536 -0
  68. package/src/commands/doctor.ts +3 -2
  69. package/src/commands/govern-scan.ts +187 -8
  70. package/src/commands/govern.ts +65 -2
  71. package/src/commands/init-cloud.ts +32 -4
  72. package/src/commands/push-contracts.ts +112 -0
  73. package/src/commands/scan-generate.ts +1 -1
  74. package/src/commands/scan.ts +13 -0
  75. package/src/commands/sync.ts +2 -2
  76. package/src/commands/tokens-push.ts +199 -0
  77. package/src/core/__tests__/token-resolver.test.ts +1 -1
  78. package/src/core/component-extractor.test.ts +1 -1
  79. package/src/core/drift-verifier.ts +1 -1
  80. package/src/core/extractor-adapter.ts +1 -1
  81. package/src/index.ts +3 -3
  82. package/src/migrate/fragment-to-contract.ts +2 -2
  83. package/src/service/index.ts +8 -0
  84. package/src/service/tailwind-v4-parser.ts +314 -0
  85. package/src/service/token-parser.ts +56 -0
  86. package/src/setup.ts +10 -39
  87. package/src/theme/__tests__/component-contrast.test.ts +2 -2
  88. package/src/theme/__tests__/serializer.test.ts +1 -1
  89. package/src/theme/generator.ts +16 -1
  90. package/src/theme/schema.ts +8 -0
  91. package/src/theme/serializer.ts +13 -9
  92. package/src/theme/types.ts +8 -0
  93. package/src/validators.ts +1 -2
  94. package/dist/chunk-65WSVDV5.js.map +0 -1
  95. package/dist/chunk-7WHVW72L.js +0 -2664
  96. package/dist/chunk-7WHVW72L.js.map +0 -1
  97. package/dist/chunk-CZD3AD4Q.js.map +0 -1
  98. package/dist/chunk-MN3TJ3D5.js +0 -695
  99. package/dist/chunk-MN3TJ3D5.js.map +0 -1
  100. package/dist/chunk-XJQ5BIWI.js.map +0 -1
  101. package/dist/chunk-Z7EY4VHE.js +0 -50
  102. package/dist/govern-scan-UCBZR6D6.js.map +0 -1
  103. package/dist/sass.node-4XJK6YBF.js +0 -130708
  104. package/dist/sass.node-4XJK6YBF.js.map +0 -1
  105. package/dist/scan-generate-TWRHNU5M.js.map +0 -1
  106. package/src/build.ts +0 -736
  107. package/src/core/auto-props.ts +0 -464
  108. package/src/core/component-extractor.ts +0 -1121
  109. package/src/core/token-resolver.ts +0 -155
  110. package/src/viewer/preview-adapter.ts +0 -116
  111. /package/dist/{ai-client-I6MDWNYA.js.map → ai-client-LSLQGOMM.js.map} +0 -0
  112. /package/dist/{chunk-Z7EY4VHE.js.map → codebase-scanner-MQHUZC2G.js.map} +0 -0
  113. /package/dist/{codebase-scanner-VOTPXRYW.js.map → node-37AUE74M.js.map} +0 -0
  114. /package/dist/{scan-VNNKACG2.js.map → scan-PKSYSTRR.js.map} +0 -0
  115. /package/dist/{scanner-7LAZYPWZ.js.map → scanner-4KZNOXAK.js.map} +0 -0
  116. /package/dist/{service-FHQU7YS7.js.map → service-QJGWUIVL.js.map} +0 -0
  117. /package/dist/{static-viewer-63PG6FWY.js.map → static-viewer-7QIBQZRC.js.map} +0 -0
  118. /package/dist/{tokens-6GYKDV6U.js.map → tokens-NZWFQIAB.js.map} +0 -0
@@ -0,0 +1,84 @@
1
+ import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
+ import "./chunk-D2CDBRNU.js";
3
+ import {
4
+ BRAND
5
+ } from "./chunk-32LIWN2P.js";
6
+
7
+ // src/commands/push-contracts.ts
8
+ import { readFileSync, existsSync } from "fs";
9
+ import { resolve } from "path";
10
+ import pc from "picocolors";
11
+ async function pushContracts(options = {}) {
12
+ const quiet = options.quiet ?? false;
13
+ const apiKey = options.apiKey ?? process.env.FRAGMENTS_API_KEY;
14
+ if (!apiKey) {
15
+ console.error(
16
+ pc.red("No API key found. Set FRAGMENTS_API_KEY or pass --api-key.")
17
+ );
18
+ return { exitCode: 1 };
19
+ }
20
+ if (!quiet) {
21
+ console.log(pc.cyan(`
22
+ ${BRAND.name} Push Contracts
23
+ `));
24
+ }
25
+ const inputPath = options.input ? resolve(options.input) : resolve("fragments.json");
26
+ if (!existsSync(inputPath)) {
27
+ console.error(
28
+ pc.red(`Contract registry not found at ${inputPath}`)
29
+ );
30
+ console.error(
31
+ pc.dim("Run `fragments build` or `fragments scan` to generate fragments.json first.")
32
+ );
33
+ return { exitCode: 1 };
34
+ }
35
+ let contractRegistry;
36
+ let componentCount = 0;
37
+ try {
38
+ const raw = readFileSync(inputPath, "utf-8");
39
+ const parsed = JSON.parse(raw);
40
+ const fragments = parsed.fragments ?? parsed;
41
+ if (!Array.isArray(fragments)) {
42
+ console.error(pc.red("Invalid contract registry: expected fragments array"));
43
+ return { exitCode: 1 };
44
+ }
45
+ componentCount = fragments.length;
46
+ contractRegistry = JSON.stringify({ fragments });
47
+ } catch (error) {
48
+ console.error(
49
+ pc.red("Failed to parse contract registry:"),
50
+ error instanceof Error ? error.message : "unknown error"
51
+ );
52
+ return { exitCode: 1 };
53
+ }
54
+ if (componentCount === 0) {
55
+ console.warn(pc.yellow("No components found in contract registry. Nothing to push."));
56
+ return { exitCode: 0 };
57
+ }
58
+ if (!quiet) {
59
+ console.log(pc.dim(` Found ${componentCount} component contracts
60
+ `));
61
+ console.log(pc.dim(" Pushing to Fragments Cloud...\n"));
62
+ }
63
+ const { pushContracts: push } = await import("@fragments-sdk/govern");
64
+ const result = await push({
65
+ contractRegistry,
66
+ url: options.url,
67
+ apiKey
68
+ });
69
+ if (!result.ok) {
70
+ console.error(pc.red(`Failed to push contracts: ${result.error}`));
71
+ return { exitCode: 1 };
72
+ }
73
+ if (!quiet) {
74
+ console.log(
75
+ pc.green(` \u2713 Pushed ${componentCount} component contracts to Fragments Cloud
76
+ `)
77
+ );
78
+ }
79
+ return { exitCode: 0 };
80
+ }
81
+ export {
82
+ pushContracts
83
+ };
84
+ //# sourceMappingURL=push-contracts-WY32TFP6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/push-contracts.ts"],"sourcesContent":["/**\n * fragments push-contracts\n *\n * Push compiled component contracts to Fragments Cloud.\n * Reads fragments.json from the project root (or builds it from .contract.json files)\n * and posts the contract registry to the Cloud ingest endpoint.\n */\n\nimport { readFileSync, existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport pc from 'picocolors';\nimport { BRAND } from '../core/index.js';\n\nexport interface PushContractsOptions {\n /** Path to fragments.json or directory containing .contract.json files */\n input?: string;\n /** Fragments Cloud URL */\n url?: string;\n /** API key (defaults to FRAGMENTS_API_KEY env var) */\n apiKey?: string;\n /** Suppress output */\n quiet?: boolean;\n}\n\nexport async function pushContracts(\n options: PushContractsOptions = {},\n): Promise<{ exitCode: number }> {\n const quiet = options.quiet ?? false;\n const apiKey = options.apiKey ?? process.env.FRAGMENTS_API_KEY;\n\n if (!apiKey) {\n console.error(\n pc.red('No API key found. Set FRAGMENTS_API_KEY or pass --api-key.'),\n );\n return { exitCode: 1 };\n }\n\n if (!quiet) {\n console.log(pc.cyan(`\\n${BRAND.name} Push Contracts\\n`));\n }\n\n // 1. Find contract registry\n const inputPath = options.input\n ? resolve(options.input)\n : resolve('fragments.json');\n\n if (!existsSync(inputPath)) {\n console.error(\n pc.red(`Contract registry not found at ${inputPath}`),\n );\n console.error(\n pc.dim('Run `fragments build` or `fragments scan` to generate fragments.json first.'),\n );\n return { exitCode: 1 };\n }\n\n // 2. Parse and validate\n let contractRegistry: string;\n let componentCount = 0;\n\n try {\n const raw = readFileSync(inputPath, 'utf-8');\n const parsed = JSON.parse(raw);\n const fragments = parsed.fragments ?? parsed;\n\n if (!Array.isArray(fragments)) {\n console.error(pc.red('Invalid contract registry: expected fragments array'));\n return { exitCode: 1 };\n }\n\n componentCount = fragments.length;\n contractRegistry = JSON.stringify({ fragments });\n } catch (error) {\n console.error(\n pc.red('Failed to parse contract registry:'),\n error instanceof Error ? error.message : 'unknown error',\n );\n return { exitCode: 1 };\n }\n\n if (componentCount === 0) {\n console.warn(pc.yellow('No components found in contract registry. Nothing to push.'));\n return { exitCode: 0 };\n }\n\n if (!quiet) {\n console.log(pc.dim(` Found ${componentCount} component contracts\\n`));\n console.log(pc.dim(' Pushing to Fragments Cloud...\\n'));\n }\n\n // 3. Push to Cloud\n const { pushContracts: push } = await import('@fragments-sdk/govern');\n\n const result = await push({\n contractRegistry,\n url: options.url,\n apiKey,\n });\n\n if (!result.ok) {\n console.error(pc.red(`Failed to push contracts: ${result.error}`));\n return { exitCode: 1 };\n }\n\n if (!quiet) {\n console.log(\n pc.green(` ✓ Pushed ${componentCount} component contracts to Fragments Cloud\\n`),\n );\n }\n\n return { exitCode: 0 };\n}\n"],"mappings":";;;;;;;AAQA,SAAS,cAAc,kBAAkB;AACzC,SAAS,eAAe;AACxB,OAAO,QAAQ;AAcf,eAAsB,cACpB,UAAgC,CAAC,GACF;AAC/B,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,SAAS,QAAQ,UAAU,QAAQ,IAAI;AAE7C,MAAI,CAAC,QAAQ;AACX,YAAQ;AAAA,MACN,GAAG,IAAI,4DAA4D;AAAA,IACrE;AACA,WAAO,EAAE,UAAU,EAAE;AAAA,EACvB;AAEA,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,GAAG,KAAK;AAAA,EAAK,MAAM,IAAI;AAAA,CAAmB,CAAC;AAAA,EACzD;AAGA,QAAM,YAAY,QAAQ,QACtB,QAAQ,QAAQ,KAAK,IACrB,QAAQ,gBAAgB;AAE5B,MAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,YAAQ;AAAA,MACN,GAAG,IAAI,kCAAkC,SAAS,EAAE;AAAA,IACtD;AACA,YAAQ;AAAA,MACN,GAAG,IAAI,6EAA6E;AAAA,IACtF;AACA,WAAO,EAAE,UAAU,EAAE;AAAA,EACvB;AAGA,MAAI;AACJ,MAAI,iBAAiB;AAErB,MAAI;AACF,UAAM,MAAM,aAAa,WAAW,OAAO;AAC3C,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UAAM,YAAY,OAAO,aAAa;AAEtC,QAAI,CAAC,MAAM,QAAQ,SAAS,GAAG;AAC7B,cAAQ,MAAM,GAAG,IAAI,qDAAqD,CAAC;AAC3E,aAAO,EAAE,UAAU,EAAE;AAAA,IACvB;AAEA,qBAAiB,UAAU;AAC3B,uBAAmB,KAAK,UAAU,EAAE,UAAU,CAAC;AAAA,EACjD,SAAS,OAAO;AACd,YAAQ;AAAA,MACN,GAAG,IAAI,oCAAoC;AAAA,MAC3C,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAC3C;AACA,WAAO,EAAE,UAAU,EAAE;AAAA,EACvB;AAEA,MAAI,mBAAmB,GAAG;AACxB,YAAQ,KAAK,GAAG,OAAO,4DAA4D,CAAC;AACpF,WAAO,EAAE,UAAU,EAAE;AAAA,EACvB;AAEA,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,GAAG,IAAI,WAAW,cAAc;AAAA,CAAwB,CAAC;AACrE,YAAQ,IAAI,GAAG,IAAI,mCAAmC,CAAC;AAAA,EACzD;AAGA,QAAM,EAAE,eAAe,KAAK,IAAI,MAAM,OAAO,uBAAuB;AAEpE,QAAM,SAAS,MAAM,KAAK;AAAA,IACxB;AAAA,IACA,KAAK,QAAQ;AAAA,IACb;AAAA,EACF,CAAC;AAED,MAAI,CAAC,OAAO,IAAI;AACd,YAAQ,MAAM,GAAG,IAAI,6BAA6B,OAAO,KAAK,EAAE,CAAC;AACjE,WAAO,EAAE,UAAU,EAAE;AAAA,EACvB;AAEA,MAAI,CAAC,OAAO;AACV,YAAQ;AAAA,MACN,GAAG,MAAM,mBAAc,cAAc;AAAA,CAA2C;AAAA,IAClF;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,EAAE;AACvB;","names":[]}
@@ -1,15 +1,15 @@
1
1
  import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
2
  import {
3
3
  scan
4
- } from "./chunk-CZD3AD4Q.js";
5
- import "./chunk-65WSVDV5.js";
6
- import "./chunk-XJQ5BIWI.js";
4
+ } from "./chunk-ONUP6Z4W.js";
5
+ import "./chunk-6SQPP47U.js";
7
6
  import "./chunk-D2CDBRNU.js";
7
+ import "./chunk-HQ6A6DTV.js";
8
8
  import "./chunk-32LIWN2P.js";
9
+ import "./chunk-MHIBEEW4.js";
9
10
  import "./chunk-QCN35LJU.js";
10
11
  import "./chunk-7DZC4YEV.js";
11
- import "./chunk-Z7EY4VHE.js";
12
12
  export {
13
13
  scan
14
14
  };
15
- //# sourceMappingURL=scan-VNNKACG2.js.map
15
+ //# sourceMappingURL=scan-PKSYSTRR.js.map
@@ -1,15 +1,11 @@
1
1
  import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
- import {
3
- createComponentExtractor
4
- } from "./chunk-MN3TJ3D5.js";
2
+ import "./chunk-D2CDBRNU.js";
5
3
  import {
6
4
  discoverAllComponents
7
- } from "./chunk-65WSVDV5.js";
8
- import "./chunk-D2CDBRNU.js";
5
+ } from "./chunk-HQ6A6DTV.js";
9
6
  import {
10
7
  BRAND
11
8
  } from "./chunk-32LIWN2P.js";
12
- import "./chunk-Z7EY4VHE.js";
13
9
 
14
10
  // src/commands/scan-generate.ts
15
11
  import { readFile, writeFile, access, mkdir } from "fs/promises";
@@ -17,6 +13,9 @@ import { resolve, basename, dirname, relative, join } from "path";
17
13
  import { execSync } from "child_process";
18
14
  import * as ts from "typescript";
19
15
  import pc from "picocolors";
16
+ import {
17
+ createComponentExtractor
18
+ } from "@fragments-sdk/extract";
20
19
  async function findNearestAncestor(scanPath, targetFile) {
21
20
  let dir = resolve(scanPath);
22
21
  for (let i = 0; i < 20; i++) {
@@ -245,7 +244,7 @@ ${BRAND.name} Scan \u2192 Generate
245
244
  });
246
245
  enrichments = enrichResult.enrichments;
247
246
  if (enrichResult.model && enrichResult.totalInputTokens > 0) {
248
- const { calculateCost } = await import("./ai-client-I6MDWNYA.js");
247
+ const { calculateCost } = await import("./ai-client-LSLQGOMM.js");
249
248
  enrichmentCost = calculateCost(
250
249
  enrichResult.model,
251
250
  enrichResult.totalInputTokens,
@@ -668,7 +667,7 @@ async function enrichComponents(componentDataList, options) {
668
667
  createAIClient,
669
668
  generateCompletion,
670
669
  ENRICHMENT_MODELS
671
- } = await import("./ai-client-I6MDWNYA.js");
670
+ } = await import("./ai-client-LSLQGOMM.js");
672
671
  const provider = detectProvider({ provider: options.provider, apiKey: options.apiKey });
673
672
  if (provider === "none") {
674
673
  console.log(pc.yellow(" No API key found. Set ANTHROPIC_API_KEY or OPENAI_API_KEY, or use --api-key"));
@@ -1401,4 +1400,4 @@ export {
1401
1400
  resolveCoreInstallCommand,
1402
1401
  scanGenerate
1403
1402
  };
1404
- //# sourceMappingURL=scan-generate-TWRHNU5M.js.map
1403
+ //# sourceMappingURL=scan-generate-VY27PIOX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/scan-generate.ts"],"sourcesContent":["/**\n * fragments init --scan - Generate fragment files from any TypeScript component library\n *\n * Phase 2 of the Universal GenUI strategy. Scans a component directory and\n * generates .fragment.tsx files with TODO markers for uncertain fields.\n *\n * Combines:\n * - Component discovery (core/discovery.ts)\n * - ComponentExtractor: persistent LanguageService-based prop + compound extraction\n * - Confidence scoring with TODO markers\n * - Composition-aware code generation\n */\n\nimport { readFile, writeFile, access, mkdir } from \"node:fs/promises\";\nimport { resolve, basename, dirname, relative, join } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport * as ts from \"typescript\";\nimport pc from \"picocolors\";\nimport { BRAND } from \"../core/index.js\";\nimport {\n discoverAllComponents,\n type DiscoveredComponent,\n} from \"../core/node.js\";\nimport {\n createComponentExtractor,\n type ComponentExtractor,\n type ComponentMeta,\n type PropMeta,\n type CompositionMeta,\n} from '@fragments-sdk/extract';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ScanGenerateOptions {\n /** Path to scan for components */\n scanPath: string;\n /** Output directory (default: colocated with source) */\n outputDir?: string;\n /** Overwrite existing fragment files */\n force?: boolean;\n /** Custom component file patterns */\n patterns?: string[];\n /** Skip Storybook story extraction */\n skipStorybook?: boolean;\n /** Verbose logging */\n verbose?: boolean;\n /** Path to tsconfig.json for accurate type resolution */\n tsconfig?: string;\n /** Enable LLM enrichment of knowledge fields */\n enrich?: boolean;\n /** Show what would be enriched without calling API */\n dryRun?: boolean;\n /** AI provider override: anthropic or openai */\n provider?: 'anthropic' | 'openai';\n /** Explicit API key for enrichment */\n apiKey?: string;\n /** Override default AI model for enrichment */\n model?: string;\n}\n\nexport interface ScanGenerateResult {\n success: boolean;\n generated: Array<{\n name: string;\n path: string;\n confidence: number;\n todoCount: number;\n enriched?: boolean;\n }>;\n skipped: Array<{ name: string; reason: string }>;\n errors: Array<{ name: string; error: string }>;\n averageConfidence: number;\n enrichmentCost?: number;\n}\n\ninterface ComponentData {\n component: DiscoveredComponent;\n /** Full metadata from ComponentExtractor (props, composition, description) */\n meta: ComponentMeta | null;\n storyVariants: StoryVariant[];\n}\n\ninterface StoryVariant {\n name: string;\n args: Record<string, unknown>;\n}\n\ninterface FieldConfidence {\n score: number;\n todoFields: string[];\n}\n\nexport interface EnrichmentResult {\n when: string[];\n whenNot: string[];\n guidelines: string[];\n a11yRules: string[];\n scenarioTags: string[];\n tags: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Post-generation helpers\n// ---------------------------------------------------------------------------\n\ntype PackageManager = \"pnpm\" | \"yarn\" | \"npm\";\n\ninterface CompoundPartReference {\n partName: string;\n tagName: string;\n importName?: string;\n}\n\ninterface PackageManagerDetection {\n manager: PackageManager;\n lockfileDir: string | null;\n}\n\nasync function findNearestAncestor(scanPath: string, targetFile: string): Promise<string | null> {\n let dir = resolve(scanPath);\n for (let i = 0; i < 20; i++) {\n try {\n await access(join(dir, targetFile));\n return dir;\n } catch {\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n }\n return null;\n}\n\nasync function findNearestPackageJsonDir(scanPath: string): Promise<string | null> {\n return findNearestAncestor(scanPath, \"package.json\");\n}\n\nexport async function detectPackageManagerForProject(projectDir: string): Promise<PackageManagerDetection> {\n let dir = resolve(projectDir);\n\n for (let i = 0; i < 20; i++) {\n for (const [fileName, manager] of [\n [\"pnpm-lock.yaml\", \"pnpm\"],\n [\"pnpm-workspace.yaml\", \"pnpm\"],\n [\"yarn.lock\", \"yarn\"],\n [\"package-lock.json\", \"npm\"],\n ] as const) {\n try {\n await access(join(dir, fileName));\n return { manager, lockfileDir: dir };\n } catch {\n // continue\n }\n }\n\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n return { manager: \"npm\", lockfileDir: null };\n}\n\nexport function resolveCoreInstallCommand(manager: PackageManager): string {\n switch (manager) {\n case \"pnpm\":\n return \"pnpm add -D @fragments-sdk/core\";\n case \"yarn\":\n return \"yarn add -D @fragments-sdk/core\";\n default:\n return \"npm install -D @fragments-sdk/core\";\n }\n}\n\n/**\n * Ensure `@fragments-sdk/core` is in the project's devDependencies.\n * Detects package manager from lockfiles and runs install if needed.\n */\nexport async function ensureCoreDependency(scanPath: string): Promise<void> {\n const projectDir = await findNearestPackageJsonDir(scanPath);\n if (!projectDir) return;\n const pkgJsonPath = join(projectDir, \"package.json\");\n\n try {\n const pkgRaw = await readFile(pkgJsonPath, \"utf-8\");\n const pkg = JSON.parse(pkgRaw);\n const deps = pkg.dependencies || {};\n const devDeps = pkg.devDependencies || {};\n\n if (deps[\"@fragments-sdk/core\"] || devDeps[\"@fragments-sdk/core\"]) {\n console.log(pc.dim(\" · @fragments-sdk/core already installed\"));\n return;\n }\n\n const { manager } = await detectPackageManagerForProject(projectDir);\n const cmd = resolveCoreInstallCommand(manager);\n\n execSync(cmd, { cwd: projectDir, stdio: \"ignore\" });\n console.log(pc.green(\" ✓ Installed @fragments-sdk/core\"));\n } catch (e) {\n console.log(\n pc.yellow(\n ` ⚠ Could not auto-install @fragments-sdk/core: ${e instanceof Error ? e.message : String(e)}`\n )\n );\n }\n}\n\n/**\n * Add `**\\/*.fragment.tsx` to the exclude array of the project's tsconfig\n * so generated fragment files don't break the host app's TypeScript build.\n */\nexport async function excludeFragmentsFromTsconfig(scanPath: string): Promise<void> {\n const projectDir = await findNearestPackageJsonDir(scanPath);\n if (!projectDir) return;\n\n // Prefer tsconfig.app.json (Vite projects), fall back to tsconfig.json\n let tsconfigPath: string | null = null;\n let tsconfigName = \"\";\n for (const name of [\"tsconfig.app.json\", \"tsconfig.json\"]) {\n const candidate = join(projectDir, name);\n try {\n await access(candidate);\n tsconfigPath = candidate;\n tsconfigName = name;\n break;\n } catch {\n // try next\n }\n }\n\n if (!tsconfigPath) return;\n\n try {\n const raw = await readFile(tsconfigPath, \"utf-8\");\n const parsed = ts.parseConfigFileTextToJson(tsconfigPath, raw);\n if (parsed.error || !parsed.config) {\n throw new Error(parsed.error?.messageText?.toString() ?? \"Unable to parse tsconfig\");\n }\n const config = parsed.config as Record<string, unknown>;\n\n const exclude = Array.isArray(config.exclude) ? [...(config.exclude as string[])] : [];\n const ext = BRAND.fileExtension;\n const alreadyExcluded = exclude.some(\n (pattern: string) =>\n pattern.includes(`*${ext}`) || pattern.includes(\"*.fragment.*\") || pattern.includes(\"*.contract.*\")\n );\n\n if (alreadyExcluded) {\n console.log(\n pc.dim(` · ${ext} already excluded in ${tsconfigName}`)\n );\n return;\n }\n\n exclude.push(`**/*${ext}`);\n config.exclude = exclude;\n const updated = `${JSON.stringify(config, null, 2)}\\n`;\n\n await writeFile(tsconfigPath, updated, \"utf-8\");\n console.log(\n pc.green(` ✓ Added ${ext} exclusion to ${tsconfigName}`)\n );\n } catch (e) {\n console.log(\n pc.yellow(\n ` ⚠ Could not update ${tsconfigName}: ${e instanceof Error ? e.message : String(e)}`\n )\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Main orchestrator\n// ---------------------------------------------------------------------------\n\nexport async function scanGenerate(\n options: ScanGenerateOptions\n): Promise<ScanGenerateResult> {\n const scanPath = resolve(options.scanPath);\n const generated: ScanGenerateResult[\"generated\"] = [];\n const skipped: ScanGenerateResult[\"skipped\"] = [];\n const errors: ScanGenerateResult[\"errors\"] = [];\n\n console.log(pc.cyan(`\\n${BRAND.name} Scan → Generate\\n`));\n console.log(pc.dim(`Scanning: ${scanPath}\\n`));\n\n // Phase 1: Discover components\n console.log(pc.dim(\"Phase 1: Discovering components...\"));\n\n // Use broader patterns than default — the scan path IS the component root,\n // not a project root with src/components/ inside it\n const defaultScanPatterns = [\n \"**/*.tsx\",\n \"**/*.ts\",\n ];\n\n const components = await discoverAllComponents(scanPath, {\n patterns: options.patterns || defaultScanPatterns,\n exclude: [\n \"**/*.test.*\",\n \"**/*.spec.*\",\n \"**/*.stories.*\",\n \"**/*.fragment.*\",\n \"**/*.d.ts\",\n \"**/__tests__/**\",\n \"**/__mocks__/**\",\n \"**/node_modules/**\",\n \"**/dist/**\",\n ],\n });\n\n if (components.length === 0) {\n console.log(\n pc.yellow(\"No components found. Check the path or file patterns.\")\n );\n return {\n success: false,\n generated: [],\n skipped: [],\n errors: [{ name: \"*\", error: \"No components found\" }],\n averageConfidence: 0,\n };\n }\n\n console.log(pc.green(` Found ${components.length} components`));\n\n // Phase 2: Extract data for each component (persistent LanguageService)\n console.log(pc.dim(\"\\nPhase 2: Extracting component metadata...\"));\n\n // Create a single extractor that reuses its LanguageService across all components\n const extractor = createComponentExtractor(options.tsconfig);\n const componentDataList: ComponentData[] = [];\n\n const extractionStart = performance.now();\n\n for (const comp of components) {\n let meta: ComponentMeta | null = null;\n try {\n meta = extractor.extract(comp.sourcePath, comp.name);\n } catch {\n // Extraction can fail for complex types — continue gracefully\n }\n\n // Fallback compound detection for prefix-based patterns (e.g., shadcn-style\n // components that export CardHeader, CardFooter etc. as separate named exports\n // rather than using Object.assign)\n if (meta && !meta.composition) {\n try {\n const subComponents = await detectCompoundComponents(comp.sourcePath, comp.name);\n if (subComponents.length > 0) {\n meta = {\n ...meta,\n composition: {\n pattern: 'compound',\n parts: subComponents.map(name => ({ name, props: {} })),\n required: [],\n },\n };\n }\n } catch {\n // Non-fatal\n }\n }\n\n let storyVariants: StoryVariant[] = [];\n if (!options.skipStorybook && comp.storyPath) {\n try {\n storyVariants = await extractStoryVariantsFromFile(comp.storyPath);\n } catch {\n // Story extraction failure is non-fatal\n }\n }\n\n componentDataList.push({\n component: comp,\n meta,\n storyVariants,\n });\n }\n\n extractor.dispose();\n\n const extractionMs = (performance.now() - extractionStart).toFixed(0);\n const propsExtracted = componentDataList.filter(\n (d) => d.meta && Object.keys(d.meta.props).length > 0\n ).length;\n const compoundCount = componentDataList.filter(\n (d) => d.meta?.composition !== null\n ).length;\n console.log(pc.green(` Extracted props for ${propsExtracted} components (${extractionMs}ms)`));\n if (compoundCount > 0) {\n console.log(pc.green(` Detected ${compoundCount} compound component(s) with sub-component props`));\n }\n\n // Phase 3: Enrich with LLM (if --enrich)\n let enrichments = new Map<string, EnrichmentResult>();\n let enrichmentCost: number | undefined;\n\n if (options.enrich) {\n console.log(pc.dim(\"\\nPhase 3: Enriching with AI...\"));\n\n const enrichResult = await enrichComponents(componentDataList, {\n dryRun: options.dryRun,\n provider: options.provider,\n apiKey: options.apiKey,\n model: options.model,\n });\n\n enrichments = enrichResult.enrichments;\n\n if (enrichResult.model && enrichResult.totalInputTokens > 0) {\n const { calculateCost } = await import('../ai-client.js');\n enrichmentCost = calculateCost(\n enrichResult.model,\n enrichResult.totalInputTokens,\n enrichResult.totalOutputTokens\n );\n }\n }\n\n // Phase 4: Generate fragment files\n console.log(pc.dim(`\\nPhase ${options.enrich ? '4' : '3'}: Generating fragment files...`));\n\n for (const data of componentDataList) {\n const comp = data.component;\n const componentDir = dirname(comp.sourcePath);\n const componentBaseName = basename(comp.sourcePath, \".tsx\");\n\n // Determine output path\n let fragmentDir: string;\n if (options.outputDir) {\n fragmentDir = resolve(options.outputDir, comp.name);\n await mkdir(fragmentDir, { recursive: true });\n } else {\n fragmentDir = componentDir;\n }\n\n const fragmentPath = join(\n fragmentDir,\n `${componentBaseName}${BRAND.fileExtension}`\n );\n\n // Check if fragment already exists\n let fragmentExists = false;\n try {\n await access(fragmentPath);\n fragmentExists = true;\n } catch {\n // Doesn't exist\n }\n\n if (fragmentExists && !options.force) {\n skipped.push({ name: comp.name, reason: \"Fragment already exists\" });\n if (options.verbose) {\n console.log(pc.dim(` Skipping ${comp.name} (fragment exists)`));\n }\n continue;\n }\n\n try {\n // Look up enrichment for this component\n const enrichment = enrichments.get(comp.name);\n\n // Calculate confidence (enrichment boosts score)\n const confidence = calculateFieldConfidence(data, enrichment);\n\n // Compute import path\n const importPath = computeImportPath(\n fragmentDir,\n comp.sourcePath,\n componentBaseName\n );\n\n // Generate the fragment file — contract.json or legacy TSX\n let content: string;\n if (fragmentPath.endsWith('.contract.json')) {\n content = generateContractJsonFromScan(\n comp.name,\n componentBaseName,\n data,\n confidence,\n comp.sourcePath,\n scanPath,\n enrichment,\n );\n } else {\n content = generateFragmentWithTodos(\n comp.name,\n importPath,\n data,\n confidence,\n enrichment\n );\n }\n\n await writeFile(fragmentPath, content, \"utf-8\");\n\n const relPath = relative(process.cwd(), fragmentPath);\n generated.push({\n name: comp.name,\n path: relPath,\n confidence: confidence.score,\n todoCount: confidence.todoFields.length,\n enriched: !!enrichment,\n });\n\n const confColor =\n confidence.score >= 70\n ? pc.green\n : confidence.score >= 40\n ? pc.yellow\n : pc.red;\n console.log(\n pc.green(` ✓ ${comp.name}`) +\n pc.dim(` (confidence: `) +\n confColor(`${confidence.score}`) +\n pc.dim(`, TODOs: ${confidence.todoFields.length})`)\n );\n } catch (e) {\n errors.push({\n name: comp.name,\n error: e instanceof Error ? e.message : String(e),\n });\n console.log(pc.red(` ✗ ${comp.name}: ${e instanceof Error ? e.message : String(e)}`));\n }\n }\n\n // Post-generation setup: ensure @fragments-sdk/core is installed and\n // exclude .fragment.tsx files from the host project's tsconfig\n if (generated.length > 0) {\n await ensureCoreDependency(scanPath);\n await excludeFragmentsFromTsconfig(scanPath);\n }\n\n // Summary\n const avgConfidence =\n generated.length > 0\n ? Math.round(\n generated.reduce((sum, g) => sum + g.confidence, 0) /\n generated.length\n )\n : 0;\n\n console.log(pc.dim(\"\\n────────────────────────────────────────\"));\n console.log(pc.green(`\\n✓ Generated ${generated.length} fragment file(s)`));\n\n if (skipped.length > 0) {\n console.log(\n pc.dim(` Skipped ${skipped.length} (use --force to overwrite)`)\n );\n }\n if (errors.length > 0) {\n console.log(pc.yellow(` ${errors.length} error(s)`));\n }\n\n console.log(pc.dim(` Average confidence: ${avgConfidence}/100`));\n\n if (options.enrich) {\n const enrichedCount = generated.filter(g => g.enriched).length;\n console.log(pc.dim(` Enriched: ${enrichedCount}/${generated.length} components`));\n if (enrichmentCost !== undefined && enrichmentCost > 0) {\n console.log(pc.dim(` Estimated cost: $${enrichmentCost.toFixed(4)}`));\n }\n }\n\n const totalTodos = generated.reduce((sum, g) => sum + g.todoCount, 0);\n if (totalTodos > 0) {\n console.log(\n pc.dim(` Total TODOs: ${totalTodos}`) +\n pc.dim(` — search for \"TODO:\" in generated files`)\n );\n }\n\n console.log();\n\n return {\n success: errors.length === 0,\n generated,\n skipped,\n errors,\n averageConfidence: avgConfidence,\n enrichmentCost,\n };\n}\n\n// ---------------------------------------------------------------------------\n// JSDoc Extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the JSDoc description from a component's exported declaration.\n * Uses TypeScript AST — no program needed, just source file parsing.\n */\nexport async function extractComponentJSDoc(\n filePath: string,\n componentName?: string\n): Promise<string | null> {\n const content = await readFile(filePath, \"utf-8\");\n return extractComponentJSDocFromSource(content, filePath, componentName);\n}\n\nexport function extractComponentJSDocFromSource(\n source: string,\n filePath: string,\n componentName?: string\n): string | null {\n const sourceFile = ts.createSourceFile(\n filePath,\n source,\n ts.ScriptTarget.ESNext,\n true,\n filePath.endsWith(\".tsx\") ? ts.ScriptKind.TSX : ts.ScriptKind.TS\n );\n\n const targetName =\n componentName || basename(filePath).replace(/\\.(tsx?|jsx?)$/, \"\");\n\n let componentDoc: string | null = null;\n let propsInterfaceDoc: string | null = null;\n\n for (const statement of sourceFile.statements) {\n // export function ComponentName(...)\n if (\n ts.isFunctionDeclaration(statement) &&\n statement.name?.text === targetName &&\n hasExportModifier(statement)\n ) {\n const doc = getLeadingJSDoc(statement, sourceFile);\n if (doc) componentDoc = doc;\n }\n\n // export const ComponentName = ...\n if (\n ts.isVariableStatement(statement) &&\n hasExportModifier(statement)\n ) {\n for (const decl of statement.declarationList.declarations) {\n if (ts.isIdentifier(decl.name) && decl.name.text === targetName) {\n const doc = getLeadingJSDoc(statement, sourceFile);\n if (doc) componentDoc = doc;\n }\n }\n }\n\n // export default function ...\n if (\n ts.isFunctionDeclaration(statement) &&\n hasDefaultExportModifier(statement)\n ) {\n const doc = getLeadingJSDoc(statement, sourceFile);\n if (doc) componentDoc = doc;\n }\n\n // Fallback: JSDoc on the {Name}Props interface\n if (\n ts.isInterfaceDeclaration(statement) &&\n (statement.name.text === `${targetName}Props` ||\n statement.name.text === `${targetName}Properties`)\n ) {\n const doc = getLeadingJSDoc(statement, sourceFile);\n if (doc) propsInterfaceDoc = doc;\n }\n }\n\n // Prefer component-level JSDoc; fall back to props interface JSDoc\n return componentDoc || propsInterfaceDoc;\n}\n\nfunction hasExportModifier(node: ts.Node): boolean {\n const modifiers = ts.canHaveModifiers(node)\n ? ts.getModifiers(node)\n : undefined;\n return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;\n}\n\nfunction hasDefaultExportModifier(node: ts.Node): boolean {\n const modifiers = ts.canHaveModifiers(node)\n ? ts.getModifiers(node)\n : undefined;\n if (!modifiers) return false;\n return (\n modifiers.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) &&\n modifiers.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword)\n );\n}\n\nfunction getLeadingJSDoc(\n node: ts.Node,\n sourceFile: ts.SourceFile\n): string | null {\n const fullText = sourceFile.getFullText();\n const nodeStart = node.getFullStart();\n const nodePos = node.getStart(sourceFile);\n const leadingText = fullText.slice(nodeStart, nodePos);\n\n const jsDocMatch = leadingText.match(/\\/\\*\\*([\\s\\S]*?)\\*\\//);\n if (!jsDocMatch) return null;\n\n // Parse JSDoc content — extract description lines, skip tags\n const lines = jsDocMatch[1].split(\"\\n\");\n const descriptionLines: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.replace(/^\\s*\\*?\\s?/, \"\").trim();\n if (trimmed.startsWith(\"@\")) break; // Stop at first tag\n if (trimmed) descriptionLines.push(trimmed);\n }\n\n return descriptionLines.length > 0\n ? descriptionLines.join(\" \")\n : null;\n}\n\n// ---------------------------------------------------------------------------\n// Compound Component Detection\n// ---------------------------------------------------------------------------\n\n/**\n * Detect compound component patterns (Object.assign) in a source file.\n * Returns the names of sub-components found.\n */\nexport async function detectCompoundComponents(\n filePath: string,\n primaryComponentName?: string\n): Promise<string[]> {\n const content = await readFile(filePath, \"utf-8\");\n return detectCompoundComponentsFromSource(content, filePath, primaryComponentName);\n}\n\nexport function detectCompoundComponentsFromSource(\n source: string,\n filePath: string,\n primaryComponentName?: string\n): string[] {\n const sourceFile = ts.createSourceFile(\n filePath,\n source,\n ts.ScriptTarget.ESNext,\n true,\n filePath.endsWith(\".tsx\") ? ts.ScriptKind.TSX : ts.ScriptKind.TS\n );\n\n const subComponents: string[] = [];\n\n function visit(node: ts.Node) {\n // Look for Object.assign(Root, { Sub1, Sub2 }) or Object.assign(Root, { Sub1: SubComponent })\n if (\n ts.isCallExpression(node) &&\n ts.isPropertyAccessExpression(node.expression) &&\n ts.isIdentifier(node.expression.expression) &&\n node.expression.expression.text === \"Object\" &&\n node.expression.name.text === \"assign\" &&\n node.arguments.length >= 2\n ) {\n const secondArg = node.arguments[1];\n if (ts.isObjectLiteralExpression(secondArg)) {\n for (const prop of secondArg.properties) {\n if (ts.isShorthandPropertyAssignment(prop)) {\n subComponents.push(prop.name.text);\n } else if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name)\n ) {\n subComponents.push(prop.name.text);\n }\n }\n }\n }\n\n ts.forEachChild(node, visit);\n }\n\n ts.forEachChild(sourceFile, visit);\n\n // Fallback: detect shadcn-style compound exports.\n // Libraries like shadcn/ui export compound sub-components as separate named exports\n // that share a prefix: export { Card, CardHeader, CardContent, CardFooter }\n // Detect these by finding PascalCase exports that start with the primary component name.\n if (subComponents.length === 0 && primaryComponentName) {\n const exportedNames: string[] = [];\n\n // Find export { Name1, Name2, ... } blocks\n for (const statement of sourceFile.statements) {\n if (ts.isExportDeclaration(statement) && statement.exportClause) {\n if (ts.isNamedExports(statement.exportClause)) {\n for (const element of statement.exportClause.elements) {\n exportedNames.push(element.name.text);\n }\n }\n }\n // Also catch `export function CardHeader` / `export const CardHeader`\n if (ts.isFunctionDeclaration(statement) && statement.name) {\n const modifiers = ts.canHaveModifiers(statement) ? ts.getModifiers(statement) : undefined;\n if (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {\n exportedNames.push(statement.name.text);\n }\n }\n if (ts.isVariableStatement(statement)) {\n const modifiers = ts.canHaveModifiers(statement) ? ts.getModifiers(statement) : undefined;\n if (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {\n for (const decl of statement.declarationList.declarations) {\n if (ts.isIdentifier(decl.name)) {\n exportedNames.push(decl.name.text);\n }\n }\n }\n }\n }\n\n // Find exports that start with primaryComponentName but aren't the primary itself\n // e.g., \"Card\" → [\"CardHeader\", \"CardFooter\", \"CardContent\", \"CardTitle\"]\n const prefix = primaryComponentName;\n for (const name of exportedNames) {\n if (\n name !== prefix &&\n name.startsWith(prefix) &&\n /^[A-Z]/.test(name.slice(prefix.length))\n ) {\n // Strip the prefix to get the sub-component name\n const subName = name.slice(prefix.length);\n subComponents.push(subName);\n }\n }\n }\n\n return subComponents;\n}\n\n// ---------------------------------------------------------------------------\n// Story Variant Extraction (lightweight, from generate.ts patterns)\n// ---------------------------------------------------------------------------\n\nasync function extractStoryVariantsFromFile(\n storyPath: string\n): Promise<StoryVariant[]> {\n const content = await readFile(storyPath, \"utf-8\");\n const variants: StoryVariant[] = [];\n\n const exportMatches = content.matchAll(\n /export\\s+const\\s+([A-Z][a-zA-Z0-9]*)\\s*[=:]/g\n );\n\n for (const match of exportMatches) {\n const name = match[1];\n if (name === \"default\" || name.endsWith(\"Args\") || name.endsWith(\"Meta\")) {\n continue;\n }\n\n const args = extractStoryArgs(content, name);\n variants.push({ name, args });\n }\n\n return variants;\n}\n\nfunction extractStoryArgs(\n content: string,\n storyName: string\n): Record<string, unknown> {\n const storyPattern = new RegExp(\n `export\\\\s+const\\\\s+${storyName}[^=]*=\\\\s*\\\\{([\\\\s\\\\S]*?)\\\\n\\\\};`\n );\n const storyMatch = content.match(storyPattern);\n if (!storyMatch) return {};\n\n const storyBody = storyMatch[1];\n const argsStart = storyBody.indexOf(\"args:\");\n if (argsStart === -1) return {};\n\n const braceStart = storyBody.indexOf(\"{\", argsStart);\n if (braceStart === -1) return {};\n\n let depth = 0;\n let braceEnd = -1;\n for (let i = braceStart; i < storyBody.length; i++) {\n if (storyBody[i] === \"{\") depth++;\n else if (storyBody[i] === \"}\") {\n depth--;\n if (depth === 0) {\n braceEnd = i;\n break;\n }\n }\n }\n if (braceEnd === -1) return {};\n\n const argsBlock = storyBody.slice(braceStart + 1, braceEnd).trim();\n return parseArgsBlock(argsBlock);\n}\n\nfunction parseArgsBlock(argsBlock: string): Record<string, unknown> {\n const args: Record<string, unknown> = {};\n const pairPattern =\n /(\\w+)\\s*:\\s*(?:['\"]([^'\"]*?)['\"]|(true|false)|(\\d+(?:\\.\\d+)?))/g;\n let pairMatch: RegExpExecArray | null;\n\n while ((pairMatch = pairPattern.exec(argsBlock)) !== null) {\n const key = pairMatch[1];\n if (pairMatch[2] !== undefined) {\n args[key] = pairMatch[2];\n } else if (pairMatch[3] !== undefined) {\n args[key] = pairMatch[3] === \"true\";\n } else if (pairMatch[4] !== undefined) {\n args[key] = Number(pairMatch[4]);\n }\n }\n\n return args;\n}\n\n// ---------------------------------------------------------------------------\n// Enrichment: LLM-powered knowledge field generation\n// ---------------------------------------------------------------------------\n\nexport function buildEnrichmentSystemPrompt(): string {\n return `You are a senior frontend architect and design system expert.\nGiven a component's metadata (name, description, props, composition), generate knowledge fields that help AI models use the component correctly.\n\nRespond ONLY with a JSON object. No explanation, no markdown outside the JSON.\n\nThe JSON must have exactly these fields:\n{\n \"when\": [\"...\"], // 3-5 scenarios when this component should be used\n \"whenNot\": [\"...\"], // 2-4 scenarios when NOT to use this component (suggest alternatives)\n \"guidelines\": [\"...\"], // 2-3 usage guidelines or best practices\n \"a11yRules\": [\"...\"], // 2-4 accessibility rules or requirements\n \"scenarioTags\": [\"...\"], // 3-5 dot-notation scenario tags (e.g., \"form.input.text\", \"layout.container.card\")\n \"tags\": [\"...\"] // 3-5 search keywords for component discovery\n}\n\nRules:\n- \"when\" items should describe concrete UI scenarios (e.g., \"Displaying grouped content with a header, body, and footer\")\n- \"whenNot\" items should name a better alternative (e.g., \"Simple text grouping without visual separation — use a div or Stack instead\")\n- \"guidelines\" should be actionable best practices\n- \"a11yRules\" should reference WCAG or ARIA patterns where relevant\n- \"scenarioTags\" use dot notation: category.subcategory.detail\n- \"tags\" should be lowercase single words or short phrases for search\n- Keep each item to 1 sentence. Be specific, not generic.`;\n}\n\nexport function buildEnrichmentUserPrompt(\n name: string,\n data: ComponentData\n): string {\n const props = data.meta?.props ?? {};\n const fragmentProps = getFragmentPropEntries(props);\n const composition = data.meta?.composition ?? null;\n const description = data.meta?.description || '';\n const category = inferCategoryFromMeta(\n name,\n Object.fromEntries(fragmentProps)\n );\n\n const lines: string[] = [\n `Component: ${name}`,\n `Category: ${category}`,\n ];\n\n if (description) {\n lines.push(`Description: ${description}`);\n }\n\n if (fragmentProps.length > 0) {\n lines.push('');\n lines.push('Props:');\n for (const [propName, prop] of fragmentProps) {\n let propLine = ` - ${propName}: ${prop.typeKind}`;\n if (prop.values && prop.values.length > 0) {\n propLine += ` (${prop.values.join(' | ')})`;\n }\n if (prop.required) propLine += ' [required]';\n if (prop.description) propLine += ` — ${prop.description}`;\n lines.push(propLine);\n }\n }\n\n if (composition && composition.parts.length > 0) {\n lines.push('');\n lines.push(`Composition: ${composition.pattern} pattern`);\n lines.push(`Sub-components: ${composition.parts.map(p => p.name).join(', ')}`);\n }\n\n if (data.storyVariants.length > 0) {\n lines.push('');\n lines.push(`Known variants: ${data.storyVariants.map(v => v.name).join(', ')}`);\n }\n\n return lines.join('\\n');\n}\n\nexport function parseEnrichmentResponse(text: string): EnrichmentResult {\n const empty: EnrichmentResult = {\n when: [],\n whenNot: [],\n guidelines: [],\n a11yRules: [],\n scenarioTags: [],\n tags: [],\n };\n\n try {\n // Parse JSON from response, handling ```json fences\n const jsonMatch = text.match(/```json\\n?([\\s\\S]*?)\\n?```/) || text.match(/\\{[\\s\\S]*\\}/);\n const jsonStr = jsonMatch ? (jsonMatch[1] || jsonMatch[0]) : text;\n const parsed = JSON.parse(jsonStr) as Record<string, unknown>;\n\n const getArray = (key: string, maxLen: number): string[] => {\n const val = parsed[key];\n if (!Array.isArray(val)) return [];\n return val\n .filter((item): item is string => typeof item === 'string')\n .slice(0, maxLen);\n };\n\n return {\n when: getArray('when', 5),\n whenNot: getArray('whenNot', 4),\n guidelines: getArray('guidelines', 3),\n a11yRules: getArray('a11yRules', 4),\n scenarioTags: getArray('scenarioTags', 5),\n tags: getArray('tags', 5),\n };\n } catch {\n return empty;\n }\n}\n\nasync function enrichComponents(\n componentDataList: ComponentData[],\n options: Pick<ScanGenerateOptions, 'dryRun' | 'provider' | 'apiKey' | 'model'>\n): Promise<{\n enrichments: Map<string, EnrichmentResult>;\n totalInputTokens: number;\n totalOutputTokens: number;\n model: string;\n}> {\n const enrichments = new Map<string, EnrichmentResult>();\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n\n const {\n detectProvider,\n getApiKey,\n createAIClient,\n generateCompletion,\n ENRICHMENT_MODELS,\n } = await import('../ai-client.js');\n\n const provider = detectProvider({ provider: options.provider, apiKey: options.apiKey });\n if (provider === 'none') {\n console.log(pc.yellow(' No API key found. Set ANTHROPIC_API_KEY or OPENAI_API_KEY, or use --api-key'));\n console.log(pc.yellow(' Skipping enrichment — fragment files will have TODO markers instead.\\n'));\n return { enrichments, totalInputTokens: 0, totalOutputTokens: 0, model: '' };\n }\n\n const apiKey = getApiKey(provider, options.apiKey);\n if (!apiKey) {\n console.log(pc.yellow(' API key not found for provider: ' + provider));\n console.log(pc.yellow(' Skipping enrichment.\\n'));\n return { enrichments, totalInputTokens: 0, totalOutputTokens: 0, model: '' };\n }\n\n const model = options.model || ENRICHMENT_MODELS[provider];\n\n if (options.dryRun) {\n for (const data of componentDataList) {\n console.log(pc.dim(` Would enrich: ${data.component.name}`));\n }\n return { enrichments, totalInputTokens: 0, totalOutputTokens: 0, model };\n }\n\n const client = await createAIClient(provider, apiKey);\n const systemPrompt = buildEnrichmentSystemPrompt();\n\n for (const data of componentDataList) {\n const name = data.component.name;\n process.stdout.write(pc.dim(` Enriching ${name}...`));\n\n try {\n const userPrompt = buildEnrichmentUserPrompt(name, data);\n const result = await generateCompletion(client, provider, model, systemPrompt, userPrompt, 512);\n\n totalInputTokens += result.inputTokens;\n totalOutputTokens += result.outputTokens;\n\n const enrichment = parseEnrichmentResponse(result.text);\n const fieldCount =\n enrichment.when.length +\n enrichment.whenNot.length +\n enrichment.guidelines.length +\n enrichment.a11yRules.length +\n enrichment.scenarioTags.length +\n enrichment.tags.length;\n\n enrichments.set(name, enrichment);\n process.stdout.write(`\\r ${pc.green('✓')} ${name} (${fieldCount} fields)\\n`);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stdout.write(`\\r ${pc.yellow('!')} ${name}: ${msg}\\n`);\n }\n }\n\n return { enrichments, totalInputTokens, totalOutputTokens, model };\n}\n\nexport function buildEnrichedUsageBlock(enrichment: EnrichmentResult): string {\n const lines: string[] = [];\n lines.push(' usage: {');\n\n if (enrichment.when.length > 0) {\n lines.push(' when: [');\n for (const item of enrichment.when) {\n lines.push(` '${escapeQuotes(item)}',`);\n }\n lines.push(' ],');\n } else {\n lines.push(' when: [],');\n }\n\n if (enrichment.whenNot.length > 0) {\n lines.push(' whenNot: [');\n for (const item of enrichment.whenNot) {\n lines.push(` '${escapeQuotes(item)}',`);\n }\n lines.push(' ],');\n } else {\n lines.push(' whenNot: [],');\n }\n\n if (enrichment.guidelines.length > 0) {\n lines.push(' guidelines: [');\n for (const item of enrichment.guidelines) {\n lines.push(` '${escapeQuotes(item)}',`);\n }\n lines.push(' ],');\n }\n\n lines.push(' },');\n return lines.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Confidence Scoring\n// ---------------------------------------------------------------------------\n\nexport function calculateFieldConfidence(\n data: ComponentData,\n enrichment?: EnrichmentResult\n): FieldConfidence {\n let score = 0;\n const todoFields: string[] = [];\n\n const props = data.meta?.props ?? {};\n const fragmentPropEntries = getFragmentPropEntries(props);\n const hasProps = fragmentPropEntries.length > 0;\n\n // Props extracted: +30\n if (hasProps) {\n score += 30;\n }\n\n // JSDoc description found: +15\n if (data.meta?.description) {\n score += 15;\n } else {\n todoFields.push(\"meta.description\");\n }\n\n // Category inferred from path/name (not fallback): +10\n const fragmentProps = Object.fromEntries(fragmentPropEntries);\n const category = inferCategoryFromMeta(data.component.name, fragmentProps);\n if (category !== \"Components\") {\n score += 10;\n } else {\n todoFields.push(\"meta.category\");\n }\n\n // Story variants found: +25\n if (data.storyVariants.length > 0) {\n score += 25;\n }\n\n // All prop types resolved (no \"custom\"): +10\n if (hasProps) {\n const allResolved = fragmentPropEntries.every(([_, p]) => p.typeKind !== \"custom\");\n if (allResolved) {\n score += 10;\n }\n }\n\n // Compound component detected with sub-component props: +10\n if (data.meta?.composition && data.meta.composition.parts.length > 0) {\n score += 10;\n }\n\n // Has default values: +5\n if (hasProps) {\n const hasDefaults = fragmentPropEntries.some(([_, p]) => p.default !== undefined);\n if (hasDefaults) {\n score += 5;\n }\n }\n\n // Enrichment bonuses — if LLM filled these, they're no longer TODOs\n if (enrichment && enrichment.when.length > 0) {\n score += 10;\n } else {\n todoFields.push(\"usage.when\");\n }\n\n if (enrichment && enrichment.whenNot.length > 0) {\n score += 5;\n } else {\n todoFields.push(\"usage.whenNot\");\n }\n\n if (enrichment && enrichment.guidelines.length > 0) {\n score += 5;\n }\n\n if (enrichment && enrichment.tags.length > 0) {\n score += 5;\n }\n\n return { score: Math.min(score, 100), todoFields };\n}\n\n// ---------------------------------------------------------------------------\n// Category / Status / Description inference (adapted from generate.ts + scan.ts)\n// ---------------------------------------------------------------------------\n\nconst CATEGORY_PATTERNS: Record<string, string[]> = {\n Actions: [\"button\", \"action\", \"cta\", \"fab\", \"floatingaction\"],\n Forms: [\n \"form\", \"input\", \"select\", \"checkbox\", \"radio\", \"textarea\", \"field\",\n \"textfield\", \"datepicker\", \"switch\", \"slider\", \"segmented\",\n ],\n Layout: [\n \"layout\", \"container\", \"grid\", \"flex\", \"stack\", \"box\", \"divider\", \"spacer\",\n \"sidebar\",\n ],\n Navigation: [\n \"nav\", \"menu\", \"breadcrumb\", \"tab\", \"link\", \"pagination\", \"stepper\",\n \"topbar\",\n ],\n Feedback: [\n \"alert\", \"toast\", \"notification\", \"message\", \"badge\", \"indicator\",\n \"progress\", \"spinner\", \"loading\", \"loader\", \"lozenge\", \"chip\",\n ],\n \"Data Display\": [\n \"table\", \"list\", \"card\", \"avatar\", \"stat\", \"timeline\", \"tree\", \"datalist\",\n \"datacard\",\n ],\n Overlays: [\n \"modal\", \"dialog\", \"drawer\", \"popover\", \"tooltip\", \"dropdown\",\n \"slidepanel\",\n ],\n Typography: [\"text\", \"heading\", \"title\", \"label\", \"paragraph\"],\n Media: [\"image\", \"video\", \"icon\", \"carousel\"],\n};\n\nfunction inferCategoryFromMeta(\n componentName: string,\n props: Record<string, PropMeta>\n): string {\n const lower = componentName.toLowerCase();\n\n for (const [category, patterns] of Object.entries(CATEGORY_PATTERNS)) {\n for (const pattern of patterns) {\n if (lower.includes(pattern)) {\n return category;\n }\n }\n }\n\n // Prop-based fallbacks\n const propNames = new Set(Object.keys(props));\n if (propNames.has(\"onClick\") || propNames.has(\"onPress\")) return \"Actions\";\n if (propNames.has(\"value\") || propNames.has(\"defaultValue\")) return \"Forms\";\n if (propNames.has(\"children\")) return \"Layout\";\n\n return \"Components\";\n}\n\nfunction inferStatus(\n filePath: string\n): \"draft\" | \"experimental\" | \"beta\" | \"stable\" | \"deprecated\" {\n const lowerPath = filePath.toLowerCase();\n if (lowerPath.includes(\"/experimental/\") || lowerPath.includes(\"/labs/\"))\n return \"experimental\";\n if (lowerPath.includes(\"/beta/\")) return \"beta\";\n if (lowerPath.includes(\"/deprecated/\") || lowerPath.includes(\"/legacy/\"))\n return \"deprecated\";\n if (lowerPath.includes(\"/draft/\") || lowerPath.includes(\"/wip/\"))\n return \"draft\";\n return \"stable\";\n}\n\nfunction inferDescriptionFromMeta(\n componentName: string,\n props: Record<string, PropMeta>\n): string {\n const words = componentName\n .replace(/([A-Z])/g, \" $1\")\n .trim()\n .toLowerCase();\n\n const propNames = new Set(Object.keys(props));\n const hasOnClick =\n propNames.has(\"onClick\") || propNames.has(\"onPress\");\n const hasValue =\n propNames.has(\"value\") || propNames.has(\"defaultValue\");\n const hasChildren = propNames.has(\"children\");\n\n if (hasOnClick && !hasValue)\n return `Interactive ${words} element for triggering actions`;\n if (hasValue) return `Form ${words} for user input`;\n if (hasChildren) return `Container ${words} for grouping content`;\n return `${words.charAt(0).toUpperCase() + words.slice(1)} component`;\n}\n\nfunction inferAccessibilityFromMeta(props: Record<string, PropMeta>): {\n role?: string;\n requirements?: string[];\n} {\n const propNames = new Set(Object.keys(props));\n const accessibility: { role?: string; requirements?: string[] } = {};\n\n const hasOnClick =\n propNames.has(\"onClick\") || propNames.has(\"onPress\");\n const hasAriaLabel =\n propNames.has(\"ariaLabel\") || propNames.has(\"aria-label\");\n const hasDisabled = propNames.has(\"disabled\");\n const hasHref = propNames.has(\"href\");\n\n if (hasOnClick && !hasHref) accessibility.role = \"button\";\n else if (hasHref) accessibility.role = \"link\";\n\n const requirements: string[] = [];\n if (hasOnClick && !hasAriaLabel)\n requirements.push(\"Should have visible text or aria-label\");\n if (hasDisabled)\n requirements.push(\n \"Disabled state should be conveyed to assistive technology\"\n );\n if (requirements.length > 0) accessibility.requirements = requirements;\n\n return accessibility;\n}\n\n// ---------------------------------------------------------------------------\n// Contract Block Generation\n// ---------------------------------------------------------------------------\n\ninterface ContractBlock {\n propsSummary: string[];\n compoundChildren?: Record<string, {\n required?: boolean;\n accepts?: string[];\n description?: string;\n }>;\n canonicalUsage?: string[];\n a11yRules?: string[];\n scenarioTags?: string[];\n}\n\nconst INHERITED_PROP_PRIORITY = [\n \"htmlFor\",\n \"type\",\n \"value\",\n \"defaultValue\",\n \"checked\",\n \"defaultChecked\",\n \"disabled\",\n \"required\",\n \"placeholder\",\n \"name\",\n \"id\",\n \"form\",\n \"accept\",\n \"multiple\",\n \"min\",\n \"max\",\n \"step\",\n \"pattern\",\n \"role\",\n \"children\",\n] as const;\n\nfunction getFragmentPropEntries(props: Record<string, PropMeta>): Array<[string, PropMeta]> {\n const entries = Object.entries(props);\n const localEntries = entries.filter(([_, prop]) => prop.source === \"local\");\n if (localEntries.length > 0) {\n return localEntries;\n }\n\n const prioritized = new Set(INHERITED_PROP_PRIORITY);\n const inheritedEntries = entries\n .filter(([name, prop]) => {\n if (prop.source !== \"inherited\") return false;\n if (name === \"key\" || name === \"ref\" || name === \"className\" || name === \"style\") return false;\n if (name.startsWith(\"on\")) return false;\n if (name.startsWith(\"aria-\") || name.startsWith(\"data-\")) return false;\n return prioritized.has(name as typeof INHERITED_PROP_PRIORITY[number]);\n })\n .sort(([nameA], [nameB]) => {\n const rankA = INHERITED_PROP_PRIORITY.indexOf(nameA as typeof INHERITED_PROP_PRIORITY[number]);\n const rankB = INHERITED_PROP_PRIORITY.indexOf(nameB as typeof INHERITED_PROP_PRIORITY[number]);\n return rankA - rankB;\n });\n\n return inheritedEntries.slice(0, 8);\n}\n\nfunction buildContractBlock(\n componentName: string,\n props: Record<string, PropMeta>,\n composition: CompositionMeta | null,\n accessibility: { role?: string; requirements?: string[] },\n compoundPartRefs: CompoundPartReference[] = []\n): ContractBlock | null {\n const relevantEntries = getFragmentPropEntries(props);\n if (relevantEntries.length === 0 && !composition && !accessibility.requirements?.length) {\n return null;\n }\n\n const contract: ContractBlock = { propsSummary: [] };\n\n // propsSummary: \"propName: value1 | value2 | value3\" for enums, \"propName: type\" otherwise\n for (const [name, prop] of relevantEntries) {\n let summary = name + ': ';\n if (prop.typeKind === 'enum' && prop.values && prop.values.length > 0) {\n summary += prop.values.join(' | ');\n } else {\n summary += prop.typeKind;\n }\n if (prop.required) summary += ' (required)';\n if (prop.default !== undefined) summary += ` (default: ${prop.default})`;\n contract.propsSummary.push(summary);\n }\n\n // compoundChildren: built from CompositionMeta.parts[]\n if (composition && composition.parts.length > 0) {\n const children: Record<string, { required?: boolean; accepts?: string[]; description?: string }> = {};\n for (const part of composition.parts) {\n const childEntry: { required?: boolean; accepts?: string[]; description?: string } = {};\n if (composition.required.includes(part.name)) {\n childEntry.required = true;\n }\n // Infer accepts from ReactNode-type props on the sub-component\n const nodeProps = Object.entries(part.props)\n .filter(([_, p]) => p.typeKind === 'node' || p.typeKind === 'element')\n .map(([n]) => n);\n if (nodeProps.length > 0) {\n childEntry.accepts = nodeProps;\n }\n children[part.name] = childEntry;\n }\n contract.compoundChildren = children;\n }\n\n // canonicalUsage: generate 1 JSX snippet using actual component + sub-component names\n if (composition && composition.parts.length > 0) {\n const resolvedParts = compoundPartRefs.length > 0\n ? compoundPartRefs\n : composition.parts.map((part) => ({ partName: part.name, tagName: `${componentName}.${part.name}` }));\n\n const innerLines = resolvedParts\n .map((part) => ` <${part.tagName}>...</${part.tagName}>`)\n .join('\\n');\n contract.canonicalUsage = [\n `<${componentName}>\\n${innerLines}\\n</${componentName}>`,\n ];\n }\n\n // a11yRules: from accessibility inference\n const rules: string[] = [];\n if (accessibility.role) {\n rules.push(`Role: ${accessibility.role}`);\n }\n if (accessibility.requirements) {\n rules.push(...accessibility.requirements);\n }\n if (rules.length > 0) {\n contract.a11yRules = rules;\n }\n\n return contract;\n}\n\nfunction emitContractBlock(contract: ContractBlock): string {\n const lines: string[] = [];\n lines.push('\\n contract: {');\n\n // propsSummary\n if (contract.propsSummary.length > 0) {\n lines.push(' propsSummary: [');\n for (const s of contract.propsSummary) {\n lines.push(` '${escapeQuotes(s)}',`);\n }\n lines.push(' ],');\n }\n\n // compoundChildren\n if (contract.compoundChildren && Object.keys(contract.compoundChildren).length > 0) {\n lines.push(' compoundChildren: {');\n for (const [name, meta] of Object.entries(contract.compoundChildren)) {\n const fields: string[] = [];\n if (meta.required) fields.push(`required: true`);\n if (meta.accepts && meta.accepts.length > 0) {\n fields.push(`accepts: [${meta.accepts.map(a => `'${a}'`).join(', ')}]`);\n }\n if (meta.description) fields.push(`description: '${escapeQuotes(meta.description)}'`);\n lines.push(` ${name}: { ${fields.join(', ')} },`);\n }\n lines.push(' },');\n }\n\n // canonicalUsage\n if (contract.canonicalUsage && contract.canonicalUsage.length > 0) {\n lines.push(' canonicalUsage: [');\n for (const usage of contract.canonicalUsage) {\n lines.push(` \\`${usage}\\`,`);\n }\n lines.push(' ],');\n }\n\n // a11yRules\n if (contract.a11yRules && contract.a11yRules.length > 0) {\n lines.push(' a11yRules: [');\n for (const rule of contract.a11yRules) {\n lines.push(` '${escapeQuotes(rule)}',`);\n }\n lines.push(' ],');\n }\n\n // scenarioTags\n if (contract.scenarioTags && contract.scenarioTags.length > 0) {\n lines.push(' scenarioTags: [');\n for (const tag of contract.scenarioTags) {\n lines.push(` '${escapeQuotes(tag)}',`);\n }\n lines.push(' ],');\n }\n\n lines.push(' },');\n return lines.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Import path computation\n// ---------------------------------------------------------------------------\n\nfunction computeImportPath(\n fragmentDir: string,\n sourcePath: string,\n componentBaseName: string\n): string {\n const sourceDir = dirname(sourcePath);\n\n // Colocated: fragment sits next to the source file\n if (fragmentDir === sourceDir) {\n // If source is index.tsx, import from '.'\n if (componentBaseName === \"index\") {\n return \".\";\n }\n return `./${componentBaseName}`;\n }\n\n // Different directory: compute relative path\n let rel = relative(fragmentDir, sourceDir);\n if (!rel.startsWith(\".\")) rel = `./${rel}`;\n if (componentBaseName !== \"index\") {\n rel = `${rel}/${componentBaseName}`;\n }\n return rel;\n}\n\n// ---------------------------------------------------------------------------\n// Fragment file generation with TODO markers\n// ---------------------------------------------------------------------------\n\nfunction escapeQuotes(str: string): string {\n return str.replace(/'/g, \"\\\\'\");\n}\n\nfunction resolveCompoundPartReferences(\n componentName: string,\n composition: CompositionMeta | null,\n exportNames: string[]\n): CompoundPartReference[] {\n if (!composition || composition.parts.length === 0) return [];\n\n return composition.parts.map((part) => {\n const directExportName = `${componentName}${part.name}`;\n if (exportNames.includes(directExportName)) {\n return {\n partName: part.name,\n tagName: directExportName,\n importName: directExportName,\n };\n }\n\n return {\n partName: part.name,\n tagName: `${componentName}.${part.name}`,\n };\n });\n}\n\nfunction generateFragmentWithTodos(\n componentName: string,\n importPath: string,\n data: ComponentData,\n confidence: FieldConfidence,\n enrichment?: EnrichmentResult\n): string {\n const props = data.meta?.props ?? {};\n const localProps = Object.fromEntries(\n Object.entries(props).filter(([_, p]) => p.source === 'local')\n );\n const fragmentProps = Object.fromEntries(getFragmentPropEntries(props));\n const inferenceProps = Object.keys(localProps).length > 0 ? localProps : fragmentProps;\n const composition = data.meta?.composition ?? null;\n const description = data.meta?.description || inferDescriptionFromMeta(componentName, inferenceProps);\n const descriptionTodo = data.meta?.description ? \"\" : \" // TODO: Review description\";\n const category = inferCategoryFromMeta(componentName, inferenceProps);\n const categoryTodo = category === \"Components\" ? \" // TODO: Set correct category\" : \"\";\n const status = inferStatus(data.component.sourcePath);\n const accessibility = inferAccessibilityFromMeta(inferenceProps);\n const exportNames = data.meta?.exports ?? [];\n const compoundPartRefs = resolveCompoundPartReferences(componentName, composition, exportNames);\n const importNames = Array.from(\n new Set([\n componentName,\n ...compoundPartRefs.flatMap((part) => (part.importName ? [part.importName] : [])),\n ])\n );\n\n // Build props block from PropMeta\n const propsBlock = buildPropsBlockFromMeta(props);\n\n // Build contract block — enrichment can replace/augment a11yRules and add scenarioTags\n const contract = buildContractBlock(\n componentName,\n props,\n composition,\n accessibility,\n compoundPartRefs\n );\n if (contract && enrichment) {\n if (enrichment.a11yRules.length > 0) {\n contract.a11yRules = enrichment.a11yRules;\n }\n if (enrichment.scenarioTags.length > 0) {\n contract.scenarioTags = enrichment.scenarioTags;\n }\n }\n const contractBlock = contract ? emitContractBlock(contract) : '';\n\n // Build usage block — enriched or TODO markers\n let usageBlock: string;\n if (enrichment && (enrichment.when.length > 0 || enrichment.whenNot.length > 0)) {\n usageBlock = buildEnrichedUsageBlock(enrichment);\n } else {\n usageBlock = ` usage: {\n when: [\n // TODO: Describe when to use ${componentName}\n ],\n whenNot: [\n // TODO: Describe when NOT to use ${componentName}\n ],\n },`;\n }\n\n // Build meta.tags from enrichment\n const tagsLine = enrichment && enrichment.tags.length > 0\n ? `\\n tags: [${enrichment.tags.map(t => `'${escapeQuotes(t)}'`).join(', ')}],`\n : '';\n\n // Build variants (compound-aware)\n const variantsBlock = buildVariantsBlock(\n componentName,\n data.storyVariants,\n composition,\n compoundPartRefs\n );\n\n // Build AI metadata block with composition info\n const aiBlock = buildAIBlock(composition, compoundPartRefs);\n\n // Build provenance block\n const provenanceBlock = buildProvenanceBlock(confidence, props);\n\n // Build compound sub-components comment\n const compoundComment = composition && composition.parts.length > 0\n ? `\\n// Compound sub-components detected: ${composition.parts.map(p => p.name).join(', ')}`\n : '';\n\n return `// Auto-generated by fragments init --scan | Confidence: ${confidence.score}/100\n// ${confidence.todoFields.length} TODO(s) — search for \"TODO:\" and fill in human knowledge${compoundComment}\nimport { defineFragment } from '@fragments-sdk/core';\nimport { ${importNames.join(\", \")} } from '${importPath}';\n\nexport default defineFragment({\n component: ${componentName},\n\n meta: {\n name: '${escapeQuotes(componentName)}',\n description: '${escapeQuotes(description)}',${descriptionTodo}\n category: '${escapeQuotes(category)}',${categoryTodo}\n status: '${status}',${tagsLine}\n },\n\n${usageBlock}\n\n props: ${propsBlock},${contractBlock}${aiBlock}\n\n variants: [\n${variantsBlock}\n ],\n${provenanceBlock}});\n`;\n}\n\nfunction buildPropsBlockFromMeta(props: Record<string, PropMeta>): string {\n const entries = getFragmentPropEntries(props);\n if (entries.length === 0) return \"{}\";\n\n const lines = entries.map(([name, prop]) => {\n const type = prop.typeKind;\n const parts: string[] = [` type: '${type}'`];\n\n if (prop.description) {\n parts.push(\n ` description: '${escapeQuotes(prop.description.replace(/\\n/g, \" \"))}'`\n );\n }\n\n parts.push(` required: ${prop.required}`);\n\n if (prop.default !== undefined) {\n parts.push(` default: ${JSON.stringify(prop.default)}`);\n }\n\n if (prop.values && prop.values.length > 0) {\n parts.push(` values: ${JSON.stringify(prop.values)}`);\n }\n\n const todoComment =\n type === \"custom\" ? \" // TODO: Review type\" : \"\";\n\n return ` ${name}: {\\n${parts.join(\",\\n\")},\\n },${todoComment}`;\n });\n\n return `{\\n${lines.join(\"\\n\")}\\n }`;\n}\n\nfunction buildVariantsBlock(\n componentName: string,\n storyVariants: StoryVariant[],\n composition?: CompositionMeta | null,\n compoundPartRefs: CompoundPartReference[] = []\n): string {\n const entries: string[] = [];\n\n // Always include a Default variant\n const hasDefault = storyVariants.some((v) => v.name === \"Default\");\n if (!hasDefault) {\n if (composition && composition.pattern === 'compound' && composition.parts.length > 0) {\n // Generate a compound-aware default variant\n entries.push(formatCompoundVariantEntry(componentName, composition, compoundPartRefs));\n } else {\n entries.push(formatVariantEntry(componentName, \"Default\", `Default ${componentName}`, {}));\n }\n }\n\n for (const variant of storyVariants) {\n const description = variant.name.replace(/([A-Z])/g, \" $1\").trim();\n entries.push(\n formatVariantEntry(\n componentName,\n variant.name,\n `${description} ${componentName}`,\n variant.args\n )\n );\n }\n\n return entries.join(\"\\n\");\n}\n\nfunction formatVariantEntry(\n componentName: string,\n name: string,\n description: string,\n args: Record<string, unknown>\n): string {\n const jsxCode = buildJsxString(componentName, args);\n return ` {\n name: '${escapeQuotes(name)}',\n description: '${escapeQuotes(description)}',\n code: \\`${jsxCode}\\`,\n render: () => ${jsxCode},\n },`;\n}\n\n/**\n * Generate a compound-aware default variant showing sub-component usage.\n */\nfunction formatCompoundVariantEntry(\n componentName: string,\n composition: CompositionMeta,\n compoundPartRefs: CompoundPartReference[] = []\n): string {\n const resolvedParts = compoundPartRefs.length > 0\n ? compoundPartRefs\n : composition.parts.map((part) => ({ partName: part.name, tagName: `${componentName}.${part.name}` }));\n\n const innerJsx = resolvedParts\n .map((part) => ` <${part.tagName}>...</${part.tagName}>`)\n .join('\\n');\n\n const jsxCode = `<${componentName}>\\n${innerJsx}\\n </${componentName}>`;\n\n return ` {\n name: 'Default',\n description: 'Default ${componentName} with sub-components',\n code: \\`${jsxCode}\\`,\n render: () => (\\n ${jsxCode}\\n ),\n },`;\n}\n\n/**\n * Build the ai block with composition metadata.\n */\nfunction buildAIBlock(\n composition: CompositionMeta | null,\n compoundPartRefs: CompoundPartReference[] = []\n): string {\n if (!composition || composition.parts.length === 0) return \"\";\n\n const resolvedParts = compoundPartRefs.length > 0\n ? compoundPartRefs\n : composition.parts.map<CompoundPartReference>((part) => ({\n partName: part.name,\n tagName: `Component.${part.name}`,\n }));\n const subComponents = resolvedParts\n .map((part) => `'${part.importName ?? part.partName}'`)\n .join(', ');\n const pattern = `\\n <Component>\\n${resolvedParts\n .map((part) => ` <${part.tagName}>...</${part.tagName}>`)\n .join('\\n')}\\n </Component>`;\n\n return `\n\n ai: {\n compositionPattern: '${composition.pattern}',\n subComponents: [${subComponents}],\n commonPatterns: [\\`${pattern}\\n \\`],\n },`;\n}\n\n/**\n * Build _generated provenance block.\n */\nfunction buildProvenanceBlock(\n confidence: FieldConfidence,\n props: Record<string, PropMeta>\n): string {\n const autoFields = Object.keys(props).filter((name) => props[name].source === 'local');\n return `\n _generated: {\n source: 'ai',\n confidence: ${(confidence.score / 100).toFixed(2)},\n timestamp: '${new Date().toISOString()}',\n },\n`;\n}\n\nfunction buildJsxString(\n componentName: string,\n args: Record<string, unknown>\n): string {\n const { children, ...restArgs } = args;\n const propParts: string[] = [];\n\n for (const [key, value] of Object.entries(restArgs)) {\n if (typeof value === \"string\") {\n propParts.push(`${key}=\"${escapeQuotes(value)}\"`);\n } else if (typeof value === \"boolean\") {\n propParts.push(value ? key : `${key}={false}`);\n } else if (typeof value === \"number\") {\n propParts.push(`${key}={${value}}`);\n }\n }\n\n const propsStr = propParts.length > 0 ? \" \" + propParts.join(\" \") : \"\";\n\n if (typeof children === \"string\") {\n return `<${componentName}${propsStr}>${children}</${componentName}>`;\n }\n\n return `<${componentName}${propsStr} />`;\n}\n\n// ---------------------------------------------------------------------------\n// Contract JSON generator for init --scan\n// ---------------------------------------------------------------------------\n\nfunction generateContractJsonFromScan(\n componentName: string,\n _baseName: string,\n data: ComponentData,\n confidence: FieldConfidence,\n sourcePath: string,\n scanPath: string,\n enrichment?: EnrichmentResult,\n): string {\n const props = data.meta?.props ?? {};\n const localProps = Object.fromEntries(\n Object.entries(props).filter(([, p]) => p.source === 'local')\n );\n // Fall back to all props if no local props (wrapper components like shadcn Label)\n const effectiveProps = Object.keys(localProps).length > 0 ? localProps : props;\n const composition = data.meta?.composition ?? null;\n const description = data.meta?.description || `${componentName} component`;\n const category = inferCategoryFromMeta(componentName, effectiveProps);\n\n // Build props schema\n const propsSchema: Record<string, unknown> = {};\n for (const [name, prop] of Object.entries(effectiveProps)) {\n propsSchema[name] = {\n type: prop.typeKind,\n description: prop.description ?? '',\n ...(prop.values?.length && { values: prop.values }),\n ...(prop.default !== undefined && { default: prop.default }),\n ...(prop.required && { required: true }),\n };\n }\n\n // Build propsSummary\n const propsSummary = Object.entries(effectiveProps).map(([name, prop]) => {\n let summary = `${name}: `;\n if (prop.values?.length) {\n summary += prop.values.join('|');\n } else {\n summary += prop.typeKind;\n }\n if (prop.default !== undefined) summary += ` (default: ${prop.default})`;\n if (prop.required) summary += ' (required)';\n return summary;\n });\n\n // Build AI metadata\n let ai: Record<string, unknown> | undefined;\n if (composition) {\n ai = {\n compositionPattern: composition.pattern,\n subComponents: composition.parts.map(p => p.name),\n ...(composition.required.length > 0 && { requiredChildren: composition.required }),\n };\n }\n\n // Resolve sourcePath relative to scanPath\n const relativeSourcePath = relative(scanPath, sourcePath);\n\n // Use enrichment if available\n const usage = enrichment ? {\n when: enrichment.when ?? [],\n whenNot: enrichment.whenNot ?? [],\n ...(enrichment.guidelines?.length && { guidelines: enrichment.guidelines }),\n } : {\n when: [],\n whenNot: [],\n };\n\n const contract = {\n $schema: 'https://usefragments.com/schemas/contract.v1.json',\n name: componentName,\n description,\n category,\n sourcePath: relativeSourcePath,\n exportName: componentName,\n propsSummary,\n props: propsSchema,\n usage,\n ...(ai && { ai }),\n provenance: {\n source: 'extracted' as const,\n verified: confidence.score >= 70,\n frameworkSupport: 'native' as const,\n extractedAt: new Date().toISOString(),\n },\n };\n\n return JSON.stringify(contract, null, 2) + '\\n';\n}\n"],"mappings":"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","names":[]}
@@ -4,10 +4,9 @@ import {
4
4
  scanFileForImports,
5
5
  scanFileForUsages
6
6
  } from "./chunk-7DZC4YEV.js";
7
- import "./chunk-Z7EY4VHE.js";
8
7
  export {
9
8
  scanFile,
10
9
  scanFileForImports,
11
10
  scanFileForUsages
12
11
  };
13
- //# sourceMappingURL=scanner-7LAZYPWZ.js.map
12
+ //# sourceMappingURL=scanner-4KZNOXAK.js.map
@@ -60,30 +60,35 @@ import {
60
60
  getSharedPool,
61
61
  getSharedTokenRegistry,
62
62
  getStorybookStoryIds,
63
- hexToRgb,
64
63
  initializeSharedRegistry,
65
64
  isBoilerplate,
66
65
  mergeStorybookIntoDoc,
67
- normalizeColor,
68
66
  parseAllStories,
69
- parseRgb,
70
67
  parseStoryFile,
71
68
  parseStorySource,
72
- parseTokenFile,
73
- parseTokenFiles,
74
69
  renderAllComponentVariants,
75
70
  renderVariants,
76
71
  retry,
77
- rgbToHex,
78
72
  sanitizeFilename,
79
73
  shutdownSharedPool,
80
74
  sleep
81
- } from "./chunk-XJQ5BIWI.js";
75
+ } from "./chunk-6SQPP47U.js";
82
76
  import "./chunk-D2CDBRNU.js";
83
77
  import {
84
78
  BRAND,
85
79
  DEFAULTS
86
80
  } from "./chunk-32LIWN2P.js";
81
+ import {
82
+ containsTailwindV4Theme,
83
+ hexToRgb,
84
+ normalizeColor,
85
+ parseRgb,
86
+ parseTailwindV4File,
87
+ parseTailwindV4Theme,
88
+ parseTokenFile,
89
+ parseTokenFiles,
90
+ rgbToHex
91
+ } from "./chunk-MHIBEEW4.js";
87
92
  import {
88
93
  aggregateAllUsages,
89
94
  aggregateComponentUsages,
@@ -107,7 +112,6 @@ import {
107
112
  scanFileForImports,
108
113
  scanFileForUsages
109
114
  } from "./chunk-7DZC4YEV.js";
110
- import "./chunk-Z7EY4VHE.js";
111
115
  export {
112
116
  BRAND,
113
117
  BrowserPool,
@@ -137,6 +141,7 @@ export {
137
141
  clearSharedRegistry,
138
142
  computeFileHash,
139
143
  computeHash,
144
+ containsTailwindV4Theme,
140
145
  convertToFragmentProps,
141
146
  createCaptureEngine,
142
147
  createDeferred,
@@ -193,6 +198,8 @@ export {
193
198
  parseRgb,
194
199
  parseStoryFile,
195
200
  parseStorySource,
201
+ parseTailwindV4File,
202
+ parseTailwindV4Theme,
196
203
  parseTokenFile,
197
204
  parseTokenFiles,
198
205
  renderAllComponentVariants,
@@ -210,4 +217,4 @@ export {
210
217
  sleep,
211
218
  summarizePatternsForPrompt
212
219
  };
213
- //# sourceMappingURL=service-FHQU7YS7.js.map
220
+ //# sourceMappingURL=service-QJGWUIVL.js.map
@@ -3,7 +3,6 @@ import "./chunk-D2CDBRNU.js";
3
3
  import {
4
4
  BRAND
5
5
  } from "./chunk-32LIWN2P.js";
6
- import "./chunk-Z7EY4VHE.js";
7
6
 
8
7
  // src/commands/snapshot.ts
9
8
  import { resolve } from "path";
@@ -136,4 +135,4 @@ ${BRAND.name} Visual Snapshots
136
135
  export {
137
136
  snapshot
138
137
  };
139
- //# sourceMappingURL=snapshot-KQEQ6XHL.js.map
138
+ //# sourceMappingURL=snapshot-WIJMEIFT.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/snapshot.ts"],"sourcesContent":["/**\n * fragments snapshot - Run visual snapshot tests per component variant\n *\n * Starts the dev server (if not already running), then runs Playwright\n * snapshot tests against all component variants discovered in fragments.json.\n */\n\nimport { resolve } from \"node:path\";\nimport { execSync, spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport pc from \"picocolors\";\nimport { BRAND } from \"../core/index.js\";\n\nexport interface SnapshotOptions {\n /** Port of a running dev server (skips starting one) */\n port?: number | string;\n /** Update existing snapshots instead of comparing */\n update?: boolean;\n /** Filter to a specific component name */\n component?: string;\n /** Path to Playwright config (auto-detected if omitted) */\n config?: string;\n /** Path to the snapshot spec file */\n spec?: string;\n /** CI mode — non-interactive, exit 1 on mismatch */\n ci?: boolean;\n}\n\nexport interface SnapshotResult {\n success: boolean;\n totalTests: number;\n passed: number;\n failed: number;\n}\n\n/**\n * Find the snapshot spec file.\n * Checks project root e2e/ first, then falls back to the CLI's bundled spec.\n */\nfunction findSnapshotSpec(projectRoot: string, explicitPath?: string): string | null {\n if (explicitPath) {\n const resolved = resolve(projectRoot, explicitPath);\n return existsSync(resolved) ? resolved : null;\n }\n\n // Check common locations\n const candidates = [\n resolve(projectRoot, \"e2e/component-visual-snapshots.spec.ts\"),\n resolve(projectRoot, \"tests/visual-snapshots.spec.ts\"),\n resolve(projectRoot, \"test/visual-snapshots.spec.ts\"),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\n/**\n * Run visual snapshot tests.\n */\nexport async function snapshot(options: SnapshotOptions = {}): Promise<SnapshotResult> {\n const projectRoot = process.cwd();\n const {\n port,\n update = false,\n component,\n ci = false,\n } = options;\n\n console.log(pc.cyan(`\\n${BRAND.name} Visual Snapshots\\n`));\n\n // Check that fragments.json exists\n const fragmentsJson = resolve(projectRoot, BRAND.outFile);\n if (!existsSync(fragmentsJson)) {\n console.error(\n pc.red(`${BRAND.outFile} not found. Run ${pc.bold(`${BRAND.cliCommand} build`)} first.`)\n );\n return { success: false, totalTests: 0, passed: 0, failed: 0 };\n }\n\n // Find the snapshot spec\n const specPath = findSnapshotSpec(projectRoot, options.spec);\n if (!specPath) {\n console.error(\n pc.red(\"No snapshot spec found.\") + \"\\n\" +\n pc.dim(\"Expected: e2e/component-visual-snapshots.spec.ts\\n\") +\n pc.dim(`Create one or specify with --spec <path>`)\n );\n return { success: false, totalTests: 0, passed: 0, failed: 0 };\n }\n\n console.log(pc.dim(`Spec: ${specPath}`));\n\n // Check for Playwright\n try {\n execSync(\"npx playwright --version\", { stdio: \"pipe\" });\n } catch {\n console.error(\n pc.red(\"Playwright not found.\") + \"\\n\" +\n pc.dim(\"Install it: pnpm add -D @playwright/test && npx playwright install chromium\")\n );\n return { success: false, totalTests: 0, passed: 0, failed: 0 };\n }\n\n // Build Playwright args\n const args = [\"playwright\", \"test\", specPath];\n\n if (update) {\n args.push(\"--update-snapshots\");\n console.log(pc.yellow(\"Updating snapshots (baselines will be overwritten)\"));\n }\n\n if (component) {\n args.push(\"--grep\", component);\n console.log(pc.dim(`Filtering: ${component}`));\n }\n\n // If a port is specified, set the BASE_URL env var so the spec\n // can connect to an already-running dev server\n const env: Record<string, string> = { ...process.env as Record<string, string> };\n if (port) {\n env.FRAGMENTS_DEV_PORT = String(port);\n console.log(pc.dim(`Using running dev server on port ${port}`));\n }\n\n console.log(pc.dim(\"\\nRunning snapshot tests...\\n\"));\n\n // Run Playwright\n return new Promise<SnapshotResult>((resolveResult) => {\n const child = spawn(\"npx\", args, {\n cwd: projectRoot,\n stdio: ci ? \"pipe\" : \"inherit\",\n env,\n });\n\n let stdout = \"\";\n\n if (ci && child.stdout) {\n child.stdout.on(\"data\", (data) => {\n stdout += data.toString();\n });\n }\n if (ci && child.stderr) {\n child.stderr.on(\"data\", (data) => {\n stdout += data.toString();\n });\n }\n\n child.on(\"close\", (code) => {\n const success = code === 0;\n\n if (ci) {\n // Parse Playwright output for test counts\n const passedMatch = stdout.match(/(\\d+) passed/);\n const failedMatch = stdout.match(/(\\d+) failed/);\n const passed = passedMatch ? parseInt(passedMatch[1], 10) : 0;\n const failed = failedMatch ? parseInt(failedMatch[1], 10) : 0;\n\n if (!success) {\n process.stdout.write(stdout);\n }\n\n resolveResult({\n success,\n totalTests: passed + failed,\n passed,\n failed,\n });\n } else {\n if (success) {\n console.log(pc.green(\"\\n✓ All snapshots match\\n\"));\n } else if (update) {\n console.log(pc.green(\"\\n✓ Snapshots updated\\n\"));\n } else {\n console.log(pc.red(\"\\n✗ Snapshot mismatches detected\"));\n console.log(pc.dim(`Run ${pc.bold(`${BRAND.cliCommand} snapshot --update`)} to accept changes\\n`));\n }\n\n resolveResult({\n success: success || update,\n totalTests: 0,\n passed: 0,\n failed: 0,\n });\n }\n });\n\n child.on(\"error\", (err) => {\n console.error(pc.red(`Failed to run Playwright: ${err.message}`));\n resolveResult({ success: false, totalTests: 0, passed: 0, failed: 0 });\n });\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/snapshot.ts"],"sourcesContent":["/**\n * fragments snapshot - Run visual snapshot tests per component variant\n *\n * Starts the dev server (if not already running), then runs Playwright\n * snapshot tests against all component variants discovered in fragments.json.\n */\n\nimport { resolve } from \"node:path\";\nimport { execSync, spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport pc from \"picocolors\";\nimport { BRAND } from \"../core/index.js\";\n\nexport interface SnapshotOptions {\n /** Port of a running dev server (skips starting one) */\n port?: number | string;\n /** Update existing snapshots instead of comparing */\n update?: boolean;\n /** Filter to a specific component name */\n component?: string;\n /** Path to Playwright config (auto-detected if omitted) */\n config?: string;\n /** Path to the snapshot spec file */\n spec?: string;\n /** CI mode — non-interactive, exit 1 on mismatch */\n ci?: boolean;\n}\n\nexport interface SnapshotResult {\n success: boolean;\n totalTests: number;\n passed: number;\n failed: number;\n}\n\n/**\n * Find the snapshot spec file.\n * Checks project root e2e/ first, then falls back to the CLI's bundled spec.\n */\nfunction findSnapshotSpec(projectRoot: string, explicitPath?: string): string | null {\n if (explicitPath) {\n const resolved = resolve(projectRoot, explicitPath);\n return existsSync(resolved) ? resolved : null;\n }\n\n // Check common locations\n const candidates = [\n resolve(projectRoot, \"e2e/component-visual-snapshots.spec.ts\"),\n resolve(projectRoot, \"tests/visual-snapshots.spec.ts\"),\n resolve(projectRoot, \"test/visual-snapshots.spec.ts\"),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\n/**\n * Run visual snapshot tests.\n */\nexport async function snapshot(options: SnapshotOptions = {}): Promise<SnapshotResult> {\n const projectRoot = process.cwd();\n const {\n port,\n update = false,\n component,\n ci = false,\n } = options;\n\n console.log(pc.cyan(`\\n${BRAND.name} Visual Snapshots\\n`));\n\n // Check that fragments.json exists\n const fragmentsJson = resolve(projectRoot, BRAND.outFile);\n if (!existsSync(fragmentsJson)) {\n console.error(\n pc.red(`${BRAND.outFile} not found. Run ${pc.bold(`${BRAND.cliCommand} build`)} first.`)\n );\n return { success: false, totalTests: 0, passed: 0, failed: 0 };\n }\n\n // Find the snapshot spec\n const specPath = findSnapshotSpec(projectRoot, options.spec);\n if (!specPath) {\n console.error(\n pc.red(\"No snapshot spec found.\") + \"\\n\" +\n pc.dim(\"Expected: e2e/component-visual-snapshots.spec.ts\\n\") +\n pc.dim(`Create one or specify with --spec <path>`)\n );\n return { success: false, totalTests: 0, passed: 0, failed: 0 };\n }\n\n console.log(pc.dim(`Spec: ${specPath}`));\n\n // Check for Playwright\n try {\n execSync(\"npx playwright --version\", { stdio: \"pipe\" });\n } catch {\n console.error(\n pc.red(\"Playwright not found.\") + \"\\n\" +\n pc.dim(\"Install it: pnpm add -D @playwright/test && npx playwright install chromium\")\n );\n return { success: false, totalTests: 0, passed: 0, failed: 0 };\n }\n\n // Build Playwright args\n const args = [\"playwright\", \"test\", specPath];\n\n if (update) {\n args.push(\"--update-snapshots\");\n console.log(pc.yellow(\"Updating snapshots (baselines will be overwritten)\"));\n }\n\n if (component) {\n args.push(\"--grep\", component);\n console.log(pc.dim(`Filtering: ${component}`));\n }\n\n // If a port is specified, set the BASE_URL env var so the spec\n // can connect to an already-running dev server\n const env: Record<string, string> = { ...process.env as Record<string, string> };\n if (port) {\n env.FRAGMENTS_DEV_PORT = String(port);\n console.log(pc.dim(`Using running dev server on port ${port}`));\n }\n\n console.log(pc.dim(\"\\nRunning snapshot tests...\\n\"));\n\n // Run Playwright\n return new Promise<SnapshotResult>((resolveResult) => {\n const child = spawn(\"npx\", args, {\n cwd: projectRoot,\n stdio: ci ? \"pipe\" : \"inherit\",\n env,\n });\n\n let stdout = \"\";\n\n if (ci && child.stdout) {\n child.stdout.on(\"data\", (data) => {\n stdout += data.toString();\n });\n }\n if (ci && child.stderr) {\n child.stderr.on(\"data\", (data) => {\n stdout += data.toString();\n });\n }\n\n child.on(\"close\", (code) => {\n const success = code === 0;\n\n if (ci) {\n // Parse Playwright output for test counts\n const passedMatch = stdout.match(/(\\d+) passed/);\n const failedMatch = stdout.match(/(\\d+) failed/);\n const passed = passedMatch ? parseInt(passedMatch[1], 10) : 0;\n const failed = failedMatch ? parseInt(failedMatch[1], 10) : 0;\n\n if (!success) {\n process.stdout.write(stdout);\n }\n\n resolveResult({\n success,\n totalTests: passed + failed,\n passed,\n failed,\n });\n } else {\n if (success) {\n console.log(pc.green(\"\\n✓ All snapshots match\\n\"));\n } else if (update) {\n console.log(pc.green(\"\\n✓ Snapshots updated\\n\"));\n } else {\n console.log(pc.red(\"\\n✗ Snapshot mismatches detected\"));\n console.log(pc.dim(`Run ${pc.bold(`${BRAND.cliCommand} snapshot --update`)} to accept changes\\n`));\n }\n\n resolveResult({\n success: success || update,\n totalTests: 0,\n passed: 0,\n failed: 0,\n });\n }\n });\n\n child.on(\"error\", (err) => {\n console.error(pc.red(`Failed to run Playwright: ${err.message}`));\n resolveResult({ success: false, totalTests: 0, passed: 0, failed: 0 });\n });\n });\n}\n"],"mappings":"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","names":[]}
@@ -5,9 +5,8 @@ import {
5
5
  } from "./chunk-2WXKALIG.js";
6
6
  import "./chunk-D2CDBRNU.js";
7
7
  import "./chunk-32LIWN2P.js";
8
- import "./chunk-Z7EY4VHE.js";
9
8
  export {
10
9
  generateStaticViewer,
11
10
  generateViewerFromJson
12
11
  };
13
- //# sourceMappingURL=static-viewer-63PG6FWY.js.map
12
+ //# sourceMappingURL=static-viewer-7QIBQZRC.js.map
@@ -2,9 +2,8 @@ import { createRequire as __banner_createRequire } from 'module'; const require
2
2
  import {
3
3
  discoverFragmentFiles,
4
4
  parseFragmentFile
5
- } from "./chunk-65WSVDV5.js";
5
+ } from "./chunk-HQ6A6DTV.js";
6
6
  import "./chunk-32LIWN2P.js";
7
- import "./chunk-Z7EY4VHE.js";
8
7
 
9
8
  // src/test/index.ts
10
9
  import { resolve as resolve2, join as join2 } from "path";
@@ -1069,4 +1068,4 @@ export {
1069
1068
  listTests,
1070
1069
  runTestCommand
1071
1070
  };
1072
- //# sourceMappingURL=test-UQYUCZIS.js.map
1071
+ //# sourceMappingURL=test-64Z5BKBA.js.map