@fragments-sdk/cli 0.14.3 → 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 (181) hide show
  1. package/README.md +0 -3
  2. package/dist/{ai-client-I6MDWNYA.js → ai-client-LSLQGOMM.js} +1 -2
  3. package/dist/bin.js +4745 -3817
  4. package/dist/bin.js.map +1 -1
  5. package/dist/{chunk-TXFCEDOC.js → chunk-2WXKALIG.js} +2 -2
  6. package/dist/{chunk-I34BC3CU.js → chunk-32LIWN2P.js} +1006 -3
  7. package/dist/chunk-32LIWN2P.js.map +1 -0
  8. package/dist/chunk-5JF26E55.js +1255 -0
  9. package/dist/chunk-5JF26E55.js.map +1 -0
  10. package/dist/{chunk-APTQIBS5.js → chunk-6SQPP47U.js} +153 -1342
  11. package/dist/chunk-6SQPP47U.js.map +1 -0
  12. package/dist/chunk-7DZC4YEV.js +294 -0
  13. package/dist/chunk-7DZC4YEV.js.map +1 -0
  14. package/dist/{chunk-PJT5IZ37.js → chunk-BJE3425I.js} +19 -52
  15. package/dist/{chunk-PJT5IZ37.js.map → chunk-BJE3425I.js.map} +1 -1
  16. package/dist/{chunk-55KERLWL.js → chunk-HQ6A6DTV.js} +1587 -1073
  17. package/dist/chunk-HQ6A6DTV.js.map +1 -0
  18. package/dist/chunk-MHIBEEW4.js +511 -0
  19. package/dist/chunk-MHIBEEW4.js.map +1 -0
  20. package/dist/{chunk-5A6X2Y73.js → chunk-ONUP6Z4W.js} +25 -13
  21. package/dist/chunk-ONUP6Z4W.js.map +1 -0
  22. package/dist/chunk-QCN35LJU.js +630 -0
  23. package/dist/chunk-QCN35LJU.js.map +1 -0
  24. package/dist/chunk-T47OLCSF.js +36 -0
  25. package/dist/chunk-T47OLCSF.js.map +1 -0
  26. package/dist/codebase-scanner-MQHUZC2G.js +21 -0
  27. package/dist/converter-7XM3Y6NJ.js +33 -0
  28. package/dist/converter-7XM3Y6NJ.js.map +1 -0
  29. package/dist/core/index.js +43 -2
  30. package/dist/create-IH4R45GE.js +806 -0
  31. package/dist/create-IH4R45GE.js.map +1 -0
  32. package/dist/{generate-RYWIPDN2.js → generate-PVOLUAAC.js} +4 -6
  33. package/dist/{generate-RYWIPDN2.js.map → generate-PVOLUAAC.js.map} +1 -1
  34. package/dist/govern-scan-OYFZYOQW.js +413 -0
  35. package/dist/govern-scan-OYFZYOQW.js.map +1 -0
  36. package/dist/index.d.ts +4 -23
  37. package/dist/index.js +15 -14
  38. package/dist/index.js.map +1 -1
  39. package/dist/{init-WRUSW7R5.js → init-SSGUSP7Z.js} +131 -129
  40. package/dist/init-SSGUSP7Z.js.map +1 -0
  41. package/dist/{init-cloud-REQ3XLHO.js → init-cloud-3DNKPWFB.js} +30 -5
  42. package/dist/{init-cloud-REQ3XLHO.js.map → init-cloud-3DNKPWFB.js.map} +1 -1
  43. package/dist/mcp-bin.js +5 -37
  44. package/dist/mcp-bin.js.map +1 -1
  45. package/dist/node-37AUE74M.js +65 -0
  46. package/dist/push-contracts-WY32TFP6.js +84 -0
  47. package/dist/push-contracts-WY32TFP6.js.map +1 -0
  48. package/dist/scan-PKSYSTRR.js +15 -0
  49. package/dist/{scan-generate-TFZVL3BT.js → scan-generate-VY27PIOX.js} +340 -52
  50. package/dist/scan-generate-VY27PIOX.js.map +1 -0
  51. package/dist/scanner-4KZNOXAK.js +12 -0
  52. package/dist/{service-HKJ6B7P7.js → service-QJGWUIVL.js} +41 -30
  53. package/dist/{snapshot-C5DYIGIV.js → snapshot-WIJMEIFT.js} +2 -3
  54. package/dist/{snapshot-C5DYIGIV.js.map → snapshot-WIJMEIFT.js.map} +1 -1
  55. package/dist/{static-viewer-DUVC4UIM.js → static-viewer-7QIBQZRC.js} +3 -4
  56. package/dist/static-viewer-7QIBQZRC.js.map +1 -0
  57. package/dist/{test-JW7JIDFG.js → test-64Z5BKBA.js} +4 -7
  58. package/dist/{test-JW7JIDFG.js.map → test-64Z5BKBA.js.map} +1 -1
  59. package/dist/token-normalizer-TEPOVBPV.js +312 -0
  60. package/dist/token-normalizer-TEPOVBPV.js.map +1 -0
  61. package/dist/token-parser-32KOIOFN.js +22 -0
  62. package/dist/token-parser-32KOIOFN.js.map +1 -0
  63. package/dist/{tokens-KE73G5JC.js → tokens-NZWFQIAB.js} +10 -9
  64. package/dist/{tokens-KE73G5JC.js.map → tokens-NZWFQIAB.js.map} +1 -1
  65. package/dist/tokens-generate-5JQSJ27E.js +85 -0
  66. package/dist/tokens-generate-5JQSJ27E.js.map +1 -0
  67. package/dist/tokens-push-HY3KO36V.js +148 -0
  68. package/dist/tokens-push-HY3KO36V.js.map +1 -0
  69. package/package.json +8 -6
  70. package/src/bin.ts +300 -48
  71. package/src/commands/__fixtures__/shadcn-label-wrapper/package.json +7 -0
  72. package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.contract.json +42 -0
  73. package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.tsx +11 -0
  74. package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.contract.json +20 -0
  75. package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.tsx +14 -0
  76. package/src/commands/__fixtures__/shadcn-label-wrapper/tsconfig.app.json +23 -0
  77. package/src/commands/__tests__/build-freshness.test.ts +231 -0
  78. package/src/commands/__tests__/create.test.ts +71 -0
  79. package/src/commands/__tests__/drift-sync.test.ts +1 -1
  80. package/src/commands/__tests__/govern.test.ts +258 -0
  81. package/src/commands/__tests__/init.test.ts +113 -0
  82. package/src/commands/__tests__/scan-generate.test.ts +189 -70
  83. package/src/commands/__tests__/verify.test.ts +91 -0
  84. package/src/commands/build.ts +54 -1
  85. package/src/commands/context.ts +1 -1
  86. package/src/commands/create.ts +536 -0
  87. package/src/commands/discover.ts +151 -0
  88. package/src/commands/doctor.ts +3 -2
  89. package/src/commands/enhance.ts +3 -1
  90. package/src/commands/govern-scan.ts +565 -0
  91. package/src/commands/govern.ts +67 -4
  92. package/src/commands/init-cloud.ts +32 -4
  93. package/src/commands/init.ts +152 -28
  94. package/src/commands/inspect.ts +290 -0
  95. package/src/commands/migrate-contract.ts +85 -0
  96. package/src/commands/push-contracts.ts +112 -0
  97. package/src/commands/scan-generate.ts +439 -51
  98. package/src/commands/scan.ts +14 -0
  99. package/src/commands/setup.ts +27 -50
  100. package/src/commands/sync.ts +2 -2
  101. package/src/commands/tokens-generate.ts +113 -0
  102. package/src/commands/tokens-push.ts +199 -0
  103. package/src/commands/verify.ts +195 -1
  104. package/src/core/__fixtures__/shadcn-input/input.tsx +7 -0
  105. package/src/core/__fixtures__/shadcn-input/tsconfig.json +14 -0
  106. package/src/core/__fixtures__/shadcn-label/label.tsx +11 -0
  107. package/src/core/__fixtures__/shadcn-label/primitive.tsx +14 -0
  108. package/src/core/__fixtures__/shadcn-label/tsconfig.json +14 -0
  109. package/src/core/__fixtures__/shadcn-radix-label/label.tsx +11 -0
  110. package/src/core/__fixtures__/shadcn-radix-label/node_modules/radix-ui/index.d.ts +12 -0
  111. package/src/core/__fixtures__/shadcn-radix-label/tsconfig.json +14 -0
  112. package/src/core/__tests__/contract-parity.test.ts +316 -0
  113. package/src/core/__tests__/token-resolver.test.ts +1 -1
  114. package/src/core/component-extractor.test.ts +40 -1
  115. package/src/core/config.ts +2 -1
  116. package/src/core/discovery.ts +13 -2
  117. package/src/core/drift-verifier.ts +123 -0
  118. package/src/core/extractor-adapter.ts +80 -0
  119. package/src/index.ts +3 -3
  120. package/src/mcp/__tests__/projectFields.test.ts +1 -1
  121. package/src/mcp/utils.ts +1 -50
  122. package/src/migrate/converter.ts +3 -3
  123. package/src/migrate/fragment-to-contract.ts +253 -0
  124. package/src/migrate/report.ts +1 -1
  125. package/src/scripts/token-benchmark.ts +121 -0
  126. package/src/service/__tests__/props-extractor.test.ts +94 -0
  127. package/src/service/__tests__/token-normalizer.test.ts +690 -0
  128. package/src/service/ast-utils.ts +4 -23
  129. package/src/service/babel-config.ts +23 -0
  130. package/src/service/enhance/converter.ts +61 -0
  131. package/src/service/enhance/props-extractor.ts +25 -8
  132. package/src/service/enhance/scanner.ts +5 -24
  133. package/src/service/index.ts +8 -0
  134. package/src/service/snippet-validation.ts +9 -3
  135. package/src/service/tailwind-v4-parser.ts +314 -0
  136. package/src/service/token-normalizer.ts +510 -0
  137. package/src/service/token-parser.ts +56 -0
  138. package/src/setup.ts +10 -39
  139. package/src/shared/index.ts +1 -0
  140. package/src/shared/project-fields.ts +46 -0
  141. package/src/theme/__tests__/component-contrast.test.ts +2 -2
  142. package/src/theme/__tests__/serializer.test.ts +1 -1
  143. package/src/theme/generator.ts +16 -1
  144. package/src/theme/schema.ts +8 -0
  145. package/src/theme/serializer.ts +13 -9
  146. package/src/theme/types.ts +8 -0
  147. package/src/validators.ts +1 -2
  148. package/src/viewer/__tests__/viewer-integration.test.ts +8 -8
  149. package/src/viewer/style-utils.ts +27 -412
  150. package/src/viewer/vite-plugin.ts +2 -2
  151. package/dist/chunk-55KERLWL.js.map +0 -1
  152. package/dist/chunk-5A6X2Y73.js.map +0 -1
  153. package/dist/chunk-APTQIBS5.js.map +0 -1
  154. package/dist/chunk-EYXVAMEX.js +0 -626
  155. package/dist/chunk-EYXVAMEX.js.map +0 -1
  156. package/dist/chunk-I34BC3CU.js.map +0 -1
  157. package/dist/chunk-LOYS64QS.js +0 -2453
  158. package/dist/chunk-LOYS64QS.js.map +0 -1
  159. package/dist/chunk-Z7EY4VHE.js +0 -50
  160. package/dist/chunk-ZKTFKHWN.js +0 -324
  161. package/dist/chunk-ZKTFKHWN.js.map +0 -1
  162. package/dist/discovery-VDANZAJ2.js +0 -28
  163. package/dist/init-WRUSW7R5.js.map +0 -1
  164. package/dist/sass.node-4XJK6YBF.js +0 -130708
  165. package/dist/sass.node-4XJK6YBF.js.map +0 -1
  166. package/dist/scan-YJHQIRKG.js +0 -14
  167. package/dist/scan-generate-TFZVL3BT.js.map +0 -1
  168. package/dist/viewer-2TZS3NDL.js +0 -2730
  169. package/dist/viewer-2TZS3NDL.js.map +0 -1
  170. package/src/build.ts +0 -612
  171. package/src/commands/dev.ts +0 -107
  172. package/src/core/auto-props.ts +0 -464
  173. package/src/core/component-extractor.ts +0 -1030
  174. package/src/core/token-resolver.ts +0 -155
  175. /package/dist/{ai-client-I6MDWNYA.js.map → ai-client-LSLQGOMM.js.map} +0 -0
  176. /package/dist/{chunk-TXFCEDOC.js.map → chunk-2WXKALIG.js.map} +0 -0
  177. /package/dist/{chunk-Z7EY4VHE.js.map → codebase-scanner-MQHUZC2G.js.map} +0 -0
  178. /package/dist/{discovery-VDANZAJ2.js.map → node-37AUE74M.js.map} +0 -0
  179. /package/dist/{scan-YJHQIRKG.js.map → scan-PKSYSTRR.js.map} +0 -0
  180. /package/dist/{service-HKJ6B7P7.js.map → scanner-4KZNOXAK.js.map} +0 -0
  181. /package/dist/{static-viewer-DUVC4UIM.js.map → service-QJGWUIVL.js.map} +0 -0
@@ -2,7 +2,7 @@ import { createRequire as __banner_createRequire } from 'module'; const require
2
2
  import {
3
3
  BRAND,
4
4
  fragmentsConfigSchema
5
- } from "./chunk-I34BC3CU.js";
5
+ } from "./chunk-32LIWN2P.js";
6
6
 
7
7
  // src/core/config.ts
8
8
  import { existsSync } from "fs";
@@ -17,7 +17,9 @@ var STORYBOOK_FILTER_DEFAULTS = {
17
17
  var DEFAULT_CONFIG = {
18
18
  include: [
19
19
  `src/**/*${BRAND.fileExtension}`,
20
- // *.fragment.tsx files
20
+ // *.contract.json files (V2 canonical)
21
+ "src/**/*.fragment.tsx",
22
+ // Legacy fragment files (still supported)
21
23
  "src/**/*.stories.tsx"
22
24
  // Storybook stories (auto-converted)
23
25
  ],
@@ -80,295 +82,1254 @@ ${errors}`);
80
82
  }
81
83
  }
82
84
 
83
- // src/core/generators/typescript-extractor.ts
84
- import ts from "typescript";
85
- import { readFileSync } from "fs";
86
- function extractPropsFromFile(filePath) {
87
- const sourceText = readFileSync(filePath, "utf-8");
88
- return extractPropsFromSource(sourceText, filePath);
85
+ // src/core/discovery.ts
86
+ import { resolve as resolve2, dirname as dirname2 } from "path";
87
+ import { readFile } from "fs/promises";
88
+ import { existsSync as existsSync2 } from "fs";
89
+ import fg from "fast-glob";
90
+ function toPascalCase(name) {
91
+ return name.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
89
92
  }
90
- function extractPropsFromSource(sourceText, fileName = "component.tsx") {
91
- const sourceFile = ts.createSourceFile(
92
- fileName,
93
- sourceText,
94
- ts.ScriptTarget.Latest,
95
- true,
96
- fileName.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS
97
- );
98
- const result = {
99
- componentName: "",
100
- props: {},
101
- exports: [],
102
- imports: []
103
- };
104
- const propsInterfaces = /* @__PURE__ */ new Map();
105
- const componentExports = [];
106
- const defaultExports = /* @__PURE__ */ new Set();
107
- const importedModules = [];
108
- ts.forEachChild(sourceFile, (node) => {
109
- if (ts.isImportDeclaration(node)) {
110
- const moduleSpecifier = node.moduleSpecifier;
111
- if (ts.isStringLiteral(moduleSpecifier)) {
112
- importedModules.push(moduleSpecifier.text);
113
- }
114
- }
115
- if (ts.isInterfaceDeclaration(node)) {
116
- const name = node.name.text;
117
- if (name.endsWith("Props")) {
118
- propsInterfaces.set(name, node);
119
- }
120
- }
121
- if (ts.isTypeAliasDeclaration(node)) {
122
- const name = node.name.text;
123
- if (name.endsWith("Props")) {
124
- propsInterfaces.set(name, node);
125
- }
126
- }
127
- if (ts.isFunctionDeclaration(node) && node.name) {
128
- const hasExport = node.modifiers?.some(
129
- (m) => m.kind === ts.SyntaxKind.ExportKeyword
130
- );
131
- const hasDefault = node.modifiers?.some(
132
- (m) => m.kind === ts.SyntaxKind.DefaultKeyword
133
- );
134
- if (hasExport) {
135
- componentExports.push(node.name.text);
136
- if (hasDefault) {
137
- defaultExports.add(node.name.text);
138
- }
139
- }
93
+ async function extractPascalCaseExports(filePath) {
94
+ try {
95
+ const content = await readFile(filePath, "utf-8");
96
+ const exports = /* @__PURE__ */ new Set();
97
+ const exportFuncRegex = /export\s+function\s+([A-Z][a-zA-Z0-9]*)/g;
98
+ let match;
99
+ while ((match = exportFuncRegex.exec(content)) !== null) {
100
+ exports.add(match[1]);
140
101
  }
141
- if (ts.isVariableStatement(node)) {
142
- const hasExport = node.modifiers?.some(
143
- (m) => m.kind === ts.SyntaxKind.ExportKeyword
144
- );
145
- if (hasExport) {
146
- for (const decl of node.declarationList.declarations) {
147
- if (ts.isIdentifier(decl.name)) {
148
- componentExports.push(decl.name.text);
149
- }
150
- }
151
- }
102
+ const exportConstRegex = /export\s+const\s+([A-Z][a-zA-Z0-9]*)/g;
103
+ while ((match = exportConstRegex.exec(content)) !== null) {
104
+ exports.add(match[1]);
152
105
  }
153
- if (ts.isExportDeclaration(node) && node.exportClause) {
154
- if (ts.isNamedExports(node.exportClause)) {
155
- for (const element of node.exportClause.elements) {
156
- componentExports.push(element.name.text);
106
+ const exportBlockRegex = /export\s*\{([^}]+)\}/g;
107
+ while ((match = exportBlockRegex.exec(content)) !== null) {
108
+ const names = match[1].split(",").map((n) => n.trim().split(/\s+as\s+/)[0].trim());
109
+ for (const name of names) {
110
+ if (/^[A-Z]/.test(name)) {
111
+ exports.add(name);
157
112
  }
158
113
  }
159
114
  }
160
- });
161
- result.exports = componentExports;
162
- result.imports = importedModules;
163
- const mainComponent = componentExports.find(
164
- (name) => /^[A-Z]/.test(name) && !name.endsWith("Props")
165
- );
166
- if (!mainComponent) {
167
- return null;
168
- }
169
- result.componentName = mainComponent;
170
- result.isDefaultExport = defaultExports.has(mainComponent);
171
- const propsInterfaceName = `${mainComponent}Props`;
172
- const propsInterface = propsInterfaces.get(propsInterfaceName);
173
- if (propsInterface) {
174
- result.propsInterfaceName = propsInterfaceName;
175
- result.props = extractPropsFromInterface(propsInterface, sourceFile);
115
+ return Array.from(exports);
116
+ } catch {
117
+ return [];
176
118
  }
177
- return result;
178
119
  }
179
- function extractPropsFromInterface(node, sourceFile) {
180
- const props = {};
181
- if (ts.isInterfaceDeclaration(node)) {
182
- for (const member of node.members) {
183
- if (ts.isPropertySignature(member) && member.name) {
184
- const propName = member.name.getText(sourceFile);
185
- const prop = extractPropFromMember(member, sourceFile);
186
- if (prop) {
187
- props[propName] = prop;
188
- }
189
- }
190
- }
120
+ async function discoverBlockFiles(configDir, exclude) {
121
+ const patterns = [
122
+ `**/*${BRAND.blockFileExtension}`,
123
+ `**/*${BRAND.recipeFileExtension}`
124
+ ];
125
+ const files = await fg(patterns, {
126
+ cwd: configDir,
127
+ ignore: exclude ?? ["**/node_modules/**", "**/dist/**"],
128
+ absolute: false
129
+ });
130
+ return files.map((relativePath) => ({
131
+ relativePath,
132
+ absolutePath: resolve2(configDir, relativePath)
133
+ }));
134
+ }
135
+ var discoverRecipeFiles = discoverBlockFiles;
136
+ async function discoverFragmentFiles(config, configDir) {
137
+ const defaultExcludes = [
138
+ "**/*.test.stories.*",
139
+ "**/*.stories.test.*",
140
+ "**/*.test.story.*",
141
+ "**/*.story.test.*"
142
+ ];
143
+ const patterns = [
144
+ ...config.include,
145
+ "**/*.contract.json"
146
+ ];
147
+ const files = await fg(patterns, {
148
+ cwd: configDir,
149
+ ignore: [...defaultExcludes, ...config.exclude ?? []],
150
+ absolute: false
151
+ });
152
+ return files.map((relativePath) => ({
153
+ relativePath,
154
+ absolutePath: resolve2(configDir, relativePath)
155
+ }));
156
+ }
157
+ async function discoverComponentFiles(config, configDir) {
158
+ if (!config.components || config.components.length === 0) {
159
+ return [];
191
160
  }
192
- if (ts.isTypeAliasDeclaration(node)) {
193
- const typeNode = node.type;
194
- if (ts.isTypeLiteralNode(typeNode)) {
195
- for (const member of typeNode.members) {
196
- if (ts.isPropertySignature(member) && member.name) {
197
- const propName = member.name.getText(sourceFile);
198
- const prop = extractPropFromMember(member, sourceFile);
199
- if (prop) {
200
- props[propName] = prop;
201
- }
202
- }
203
- }
204
- }
161
+ const files = await fg(config.components, {
162
+ cwd: configDir,
163
+ ignore: [
164
+ ...config.exclude ?? [],
165
+ // Exclude fragment files themselves
166
+ ...config.include,
167
+ // Exclude test files
168
+ "**/*.test.*",
169
+ "**/*.spec.*",
170
+ "**/__tests__/**"
171
+ ],
172
+ absolute: false
173
+ });
174
+ return files.map((relativePath) => ({
175
+ relativePath,
176
+ absolutePath: resolve2(configDir, relativePath)
177
+ }));
178
+ }
179
+ function extractComponentName(filePath) {
180
+ const parts = filePath.replace(/\\/g, "/").split("/");
181
+ const fileName = parts[parts.length - 1];
182
+ if (fileName === "index.tsx" || fileName === "index.ts") {
183
+ return parts[parts.length - 2] ?? "Unknown";
205
184
  }
206
- return props;
185
+ return fileName.replace(/\.(tsx?|jsx?)$/, "");
207
186
  }
208
- function extractPropFromMember(member, sourceFile) {
209
- const entry = {};
210
- entry.required = !member.questionToken;
211
- if (member.type) {
212
- const typeInfo = parseTypeNode(member.type, sourceFile);
213
- entry.type = typeInfo.type;
214
- entry.typeKind = typeInfo.typeKind;
215
- if (typeInfo.options) {
216
- entry.options = typeInfo.options;
187
+ var DEFAULT_COMPONENT_PATTERNS = [
188
+ "src/components/**/*.tsx",
189
+ "src/components/**/index.tsx",
190
+ "components/**/*.tsx",
191
+ "lib/components/**/*.tsx",
192
+ "packages/*/src/components/**/*.tsx"
193
+ ];
194
+ var DEFAULT_EXCLUDE_PATTERNS = [
195
+ "**/*.test.*",
196
+ "**/*.spec.*",
197
+ "**/*.stories.*",
198
+ "**/*.story.*",
199
+ "**/__tests__/**",
200
+ "**/__mocks__/**",
201
+ "**/node_modules/**",
202
+ "**/dist/**"
203
+ ];
204
+ async function discoverComponentsFromSource(configDir, patterns, exclude) {
205
+ const searchPatterns = patterns && patterns.length > 0 ? patterns : DEFAULT_COMPONENT_PATTERNS;
206
+ const excludePatterns = [
207
+ ...DEFAULT_EXCLUDE_PATTERNS,
208
+ ...exclude ?? []
209
+ ];
210
+ const files = await fg(searchPatterns, {
211
+ cwd: configDir,
212
+ ignore: excludePatterns,
213
+ absolute: false
214
+ });
215
+ const pascalCaseFiles = [];
216
+ const lowercaseFiles = [];
217
+ for (const file of files) {
218
+ const name = extractComponentName(file);
219
+ if (/^[A-Z]/.test(name)) {
220
+ pascalCaseFiles.push(file);
221
+ } else if (/^[a-z]/.test(name)) {
222
+ lowercaseFiles.push(file);
217
223
  }
218
224
  }
219
- const jsDocComment = getJSDocComment(member);
220
- if (jsDocComment) {
221
- entry.description = jsDocComment;
225
+ const storyPatterns = [
226
+ "**/*.stories.tsx",
227
+ "**/*.stories.ts",
228
+ "**/*.story.tsx",
229
+ "**/*.story.ts"
230
+ ];
231
+ const storyFiles = await fg(storyPatterns, {
232
+ cwd: configDir,
233
+ ignore: ["**/node_modules/**", "**/dist/**"],
234
+ absolute: false
235
+ });
236
+ const storyMap = /* @__PURE__ */ new Map();
237
+ for (const storyFile of storyFiles) {
238
+ const name = extractComponentName(storyFile.replace(/\.stories?\.(tsx?|jsx?)$/, ".tsx"));
239
+ storyMap.set(name, storyFile);
240
+ }
241
+ const components = [];
242
+ for (const file of pascalCaseFiles) {
243
+ const name = extractComponentName(file);
244
+ const absolutePath = resolve2(configDir, file);
245
+ const storyFile = storyMap.get(name);
246
+ components.push({
247
+ name,
248
+ sourcePath: absolutePath,
249
+ relativePath: file,
250
+ storyPath: storyFile ? resolve2(configDir, storyFile) : void 0
251
+ });
222
252
  }
223
- const defaultValue = getJSDocDefault(member);
224
- if (defaultValue !== void 0) {
225
- entry.default = defaultValue;
253
+ for (const file of lowercaseFiles) {
254
+ const absolutePath = resolve2(configDir, file);
255
+ const fileName = extractComponentName(file);
256
+ const pascalName = toPascalCase(fileName);
257
+ const exports = await extractPascalCaseExports(absolutePath);
258
+ const primaryExport = exports.find((e) => e === pascalName) || exports[0];
259
+ if (primaryExport) {
260
+ const storyFile = storyMap.get(primaryExport) || storyMap.get(fileName);
261
+ components.push({
262
+ name: primaryExport,
263
+ sourcePath: absolutePath,
264
+ relativePath: file,
265
+ storyPath: storyFile ? resolve2(configDir, storyFile) : void 0
266
+ });
267
+ }
226
268
  }
227
- return entry;
269
+ components.sort((a, b) => a.name.localeCompare(b.name));
270
+ return components;
228
271
  }
229
- function parseTypeNode(typeNode, sourceFile) {
230
- if (typeNode.kind === ts.SyntaxKind.StringKeyword) {
231
- return { type: "string", typeKind: "string" };
232
- }
233
- if (typeNode.kind === ts.SyntaxKind.NumberKeyword) {
234
- return { type: "number", typeKind: "number" };
235
- }
236
- if (typeNode.kind === ts.SyntaxKind.BooleanKeyword) {
237
- return { type: "boolean", typeKind: "boolean" };
272
+ async function discoverComponentsFromBarrel(barrelPath, configDir) {
273
+ const absoluteBarrelPath = resolve2(configDir, barrelPath);
274
+ if (!existsSync2(absoluteBarrelPath)) {
275
+ return [];
238
276
  }
239
- if (ts.isUnionTypeNode(typeNode)) {
240
- const options = [];
241
- let allLiterals = true;
242
- for (const subType of typeNode.types) {
243
- if (ts.isLiteralTypeNode(subType)) {
244
- if (ts.isStringLiteral(subType.literal)) {
245
- options.push(subType.literal.text);
246
- } else if (subType.literal.kind === ts.SyntaxKind.TrueKeyword) {
247
- options.push("true");
248
- } else if (subType.literal.kind === ts.SyntaxKind.FalseKeyword) {
249
- options.push("false");
250
- } else {
251
- allLiterals = false;
252
- }
253
- } else {
254
- allLiterals = false;
277
+ const content = await readFile(absoluteBarrelPath, "utf-8");
278
+ const components = [];
279
+ const exportRegex = /export\s+(?:\*|{([^}]+)})\s+from\s+['"]([^'"]+)['"]/g;
280
+ let match;
281
+ while ((match = exportRegex.exec(content)) !== null) {
282
+ const exportedNames = match[1];
283
+ const importPath = match[2];
284
+ const barrelDir = dirname2(absoluteBarrelPath);
285
+ let resolvedPath = resolve2(barrelDir, importPath);
286
+ if (!resolvedPath.endsWith(".tsx") && !resolvedPath.endsWith(".ts")) {
287
+ if (existsSync2(`${resolvedPath}.tsx`)) {
288
+ resolvedPath = `${resolvedPath}.tsx`;
289
+ } else if (existsSync2(`${resolvedPath}.ts`)) {
290
+ resolvedPath = `${resolvedPath}.ts`;
291
+ } else if (existsSync2(`${resolvedPath}/index.tsx`)) {
292
+ resolvedPath = `${resolvedPath}/index.tsx`;
293
+ } else if (existsSync2(`${resolvedPath}/index.ts`)) {
294
+ resolvedPath = `${resolvedPath}/index.ts`;
255
295
  }
256
296
  }
257
- if (allLiterals && options.length > 0) {
258
- return {
259
- type: options.map((o) => `"${o}"`).join(" | "),
260
- typeKind: "enum",
261
- options
262
- };
263
- }
264
- return {
265
- type: typeNode.getText(sourceFile),
266
- typeKind: "union"
267
- };
268
- }
269
- if (ts.isFunctionTypeNode(typeNode)) {
270
- return {
271
- type: typeNode.getText(sourceFile),
272
- typeKind: "function"
273
- };
274
- }
275
- if (ts.isArrayTypeNode(typeNode)) {
276
- return {
277
- type: typeNode.getText(sourceFile),
278
- typeKind: "array"
279
- };
280
- }
281
- if (ts.isTypeReferenceNode(typeNode)) {
282
- const typeName = typeNode.typeName.getText(sourceFile);
283
- if (typeName === "ReactNode" || typeName === "React.ReactNode") {
284
- return { type: "ReactNode", typeKind: "node" };
285
- }
286
- if (typeName === "ReactElement" || typeName === "React.ReactElement") {
287
- return { type: "ReactElement", typeKind: "element" };
297
+ if (!existsSync2(resolvedPath)) {
298
+ continue;
288
299
  }
289
- if (typeName === "JSX.Element") {
290
- return { type: "JSX.Element", typeKind: "element" };
300
+ if (exportedNames) {
301
+ const names = exportedNames.split(",").map((n) => n.trim().split(/\s+as\s+/)[0].trim());
302
+ for (const name of names) {
303
+ if (/^[A-Z]/.test(name)) {
304
+ const relativePath = resolvedPath.replace(configDir + "/", "");
305
+ components.push({
306
+ name,
307
+ sourcePath: resolvedPath,
308
+ relativePath
309
+ });
310
+ }
311
+ }
312
+ } else {
313
+ const name = extractComponentName(importPath);
314
+ if (/^[A-Z]/.test(name)) {
315
+ const relativePath = resolvedPath.replace(configDir + "/", "");
316
+ components.push({
317
+ name,
318
+ sourcePath: resolvedPath,
319
+ relativePath
320
+ });
321
+ }
291
322
  }
292
- return {
293
- type: typeNode.getText(sourceFile),
294
- typeKind: "object"
295
- };
296
- }
297
- if (ts.isTypeLiteralNode(typeNode)) {
298
- return {
299
- type: typeNode.getText(sourceFile),
300
- typeKind: "object"
301
- };
302
323
  }
303
- return {
304
- type: typeNode.getText(sourceFile),
305
- typeKind: "unknown"
306
- };
324
+ return components;
307
325
  }
308
- function getJSDocComment(node) {
309
- const jsDocTags = ts.getJSDocTags(node);
310
- const jsDoc = node.jsDoc;
311
- if (jsDoc && jsDoc.length > 0) {
312
- const comment = jsDoc[0].comment;
313
- if (typeof comment === "string") {
314
- return comment;
315
- }
316
- if (Array.isArray(comment)) {
317
- return comment.map((c) => typeof c === "string" ? c : c.text).join("");
326
+ var DEFAULT_TOKEN_PATTERNS = [
327
+ "src/**/tokens/**/_variables.scss",
328
+ "src/**/tokens/**/variables.scss",
329
+ "src/**/styles/**/variables.scss",
330
+ "src/**/styles/**/tokens.scss",
331
+ "src/**/styles/**/variables.css",
332
+ "src/**/theme/**/_variables.scss",
333
+ "src/**/theme/**/tokens.css",
334
+ // DTCG token files
335
+ "**/*.tokens.json",
336
+ "**/*.tokens"
337
+ ];
338
+ async function discoverTokenFiles(configDir, patterns, exclude) {
339
+ const searchPatterns = patterns && patterns.length > 0 ? patterns : DEFAULT_TOKEN_PATTERNS;
340
+ const files = await fg(searchPatterns, {
341
+ cwd: configDir,
342
+ ignore: exclude ?? ["**/node_modules/**", "**/dist/**"],
343
+ absolute: false
344
+ });
345
+ return files.map((relativePath) => ({
346
+ relativePath,
347
+ absolutePath: resolve2(configDir, relativePath)
348
+ }));
349
+ }
350
+ async function discoverInstalledFragments(projectRoot) {
351
+ const pkgJsonPath = resolve2(projectRoot, "package.json");
352
+ if (!existsSync2(pkgJsonPath)) return [];
353
+ const pkgJson = JSON.parse(await readFile(pkgJsonPath, "utf-8"));
354
+ const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
355
+ const results = [];
356
+ for (const depName of Object.keys(allDeps)) {
357
+ const depDir = resolve2(projectRoot, "node_modules", depName);
358
+ const depPkgPath = resolve2(depDir, "package.json");
359
+ if (!existsSync2(depPkgPath)) continue;
360
+ const depPkg = JSON.parse(await readFile(depPkgPath, "utf-8"));
361
+ if (!depPkg.fragments) continue;
362
+ const files = await fg(
363
+ [`src/**/*${BRAND.fileExtension}`, "src/**/*.stories.tsx"],
364
+ { cwd: depDir, ignore: ["**/node_modules/**"], absolute: false }
365
+ );
366
+ for (const rel of files) {
367
+ results.push({
368
+ relativePath: `${depName}/${rel}`,
369
+ absolutePath: resolve2(depDir, rel)
370
+ });
318
371
  }
319
372
  }
320
- return void 0;
373
+ return results;
321
374
  }
322
- function getJSDocDefault(node) {
323
- const jsDocTags = ts.getJSDocTags(node);
324
- for (const tag of jsDocTags) {
325
- if (tag.tagName.text === "default") {
326
- const comment = tag.comment;
327
- if (typeof comment === "string") {
328
- try {
329
- return JSON.parse(comment);
330
- } catch {
331
- return comment;
375
+ async function discoverAllComponents(configDir, options = {}) {
376
+ const componentsMap = /* @__PURE__ */ new Map();
377
+ const sourceComponents = await discoverComponentsFromSource(
378
+ configDir,
379
+ options.patterns,
380
+ options.exclude
381
+ );
382
+ for (const comp of sourceComponents) {
383
+ componentsMap.set(comp.name, comp);
384
+ }
385
+ if (options.barrelFiles && options.barrelFiles.length > 0) {
386
+ for (const barrelFile of options.barrelFiles) {
387
+ const barrelComponents = await discoverComponentsFromBarrel(barrelFile, configDir);
388
+ for (const comp of barrelComponents) {
389
+ if (!componentsMap.has(comp.name)) {
390
+ componentsMap.set(comp.name, comp);
332
391
  }
333
392
  }
334
393
  }
335
394
  }
336
- return void 0;
395
+ return Array.from(componentsMap.values()).sort((a, b) => a.name.localeCompare(b.name));
337
396
  }
338
397
 
339
- // src/core/generators/registry.ts
340
- import { readFileSync as readFileSync2 } from "fs";
341
- import { relative, dirname as dirname2, basename, join } from "path";
342
- import fg from "fast-glob";
343
- async function generateRegistry(options) {
344
- const {
345
- projectRoot,
346
- componentPatterns = ["src/**/*.tsx", "src/**/*.ts"],
347
- storyPatterns = ["src/**/*.stories.tsx", "src/**/*.stories.ts"],
348
- fragmentsDir = join(projectRoot, BRAND.dataDir),
349
- registryOptions = {}
350
- } = options;
351
- const {
352
- requireStory = false,
353
- publicOnly = false,
354
- categoryDepth = 1,
355
- includeProps = false,
356
- embedFragments = false
357
- } = registryOptions;
358
- const errors = [];
359
- const warnings = [];
360
- const storyFiles = await fg(storyPatterns, {
361
- cwd: projectRoot,
362
- ignore: ["**/node_modules/**"],
363
- absolute: true
398
+ // src/core/loader.ts
399
+ import { unlink } from "fs/promises";
400
+ import { dirname as dirname3, basename as basename2, join } from "path";
401
+ import { pathToFileURL } from "url";
402
+ import { build } from "esbuild";
403
+ var DEFINE_FRAGMENT_SHIM = `
404
+ export function defineFragment(def) {
405
+ return def;
406
+ }
407
+ export function defineBlock(def) {
408
+ return def;
409
+ }
410
+ export function defineRecipe(def) {
411
+ return def;
412
+ }
413
+ `;
414
+ function createFragmentsCoreShimPlugin() {
415
+ return {
416
+ name: BRAND.vitePluginNamespace,
417
+ setup(build2) {
418
+ build2.onResolve({ filter: /^@fragments-sdk\/cli\/core$/ }, (args) => {
419
+ return {
420
+ path: args.path,
421
+ namespace: BRAND.vitePluginNamespace
422
+ };
423
+ });
424
+ build2.onLoad({ filter: /.*/, namespace: BRAND.vitePluginNamespace }, () => {
425
+ return {
426
+ contents: DEFINE_FRAGMENT_SHIM,
427
+ loader: "js"
428
+ };
429
+ });
430
+ }
431
+ };
432
+ }
433
+ async function loadFragmentFile(absolutePath) {
434
+ const unwrapFragmentExport = (value) => {
435
+ if (!value) return null;
436
+ const asObject = (v) => v && typeof v === "object" ? v : null;
437
+ const isFragmentLike = (v) => {
438
+ const obj = asObject(v);
439
+ return !!obj && ("component" in obj || "meta" in obj || "variants" in obj);
440
+ };
441
+ if (isFragmentLike(value)) {
442
+ return value;
443
+ }
444
+ const first = asObject(value)?.default;
445
+ if (isFragmentLike(first)) {
446
+ return first;
447
+ }
448
+ const second = asObject(first)?.default;
449
+ if (isFragmentLike(second)) {
450
+ return second;
451
+ }
452
+ return value ?? null;
453
+ };
454
+ const ext = absolutePath.split(".").pop()?.toLowerCase();
455
+ const needsTransform = ext === "tsx" || ext === "ts" || ext === "jsx";
456
+ if (!needsTransform) {
457
+ const fileUrl = pathToFileURL(absolutePath).href;
458
+ const module = await import(fileUrl);
459
+ return unwrapFragmentExport(module.default ?? null);
460
+ }
461
+ const sourceDir = dirname3(absolutePath);
462
+ const baseName = basename2(absolutePath, `.${ext}`);
463
+ const tempFile = join(sourceDir, `.${baseName}.fragments-temp-${Date.now()}.mjs`);
464
+ try {
465
+ await build({
466
+ entryPoints: [absolutePath],
467
+ outfile: tempFile,
468
+ bundle: true,
469
+ format: "esm",
470
+ target: "es2022",
471
+ jsx: "automatic",
472
+ platform: "node",
473
+ plugins: [createFragmentsCoreShimPlugin()],
474
+ // Externalize all node_modules - we only need fragment metadata, not component code
475
+ packages: "external",
476
+ // Also explicitly list patterns for nested imports
477
+ external: [
478
+ // React and its subpaths
479
+ "react",
480
+ "react-dom",
481
+ "react/*",
482
+ "react-dom/*"
483
+ ],
484
+ // Don't emit sourcemaps for temp files
485
+ sourcemap: false,
486
+ // Suppress warnings
487
+ logLevel: "silent",
488
+ // Use loader to ignore style imports
489
+ loader: {
490
+ ".scss": "empty",
491
+ ".css": "empty",
492
+ ".svg": "empty",
493
+ ".png": "empty",
494
+ ".jpg": "empty",
495
+ ".jpeg": "empty",
496
+ ".gif": "empty",
497
+ ".woff": "empty",
498
+ ".woff2": "empty",
499
+ ".ttf": "empty",
500
+ ".eot": "empty"
501
+ }
502
+ });
503
+ const fileUrl = pathToFileURL(tempFile).href;
504
+ const module = await import(fileUrl);
505
+ return unwrapFragmentExport(module.default ?? null);
506
+ } finally {
507
+ try {
508
+ await unlink(tempFile);
509
+ } catch {
510
+ }
511
+ }
512
+ }
513
+ async function loadFragmentFiles(absolutePaths) {
514
+ const results = /* @__PURE__ */ new Map();
515
+ await Promise.all(
516
+ absolutePaths.map(async (path) => {
517
+ try {
518
+ const fragment = await loadFragmentFile(path);
519
+ if (fragment) {
520
+ results.set(path, fragment);
521
+ } else {
522
+ results.set(path, new Error("No default export found"));
523
+ }
524
+ } catch (error) {
525
+ results.set(
526
+ path,
527
+ error instanceof Error ? error : new Error(String(error))
528
+ );
529
+ }
530
+ })
531
+ );
532
+ return results;
533
+ }
534
+
535
+ // src/core/parser.ts
536
+ import ts from "typescript";
537
+ function parseFragmentFile(fileContent, filePath) {
538
+ const warnings = [];
539
+ const sourceFile = ts.createSourceFile(
540
+ filePath ?? "fragment.tsx",
541
+ fileContent,
542
+ ts.ScriptTarget.Latest,
543
+ true,
544
+ ts.ScriptKind.TSX
545
+ );
546
+ const imports = extractImports(sourceFile);
547
+ const defineFragmentCall = findDefineFragmentCall(sourceFile);
548
+ if (!defineFragmentCall) {
549
+ warnings.push("No defineFragment() call found");
550
+ return {
551
+ componentImport: null,
552
+ componentName: null,
553
+ meta: {},
554
+ usage: { when: [], whenNot: [] },
555
+ props: {},
556
+ variants: [],
557
+ relations: [],
558
+ warnings
559
+ };
560
+ }
561
+ const arg = defineFragmentCall.arguments[0];
562
+ if (!arg || !ts.isObjectLiteralExpression(arg)) {
563
+ warnings.push("defineFragment() argument is not an object literal");
564
+ return {
565
+ componentImport: null,
566
+ componentName: null,
567
+ meta: {},
568
+ usage: { when: [], whenNot: [] },
569
+ props: {},
570
+ variants: [],
571
+ relations: [],
572
+ warnings
573
+ };
574
+ }
575
+ const componentProp = findProperty(arg, "component");
576
+ let componentName = null;
577
+ let componentImport = null;
578
+ if (componentProp && ts.isIdentifier(componentProp)) {
579
+ componentName = componentProp.text;
580
+ componentImport = imports.get(componentName) ?? null;
581
+ }
582
+ const meta = extractMeta(arg, warnings);
583
+ const usage = extractUsage(arg, warnings);
584
+ const props = extractProps(arg, warnings);
585
+ const variants = extractVariants(arg, sourceFile, warnings);
586
+ const relations = extractRelations(arg, warnings);
587
+ const ai = extractAIMetadata(arg, warnings);
588
+ const contract = extractContractMetadata(arg);
589
+ return {
590
+ componentImport,
591
+ componentName,
592
+ meta,
593
+ usage,
594
+ props,
595
+ variants,
596
+ relations,
597
+ ai,
598
+ contract,
599
+ warnings
600
+ };
601
+ }
602
+ function extractImports(sourceFile) {
603
+ const imports = /* @__PURE__ */ new Map();
604
+ ts.forEachChild(sourceFile, (node) => {
605
+ if (ts.isImportDeclaration(node)) {
606
+ const moduleSpecifier = node.moduleSpecifier;
607
+ if (ts.isStringLiteral(moduleSpecifier)) {
608
+ const modulePath = moduleSpecifier.text;
609
+ const importClause = node.importClause;
610
+ if (importClause) {
611
+ if (importClause.name) {
612
+ imports.set(importClause.name.text, modulePath);
613
+ }
614
+ const namedBindings = importClause.namedBindings;
615
+ if (namedBindings && ts.isNamedImports(namedBindings)) {
616
+ for (const element of namedBindings.elements) {
617
+ imports.set(element.name.text, modulePath);
618
+ }
619
+ }
620
+ }
621
+ }
622
+ }
623
+ });
624
+ return imports;
625
+ }
626
+ function findDefineFragmentCall(sourceFile) {
627
+ let result = null;
628
+ function visit(node) {
629
+ if (ts.isCallExpression(node)) {
630
+ const expression = node.expression;
631
+ if (ts.isIdentifier(expression) && expression.text === "defineFragment") {
632
+ result = node;
633
+ return;
634
+ }
635
+ }
636
+ ts.forEachChild(node, visit);
637
+ }
638
+ visit(sourceFile);
639
+ return result;
640
+ }
641
+ function findProperty(obj, name) {
642
+ for (const prop of obj.properties) {
643
+ if (ts.isPropertyAssignment(prop)) {
644
+ const propName = prop.name;
645
+ if (ts.isIdentifier(propName) && propName.text === name) {
646
+ return prop.initializer;
647
+ }
648
+ }
649
+ }
650
+ return null;
651
+ }
652
+ function extractMeta(arg, warnings) {
653
+ const metaProp = findProperty(arg, "meta");
654
+ if (!metaProp || !ts.isObjectLiteralExpression(metaProp)) {
655
+ warnings.push("No meta object found");
656
+ return {};
657
+ }
658
+ const meta = {};
659
+ const name = extractStringProperty(metaProp, "name");
660
+ if (name) meta.name = name;
661
+ const description = extractStringProperty(metaProp, "description");
662
+ if (description) meta.description = description;
663
+ const category = extractStringProperty(metaProp, "category");
664
+ if (category) meta.category = category;
665
+ const status = extractStringProperty(metaProp, "status");
666
+ if (status) meta.status = status;
667
+ const since = extractStringProperty(metaProp, "since");
668
+ if (since) meta.since = since;
669
+ const figma = extractStringProperty(metaProp, "figma");
670
+ if (figma) meta.figma = figma;
671
+ const tags = extractStringArray(metaProp, "tags");
672
+ if (tags.length > 0) meta.tags = tags;
673
+ const depsProp = findProperty(metaProp, "dependencies");
674
+ if (depsProp && ts.isArrayLiteralExpression(depsProp)) {
675
+ const deps = extractLiteralValue(depsProp);
676
+ if (Array.isArray(deps) && deps.length > 0) {
677
+ meta.dependencies = deps;
678
+ }
679
+ }
680
+ return meta;
681
+ }
682
+ function extractUsage(arg, warnings) {
683
+ const usageProp = findProperty(arg, "usage");
684
+ if (!usageProp || !ts.isObjectLiteralExpression(usageProp)) {
685
+ return { when: [], whenNot: [] };
686
+ }
687
+ return {
688
+ when: extractStringArray(usageProp, "when"),
689
+ whenNot: extractStringArray(usageProp, "whenNot"),
690
+ guidelines: extractStringArray(usageProp, "guidelines"),
691
+ accessibility: extractStringArray(usageProp, "accessibility")
692
+ };
693
+ }
694
+ function extractProps(arg, warnings) {
695
+ const propsProp = findProperty(arg, "props");
696
+ if (!propsProp || !ts.isObjectLiteralExpression(propsProp)) {
697
+ return {};
698
+ }
699
+ const props = {};
700
+ for (const prop of propsProp.properties) {
701
+ if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
702
+ const propName = prop.name.text;
703
+ const propValue = prop.initializer;
704
+ if (ts.isObjectLiteralExpression(propValue)) {
705
+ props[propName] = extractPropDefinition(propValue);
706
+ }
707
+ }
708
+ }
709
+ return props;
710
+ }
711
+ function extractPropDefinition(obj) {
712
+ const def = {};
713
+ const type = extractStringProperty(obj, "type");
714
+ if (type) def.type = type;
715
+ const description = extractStringProperty(obj, "description");
716
+ if (description) def.description = description;
717
+ const values = extractStringArray(obj, "values");
718
+ if (values.length > 0) def.values = values;
719
+ const required = extractBooleanProperty(obj, "required");
720
+ if (required !== null) def.required = required;
721
+ const defaultProp = findProperty(obj, "default");
722
+ if (defaultProp) {
723
+ def.default = extractLiteralValue(defaultProp);
724
+ }
725
+ const constraints = extractStringArray(obj, "constraints");
726
+ if (constraints.length > 0) def.constraints = constraints;
727
+ return def;
728
+ }
729
+ function extractVariants(arg, sourceFile, warnings) {
730
+ const variantsProp = findProperty(arg, "variants");
731
+ if (!variantsProp || !ts.isArrayLiteralExpression(variantsProp)) {
732
+ return [];
733
+ }
734
+ const variants = [];
735
+ for (const element of variantsProp.elements) {
736
+ if (ts.isObjectLiteralExpression(element)) {
737
+ const name = extractStringProperty(element, "name");
738
+ const description = extractStringProperty(element, "description");
739
+ if (name) {
740
+ const variant = {
741
+ name,
742
+ description: description ?? ""
743
+ };
744
+ const codeProp = findProperty(element, "code");
745
+ if (codeProp && (ts.isStringLiteral(codeProp) || ts.isNoSubstitutionTemplateLiteral(codeProp))) {
746
+ variant.code = codeProp.text;
747
+ }
748
+ const renderProp = findProperty(element, "render");
749
+ if (renderProp && !variant.code) {
750
+ variant.code = extractRenderCode(renderProp, sourceFile);
751
+ }
752
+ const figma = extractStringProperty(element, "figma");
753
+ if (figma) {
754
+ variant.figma = figma;
755
+ }
756
+ const argsProp = findProperty(element, "args");
757
+ if (argsProp && ts.isObjectLiteralExpression(argsProp)) {
758
+ const argsValue = extractLiteralValue(argsProp);
759
+ if (argsValue && typeof argsValue === "object" && !Array.isArray(argsValue)) {
760
+ variant.args = argsValue;
761
+ }
762
+ }
763
+ variants.push(variant);
764
+ }
765
+ }
766
+ }
767
+ return variants;
768
+ }
769
+ function dedent(str) {
770
+ const lines = str.split("\n");
771
+ if (lines.length <= 1) {
772
+ return str;
773
+ }
774
+ const firstLineIndent = lines[0].match(/^(\s*)/)?.[1].length ?? 0;
775
+ const startIndex = firstLineIndent === 0 ? 1 : 0;
776
+ let minIndent = Infinity;
777
+ for (let i = startIndex; i < lines.length; i++) {
778
+ const line = lines[i];
779
+ if (line.trim() === "") continue;
780
+ const match = line.match(/^(\s*)/);
781
+ if (match) {
782
+ minIndent = Math.min(minIndent, match[1].length);
783
+ }
784
+ }
785
+ if (minIndent === Infinity || minIndent === 0) {
786
+ return str;
787
+ }
788
+ return lines.map((line, index) => {
789
+ if (index === 0 && firstLineIndent === 0) {
790
+ return line;
791
+ }
792
+ return line.slice(minIndent);
793
+ }).join("\n");
794
+ }
795
+ function extractRenderCode(renderProp, sourceFile) {
796
+ if (ts.isArrowFunction(renderProp)) {
797
+ const body = renderProp.body;
798
+ const start = body.getStart(sourceFile);
799
+ const end = body.getEnd();
800
+ let code = sourceFile.text.substring(start, end).trim();
801
+ if (code.startsWith("(") && code.endsWith(")")) {
802
+ code = code.slice(1, -1).trim();
803
+ }
804
+ code = dedent(code);
805
+ return code;
806
+ }
807
+ return void 0;
808
+ }
809
+ function extractRelations(arg, warnings) {
810
+ const relationsProp = findProperty(arg, "relations");
811
+ if (!relationsProp || !ts.isArrayLiteralExpression(relationsProp)) {
812
+ return [];
813
+ }
814
+ const relations = [];
815
+ for (const element of relationsProp.elements) {
816
+ if (ts.isObjectLiteralExpression(element)) {
817
+ const component = extractStringProperty(element, "component");
818
+ const relationship = extractStringProperty(element, "relationship");
819
+ const note = extractStringProperty(element, "note");
820
+ if (component && relationship) {
821
+ relations.push({
822
+ component,
823
+ relationship,
824
+ note: note ?? ""
825
+ });
826
+ }
827
+ }
828
+ }
829
+ return relations;
830
+ }
831
+ function extractAIMetadata(arg, warnings) {
832
+ const aiProp = findProperty(arg, "ai");
833
+ if (!aiProp || !ts.isObjectLiteralExpression(aiProp)) {
834
+ return void 0;
835
+ }
836
+ const ai = {};
837
+ const compositionPattern = extractStringProperty(aiProp, "compositionPattern");
838
+ if (compositionPattern && ["compound", "simple", "controlled"].includes(compositionPattern)) {
839
+ ai.compositionPattern = compositionPattern;
840
+ }
841
+ const subComponents = extractStringArray(aiProp, "subComponents");
842
+ if (subComponents.length > 0) {
843
+ ai.subComponents = subComponents;
844
+ }
845
+ const requiredChildren = extractStringArray(aiProp, "requiredChildren");
846
+ if (requiredChildren.length > 0) {
847
+ ai.requiredChildren = requiredChildren;
848
+ }
849
+ const commonPatterns = extractStringArray(aiProp, "commonPatterns");
850
+ if (commonPatterns.length > 0) {
851
+ ai.commonPatterns = commonPatterns;
852
+ }
853
+ if (Object.keys(ai).length > 0) {
854
+ return ai;
855
+ }
856
+ return void 0;
857
+ }
858
+ function extractContractMetadata(arg) {
859
+ const contractProp = findProperty(arg, "contract");
860
+ if (!contractProp || !ts.isObjectLiteralExpression(contractProp)) {
861
+ return void 0;
862
+ }
863
+ const contract = {};
864
+ const propsSummary = extractStringArray(contractProp, "propsSummary");
865
+ if (propsSummary.length > 0) {
866
+ contract.propsSummary = propsSummary;
867
+ }
868
+ const a11yRules = extractStringArray(contractProp, "a11yRules");
869
+ if (a11yRules.length > 0) {
870
+ contract.a11yRules = a11yRules;
871
+ }
872
+ if (Object.keys(contract).length > 0) {
873
+ return contract;
874
+ }
875
+ return void 0;
876
+ }
877
+ function extractStringProperty(obj, name) {
878
+ const prop = findProperty(obj, name);
879
+ if (prop && ts.isStringLiteral(prop)) {
880
+ return prop.text;
881
+ }
882
+ if (prop && ts.isNoSubstitutionTemplateLiteral(prop)) {
883
+ return prop.text;
884
+ }
885
+ return null;
886
+ }
887
+ function extractBooleanProperty(obj, name) {
888
+ const prop = findProperty(obj, name);
889
+ if (prop) {
890
+ if (prop.kind === ts.SyntaxKind.TrueKeyword) return true;
891
+ if (prop.kind === ts.SyntaxKind.FalseKeyword) return false;
892
+ }
893
+ return null;
894
+ }
895
+ function extractStringArray(obj, name) {
896
+ const prop = findProperty(obj, name);
897
+ if (!prop || !ts.isArrayLiteralExpression(prop)) {
898
+ return [];
899
+ }
900
+ const result = [];
901
+ for (const element of prop.elements) {
902
+ if (ts.isStringLiteral(element)) {
903
+ result.push(element.text);
904
+ } else if (ts.isNoSubstitutionTemplateLiteral(element)) {
905
+ result.push(element.text);
906
+ }
907
+ }
908
+ return result;
909
+ }
910
+ function extractLiteralValue(expr) {
911
+ if (ts.isStringLiteral(expr)) {
912
+ return expr.text;
913
+ }
914
+ if (ts.isNumericLiteral(expr)) {
915
+ return Number(expr.text);
916
+ }
917
+ if (expr.kind === ts.SyntaxKind.TrueKeyword) {
918
+ return true;
919
+ }
920
+ if (expr.kind === ts.SyntaxKind.FalseKeyword) {
921
+ return false;
922
+ }
923
+ if (expr.kind === ts.SyntaxKind.NullKeyword) {
924
+ return null;
925
+ }
926
+ if (ts.isArrayLiteralExpression(expr)) {
927
+ return expr.elements.map(extractLiteralValue);
928
+ }
929
+ if (ts.isObjectLiteralExpression(expr)) {
930
+ const obj = {};
931
+ for (const prop of expr.properties) {
932
+ if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
933
+ obj[prop.name.text] = extractLiteralValue(prop.initializer);
934
+ }
935
+ }
936
+ return obj;
937
+ }
938
+ return void 0;
939
+ }
940
+
941
+ // src/core/previewLoader.ts
942
+ import { existsSync as existsSync3 } from "fs";
943
+ import { join as join2, resolve as resolve3 } from "path";
944
+ var PREVIEW_FILES = [
945
+ "preview.tsx",
946
+ "preview.ts",
947
+ "preview.jsx",
948
+ "preview.js"
949
+ ];
950
+ function findPreviewConfigPath(storybookDir) {
951
+ for (const fileName of PREVIEW_FILES) {
952
+ const filePath = join2(storybookDir, fileName);
953
+ if (existsSync3(filePath)) {
954
+ return filePath;
955
+ }
956
+ }
957
+ return null;
958
+ }
959
+ function findStorybookDir(projectRoot) {
960
+ const possiblePaths = [
961
+ join2(projectRoot, ".storybook"),
962
+ join2(projectRoot, "storybook")
963
+ ];
964
+ for (const dir of possiblePaths) {
965
+ if (existsSync3(dir)) {
966
+ return dir;
967
+ }
968
+ }
969
+ return null;
970
+ }
971
+ async function loadPreviewConfig(previewPath) {
972
+ try {
973
+ const fileUrl = new URL(`file://${resolve3(previewPath)}`);
974
+ const module = await import(fileUrl.href);
975
+ const config = {
976
+ decorators: module.decorators ?? module.default?.decorators ?? [],
977
+ parameters: module.parameters ?? module.default?.parameters ?? {},
978
+ globalTypes: module.globalTypes ?? module.default?.globalTypes ?? {},
979
+ args: module.args ?? module.default?.args ?? {},
980
+ argTypes: module.argTypes ?? module.default?.argTypes ?? {},
981
+ loaders: module.loaders ?? module.default?.loaders ?? []
982
+ };
983
+ return config;
984
+ } catch (error) {
985
+ console.warn(
986
+ `[Fragments] Failed to load preview config from ${previewPath}:`,
987
+ error instanceof Error ? error.message : error
988
+ );
989
+ return {};
990
+ }
991
+ }
992
+ async function autoLoadPreviewConfig(projectRoot) {
993
+ const storybookDir = findStorybookDir(projectRoot);
994
+ if (!storybookDir) {
995
+ return {};
996
+ }
997
+ const previewPath = findPreviewConfigPath(storybookDir);
998
+ if (!previewPath) {
999
+ return {};
1000
+ }
1001
+ return loadPreviewConfig(previewPath);
1002
+ }
1003
+ function generatePreviewModule(previewPath) {
1004
+ if (!previewPath) {
1005
+ return `
1006
+ export const decorators = [];
1007
+ export const parameters = {};
1008
+ export const globalTypes = {};
1009
+ export const args = {};
1010
+ export const argTypes = {};
1011
+ export const loaders = [];
1012
+
1013
+ export default {
1014
+ decorators,
1015
+ parameters,
1016
+ globalTypes,
1017
+ args,
1018
+ argTypes,
1019
+ loaders,
1020
+ };
1021
+ `;
1022
+ }
1023
+ return `
1024
+ import * as preview from "${previewPath}";
1025
+
1026
+ export const decorators = preview.decorators ?? preview.default?.decorators ?? [];
1027
+ export const parameters = preview.parameters ?? preview.default?.parameters ?? {};
1028
+ export const globalTypes = preview.globalTypes ?? preview.default?.globalTypes ?? {};
1029
+ export const args = preview.args ?? preview.default?.args ?? {};
1030
+ export const argTypes = preview.argTypes ?? preview.default?.argTypes ?? {};
1031
+ export const loaders = preview.loaders ?? preview.default?.loaders ?? [];
1032
+
1033
+ export default {
1034
+ decorators,
1035
+ parameters,
1036
+ globalTypes,
1037
+ args,
1038
+ argTypes,
1039
+ loaders,
1040
+ };
1041
+ `;
1042
+ }
1043
+
1044
+ // src/core/generators/typescript-extractor.ts
1045
+ import ts2 from "typescript";
1046
+ import { readFileSync } from "fs";
1047
+ function extractPropsFromFile(filePath) {
1048
+ const sourceText = readFileSync(filePath, "utf-8");
1049
+ return extractPropsFromSource(sourceText, filePath);
1050
+ }
1051
+ function extractPropsFromSource(sourceText, fileName = "component.tsx") {
1052
+ const sourceFile = ts2.createSourceFile(
1053
+ fileName,
1054
+ sourceText,
1055
+ ts2.ScriptTarget.Latest,
1056
+ true,
1057
+ fileName.endsWith(".tsx") ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS
1058
+ );
1059
+ const result = {
1060
+ componentName: "",
1061
+ props: {},
1062
+ exports: [],
1063
+ imports: []
1064
+ };
1065
+ const propsInterfaces = /* @__PURE__ */ new Map();
1066
+ const componentExports = [];
1067
+ const defaultExports = /* @__PURE__ */ new Set();
1068
+ const importedModules = [];
1069
+ ts2.forEachChild(sourceFile, (node) => {
1070
+ if (ts2.isImportDeclaration(node)) {
1071
+ const moduleSpecifier = node.moduleSpecifier;
1072
+ if (ts2.isStringLiteral(moduleSpecifier)) {
1073
+ importedModules.push(moduleSpecifier.text);
1074
+ }
1075
+ }
1076
+ if (ts2.isInterfaceDeclaration(node)) {
1077
+ const name = node.name.text;
1078
+ if (name.endsWith("Props")) {
1079
+ propsInterfaces.set(name, node);
1080
+ }
1081
+ }
1082
+ if (ts2.isTypeAliasDeclaration(node)) {
1083
+ const name = node.name.text;
1084
+ if (name.endsWith("Props")) {
1085
+ propsInterfaces.set(name, node);
1086
+ }
1087
+ }
1088
+ if (ts2.isFunctionDeclaration(node) && node.name) {
1089
+ const hasExport = node.modifiers?.some(
1090
+ (m) => m.kind === ts2.SyntaxKind.ExportKeyword
1091
+ );
1092
+ const hasDefault = node.modifiers?.some(
1093
+ (m) => m.kind === ts2.SyntaxKind.DefaultKeyword
1094
+ );
1095
+ if (hasExport) {
1096
+ componentExports.push(node.name.text);
1097
+ if (hasDefault) {
1098
+ defaultExports.add(node.name.text);
1099
+ }
1100
+ }
1101
+ }
1102
+ if (ts2.isVariableStatement(node)) {
1103
+ const hasExport = node.modifiers?.some(
1104
+ (m) => m.kind === ts2.SyntaxKind.ExportKeyword
1105
+ );
1106
+ if (hasExport) {
1107
+ for (const decl of node.declarationList.declarations) {
1108
+ if (ts2.isIdentifier(decl.name)) {
1109
+ componentExports.push(decl.name.text);
1110
+ }
1111
+ }
1112
+ }
1113
+ }
1114
+ if (ts2.isExportDeclaration(node) && node.exportClause) {
1115
+ if (ts2.isNamedExports(node.exportClause)) {
1116
+ for (const element of node.exportClause.elements) {
1117
+ componentExports.push(element.name.text);
1118
+ }
1119
+ }
1120
+ }
1121
+ });
1122
+ result.exports = componentExports;
1123
+ result.imports = importedModules;
1124
+ const mainComponent = componentExports.find(
1125
+ (name) => /^[A-Z]/.test(name) && !name.endsWith("Props")
1126
+ );
1127
+ if (!mainComponent) {
1128
+ return null;
1129
+ }
1130
+ result.componentName = mainComponent;
1131
+ result.isDefaultExport = defaultExports.has(mainComponent);
1132
+ const propsInterfaceName = `${mainComponent}Props`;
1133
+ const propsInterface = propsInterfaces.get(propsInterfaceName);
1134
+ if (propsInterface) {
1135
+ result.propsInterfaceName = propsInterfaceName;
1136
+ result.props = extractPropsFromInterface(propsInterface, sourceFile);
1137
+ }
1138
+ return result;
1139
+ }
1140
+ function extractPropsFromInterface(node, sourceFile) {
1141
+ const props = {};
1142
+ if (ts2.isInterfaceDeclaration(node)) {
1143
+ for (const member of node.members) {
1144
+ if (ts2.isPropertySignature(member) && member.name) {
1145
+ const propName = member.name.getText(sourceFile);
1146
+ const prop = extractPropFromMember(member, sourceFile);
1147
+ if (prop) {
1148
+ props[propName] = prop;
1149
+ }
1150
+ }
1151
+ }
1152
+ }
1153
+ if (ts2.isTypeAliasDeclaration(node)) {
1154
+ const typeNode = node.type;
1155
+ if (ts2.isTypeLiteralNode(typeNode)) {
1156
+ for (const member of typeNode.members) {
1157
+ if (ts2.isPropertySignature(member) && member.name) {
1158
+ const propName = member.name.getText(sourceFile);
1159
+ const prop = extractPropFromMember(member, sourceFile);
1160
+ if (prop) {
1161
+ props[propName] = prop;
1162
+ }
1163
+ }
1164
+ }
1165
+ }
1166
+ }
1167
+ return props;
1168
+ }
1169
+ function extractPropFromMember(member, sourceFile) {
1170
+ const entry = {};
1171
+ entry.required = !member.questionToken;
1172
+ if (member.type) {
1173
+ const typeInfo = parseTypeNode(member.type, sourceFile);
1174
+ entry.type = typeInfo.type;
1175
+ entry.typeKind = typeInfo.typeKind;
1176
+ if (typeInfo.options) {
1177
+ entry.options = typeInfo.options;
1178
+ }
1179
+ }
1180
+ const jsDocComment = getJSDocComment(member);
1181
+ if (jsDocComment) {
1182
+ entry.description = jsDocComment;
1183
+ }
1184
+ const defaultValue = getJSDocDefault(member);
1185
+ if (defaultValue !== void 0) {
1186
+ entry.default = defaultValue;
1187
+ }
1188
+ return entry;
1189
+ }
1190
+ function parseTypeNode(typeNode, sourceFile) {
1191
+ if (typeNode.kind === ts2.SyntaxKind.StringKeyword) {
1192
+ return { type: "string", typeKind: "string" };
1193
+ }
1194
+ if (typeNode.kind === ts2.SyntaxKind.NumberKeyword) {
1195
+ return { type: "number", typeKind: "number" };
1196
+ }
1197
+ if (typeNode.kind === ts2.SyntaxKind.BooleanKeyword) {
1198
+ return { type: "boolean", typeKind: "boolean" };
1199
+ }
1200
+ if (ts2.isUnionTypeNode(typeNode)) {
1201
+ const options = [];
1202
+ let allLiterals = true;
1203
+ for (const subType of typeNode.types) {
1204
+ if (ts2.isLiteralTypeNode(subType)) {
1205
+ if (ts2.isStringLiteral(subType.literal)) {
1206
+ options.push(subType.literal.text);
1207
+ } else if (subType.literal.kind === ts2.SyntaxKind.TrueKeyword) {
1208
+ options.push("true");
1209
+ } else if (subType.literal.kind === ts2.SyntaxKind.FalseKeyword) {
1210
+ options.push("false");
1211
+ } else {
1212
+ allLiterals = false;
1213
+ }
1214
+ } else {
1215
+ allLiterals = false;
1216
+ }
1217
+ }
1218
+ if (allLiterals && options.length > 0) {
1219
+ return {
1220
+ type: options.map((o) => `"${o}"`).join(" | "),
1221
+ typeKind: "enum",
1222
+ options
1223
+ };
1224
+ }
1225
+ return {
1226
+ type: typeNode.getText(sourceFile),
1227
+ typeKind: "union"
1228
+ };
1229
+ }
1230
+ if (ts2.isFunctionTypeNode(typeNode)) {
1231
+ return {
1232
+ type: typeNode.getText(sourceFile),
1233
+ typeKind: "function"
1234
+ };
1235
+ }
1236
+ if (ts2.isArrayTypeNode(typeNode)) {
1237
+ return {
1238
+ type: typeNode.getText(sourceFile),
1239
+ typeKind: "array"
1240
+ };
1241
+ }
1242
+ if (ts2.isTypeReferenceNode(typeNode)) {
1243
+ const typeName = typeNode.typeName.getText(sourceFile);
1244
+ if (typeName === "ReactNode" || typeName === "React.ReactNode") {
1245
+ return { type: "ReactNode", typeKind: "node" };
1246
+ }
1247
+ if (typeName === "ReactElement" || typeName === "React.ReactElement") {
1248
+ return { type: "ReactElement", typeKind: "element" };
1249
+ }
1250
+ if (typeName === "JSX.Element") {
1251
+ return { type: "JSX.Element", typeKind: "element" };
1252
+ }
1253
+ return {
1254
+ type: typeNode.getText(sourceFile),
1255
+ typeKind: "object"
1256
+ };
1257
+ }
1258
+ if (ts2.isTypeLiteralNode(typeNode)) {
1259
+ return {
1260
+ type: typeNode.getText(sourceFile),
1261
+ typeKind: "object"
1262
+ };
1263
+ }
1264
+ return {
1265
+ type: typeNode.getText(sourceFile),
1266
+ typeKind: "unknown"
1267
+ };
1268
+ }
1269
+ function getJSDocComment(node) {
1270
+ const jsDocTags = ts2.getJSDocTags(node);
1271
+ const jsDoc = node.jsDoc;
1272
+ if (jsDoc && jsDoc.length > 0) {
1273
+ const comment = jsDoc[0].comment;
1274
+ if (typeof comment === "string") {
1275
+ return comment;
1276
+ }
1277
+ if (Array.isArray(comment)) {
1278
+ return comment.map((c) => typeof c === "string" ? c : c.text).join("");
1279
+ }
1280
+ }
1281
+ return void 0;
1282
+ }
1283
+ function getJSDocDefault(node) {
1284
+ const jsDocTags = ts2.getJSDocTags(node);
1285
+ for (const tag of jsDocTags) {
1286
+ if (tag.tagName.text === "default") {
1287
+ const comment = tag.comment;
1288
+ if (typeof comment === "string") {
1289
+ try {
1290
+ return JSON.parse(comment);
1291
+ } catch {
1292
+ return comment;
1293
+ }
1294
+ }
1295
+ }
1296
+ }
1297
+ return void 0;
1298
+ }
1299
+
1300
+ // src/core/generators/registry.ts
1301
+ import { readFileSync as readFileSync2 } from "fs";
1302
+ import { relative, dirname as dirname4, basename as basename3, join as join3 } from "path";
1303
+ import fg2 from "fast-glob";
1304
+ async function generateRegistry(options) {
1305
+ const {
1306
+ projectRoot,
1307
+ componentPatterns = ["src/**/*.tsx", "src/**/*.ts"],
1308
+ storyPatterns = ["src/**/*.stories.tsx", "src/**/*.stories.ts"],
1309
+ fragmentsDir = join3(projectRoot, BRAND.dataDir),
1310
+ registryOptions = {}
1311
+ } = options;
1312
+ const {
1313
+ requireStory = false,
1314
+ publicOnly = false,
1315
+ categoryDepth = 1,
1316
+ includeProps = false,
1317
+ embedFragments = false
1318
+ } = registryOptions;
1319
+ const errors = [];
1320
+ const warnings = [];
1321
+ const storyFiles = await fg2(storyPatterns, {
1322
+ cwd: projectRoot,
1323
+ ignore: ["**/node_modules/**"],
1324
+ absolute: true
364
1325
  });
365
1326
  const storyMap = /* @__PURE__ */ new Map();
366
1327
  for (const storyPath of storyFiles) {
367
- const storyDir = dirname2(storyPath);
368
- const storyBase = basename(storyPath).replace(/\.stories\.(tsx?|jsx?)$/, "");
1328
+ const storyDir = dirname4(storyPath);
1329
+ const storyBase = basename3(storyPath).replace(/\.stories\.(tsx?|jsx?)$/, "");
369
1330
  storyMap.set(`${storyDir}/${storyBase}`, storyPath);
370
1331
  }
371
- const componentFiles = await fg(componentPatterns, {
1332
+ const componentFiles = await fg2(componentPatterns, {
372
1333
  cwd: projectRoot,
373
1334
  ignore: [
374
1335
  "**/node_modules/**",
@@ -379,18 +1340,18 @@ async function generateRegistry(options) {
379
1340
  ],
380
1341
  absolute: true
381
1342
  });
382
- const fragmentPattern = join(
1343
+ const fragmentPattern = join3(
383
1344
  BRAND.dataDir,
384
1345
  BRAND.componentsDir,
385
1346
  `*${BRAND.fileExtension}`
386
1347
  );
387
- const fragmentFiles = await fg(fragmentPattern, {
1348
+ const fragmentFiles = await fg2(fragmentPattern, {
388
1349
  cwd: projectRoot,
389
1350
  absolute: true
390
1351
  });
391
1352
  const fragmentMap = /* @__PURE__ */ new Map();
392
1353
  for (const fragmentPath of fragmentFiles) {
393
- const fragmentName = basename(fragmentPath).replace(BRAND.fileExtension, "");
1354
+ const fragmentName = basename3(fragmentPath).replace(BRAND.fileExtension, "");
394
1355
  try {
395
1356
  const content = readFileSync2(fragmentPath, "utf-8");
396
1357
  const fragment = JSON.parse(content);
@@ -419,8 +1380,8 @@ async function generateRegistry(options) {
419
1380
  if (publicOnly && !extracted.exports.includes(componentName)) {
420
1381
  continue;
421
1382
  }
422
- const componentDir = dirname2(filePath);
423
- const baseNameWithoutExt = basename(filePath).replace(/\.(tsx?|jsx?)$/, "");
1383
+ const componentDir = dirname4(filePath);
1384
+ const baseNameWithoutExt = basename3(filePath).replace(/\.(tsx?|jsx?)$/, "");
424
1385
  const storyPath = storyMap.get(`${componentDir}/${baseNameWithoutExt}`);
425
1386
  if (requireStory && !storyPath) {
426
1387
  continue;
@@ -533,880 +1494,433 @@ function hasRealEnrichment(fragment) {
533
1494
  return true;
534
1495
  }
535
1496
  if (fragment.related?.similar && fragment.related.similar.length > 0) {
536
- return true;
537
- }
538
- return false;
539
- }
540
-
541
- // src/core/generators/context.ts
542
- function generateContextMd(registry, options = {}) {
543
- const {
544
- format = "markdown",
545
- compact = false,
546
- include = { props: true, relations: true, code: false }
547
- } = options;
548
- if (format === "json") {
549
- return generateJsonContext(registry, include, compact);
550
- }
551
- return generateMarkdownContext(registry, include, compact);
552
- }
553
- function generateMarkdownContext(registry, include, compact) {
554
- const lines = [];
555
- const componentNames = Object.keys(registry.components).sort();
556
- const componentCount = componentNames.length;
557
- lines.push("# Component Library Context");
558
- lines.push(`Generated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]} | Components: ${componentCount}`);
559
- lines.push("");
560
- lines.push("## Quick Reference");
561
- lines.push("");
562
- lines.push("| Component | Path | Category | Status |");
563
- lines.push("|-----------|------|----------|--------|");
564
- for (const name of componentNames) {
565
- const entry = registry.components[name];
566
- const status = entry.status || "stable";
567
- const category = entry.category || "-";
568
- lines.push(`| ${name} | ${entry.path} | ${category} | ${status} |`);
569
- }
570
- lines.push("");
571
- if (compact) {
572
- const content2 = lines.join("\n");
573
- return {
574
- content: content2,
575
- tokenEstimate: estimateTokens(content2),
576
- componentCount
577
- };
578
- }
579
- lines.push("---");
580
- lines.push("");
581
- for (const name of componentNames) {
582
- const entry = registry.components[name];
583
- const fragment = entry.fragment;
584
- lines.push(`## ${name}`);
585
- lines.push(`**Path:** \`${entry.path}\``);
586
- if (entry.category) {
587
- lines.push(`**Category:** ${entry.category} | **Status:** ${entry.status || "stable"}`);
588
- }
589
- lines.push("");
590
- if (entry.description || fragment?.description) {
591
- lines.push("### Description");
592
- lines.push(entry.description || fragment?.description || "");
593
- lines.push("");
594
- }
595
- if (fragment?.usage) {
596
- if (fragment.usage.when && fragment.usage.when.length > 0) {
597
- lines.push("### When to Use");
598
- for (const when of fragment.usage.when) {
599
- lines.push(`- ${when}`);
600
- }
601
- lines.push("");
602
- }
603
- if (fragment.usage.doNot && fragment.usage.doNot.length > 0) {
604
- lines.push("### Do Not");
605
- for (const doNotItem of fragment.usage.doNot) {
606
- if (typeof doNotItem === "string") {
607
- lines.push(`- ${doNotItem}`);
608
- } else {
609
- const item = doNotItem;
610
- if (item.instead) {
611
- const alternativePath = resolveComponentPath(item.instead, registry);
612
- if (alternativePath) {
613
- lines.push(`- ${item.text} \u2192 use **${item.instead}** (\`${alternativePath}\`)`);
614
- } else {
615
- lines.push(`- ${item.text} \u2192 use **${item.instead}**`);
616
- }
617
- } else {
618
- lines.push(`- ${item.text}`);
619
- }
620
- }
621
- }
622
- lines.push("");
623
- }
624
- if (include.code && fragment.usage.patterns && fragment.usage.patterns.length > 0) {
625
- lines.push("### Patterns");
626
- for (const pattern of fragment.usage.patterns) {
627
- lines.push(`**${pattern.name}**`);
628
- if (pattern.description) {
629
- lines.push(pattern.description);
630
- }
631
- lines.push("```tsx");
632
- lines.push(pattern.code);
633
- lines.push("```");
634
- lines.push("");
635
- }
636
- }
637
- }
638
- if (include.props && entry.props && Object.keys(entry.props).length > 0) {
639
- lines.push("### Props");
640
- lines.push("| Prop | Type | Default | Description |");
641
- lines.push("|------|------|---------|-------------|");
642
- for (const [propName, prop] of Object.entries(entry.props)) {
643
- const type = formatPropType(prop);
644
- const defaultVal = prop.default !== void 0 ? `\`${JSON.stringify(prop.default)}\`` : "-";
645
- const desc = prop.description || "-";
646
- const required = prop.required ? " (required)" : "";
647
- lines.push(`| ${propName}${required} | ${type} | ${defaultVal} | ${desc} |`);
648
- }
649
- lines.push("");
650
- }
651
- if (fragment?.accessibility) {
652
- lines.push("### Accessibility");
653
- if (fragment.accessibility.role) {
654
- lines.push(`**Role:** ${fragment.accessibility.role}`);
655
- }
656
- if (fragment.accessibility.requirements && fragment.accessibility.requirements.length > 0) {
657
- for (const req of fragment.accessibility.requirements) {
658
- lines.push(`- ${req}`);
659
- }
660
- }
661
- if (fragment.accessibility.keyboard) {
662
- lines.push("");
663
- lines.push("**Keyboard:**");
664
- for (const [key, action] of Object.entries(fragment.accessibility.keyboard)) {
665
- lines.push(`- \`${key}\`: ${action}`);
666
- }
667
- }
668
- lines.push("");
669
- }
670
- if (include.relations && fragment?.related) {
671
- lines.push("### Related");
672
- if (fragment.related.similar && fragment.related.similar.length > 0) {
673
- const resolved = fragment.related.similar.map((comp) => {
674
- const path = resolveComponentPath(comp, registry);
675
- return path ? `${comp} (\`${path}\`)` : comp;
676
- });
677
- lines.push(`- **Similar:** ${resolved.join(", ")}`);
678
- }
679
- if (fragment.related.composedWith && fragment.related.composedWith.length > 0) {
680
- const resolved = fragment.related.composedWith.map((comp) => {
681
- const path = resolveComponentPath(comp, registry);
682
- return path ? `${comp} (\`${path}\`)` : comp;
683
- });
684
- lines.push(`- **Composed with:** ${resolved.join(", ")}`);
685
- }
686
- if (fragment.related.usedIn && fragment.related.usedIn.length > 0) {
687
- const resolved = fragment.related.usedIn.map((comp) => {
688
- const path = resolveComponentPath(comp, registry);
689
- return path ? `${comp} (\`${path}\`)` : comp;
690
- });
691
- lines.push(`- **Used in:** ${resolved.join(", ")}`);
692
- }
693
- lines.push("");
694
- }
695
- lines.push("---");
696
- lines.push("");
697
- }
698
- const content = lines.join("\n");
699
- return {
700
- content,
701
- tokenEstimate: estimateTokens(content),
702
- componentCount
703
- };
704
- }
705
- function generateJsonContext(registry, include, compact) {
706
- const componentNames = Object.keys(registry.components).sort();
707
- const componentCount = componentNames.length;
708
- const components = {};
709
- for (const name of componentNames) {
710
- const entry = registry.components[name];
711
- const fragment = entry.fragment;
712
- const component = {
713
- path: entry.path
714
- };
715
- if (entry.category) component.category = entry.category;
716
- if (entry.status) component.status = entry.status;
717
- if (entry.description || fragment?.description) {
718
- component.description = entry.description || fragment?.description;
719
- }
720
- if (!compact && fragment?.usage) {
721
- if (fragment.usage.when && fragment.usage.when.length > 0) {
722
- component.whenToUse = fragment.usage.when;
723
- }
724
- if (fragment.usage.doNot && fragment.usage.doNot.length > 0) {
725
- component.doNot = fragment.usage.doNot.map((item) => {
726
- if (typeof item === "string") {
727
- return { text: item };
728
- }
729
- const doNotItem = item;
730
- const result = {
731
- text: doNotItem.text
732
- };
733
- if (doNotItem.instead) {
734
- result.instead = doNotItem.instead;
735
- result.insteadPath = resolveComponentPath(doNotItem.instead, registry);
736
- }
737
- return result;
738
- });
739
- }
740
- }
741
- if (!compact && include.props && entry.props) {
742
- component.props = {};
743
- for (const [propName, prop] of Object.entries(entry.props)) {
744
- component.props[propName] = {
745
- type: formatPropType(prop)
746
- };
747
- if (prop.required) component.props[propName].required = true;
748
- if (prop.default !== void 0) component.props[propName].default = prop.default;
749
- if (prop.description) component.props[propName].description = prop.description;
750
- }
751
- }
752
- if (!compact && include.relations && fragment?.related) {
753
- component.related = {};
754
- if (fragment.related.similar) {
755
- component.related.similar = fragment.related.similar.map((name2) => ({
756
- name: name2,
757
- path: resolveComponentPath(name2, registry)
758
- }));
759
- }
760
- if (fragment.related.composedWith) {
761
- component.related.composedWith = fragment.related.composedWith.map((name2) => ({
762
- name: name2,
763
- path: resolveComponentPath(name2, registry)
764
- }));
765
- }
766
- if (fragment.related.usedIn) {
767
- component.related.usedIn = fragment.related.usedIn.map((name2) => ({
768
- name: name2,
769
- path: resolveComponentPath(name2, registry)
770
- }));
771
- }
772
- }
773
- components[name] = component;
1497
+ return true;
774
1498
  }
775
- const output = {
776
- version: "1.0",
777
- generatedAt: registry.generatedAt,
778
- componentCount,
779
- categories: registry.categories,
780
- components
781
- };
782
- const content = JSON.stringify(output, null, 2);
783
- return {
784
- content,
785
- tokenEstimate: estimateTokens(content),
786
- componentCount
787
- };
1499
+ return false;
788
1500
  }
789
1501
  function resolveComponentPath(componentName, registry) {
790
- return registry.components[componentName]?.path;
1502
+ const entry = registry.components[componentName];
1503
+ return entry?.path;
791
1504
  }
792
- function formatPropType(prop) {
793
- if (prop.options && prop.options.length > 0) {
794
- return prop.options.map((o) => `"${o}"`).join(" \\| ");
795
- }
796
- return prop.type || "unknown";
797
- }
798
- function estimateTokens(text) {
799
- return Math.ceil(text.length / 4);
1505
+ function getComponentsByCategory(category, registry) {
1506
+ return registry.categories?.[category] || [];
800
1507
  }
801
1508
 
802
- // src/core/loader.ts
803
- import { unlink } from "fs/promises";
804
- import { dirname as dirname3, basename as basename2, join as join2 } from "path";
805
- import { pathToFileURL } from "url";
806
- import { build } from "esbuild";
807
- var DEFINE_FRAGMENT_SHIM = `
808
- export function defineFragment(def) {
809
- return def;
810
- }
811
- export function defineBlock(def) {
812
- return def;
813
- }
814
- export function defineRecipe(def) {
815
- return def;
816
- }
817
- `;
818
- function createFragmentsCoreShimPlugin() {
819
- return {
820
- name: BRAND.vitePluginNamespace,
821
- setup(build2) {
822
- build2.onResolve({ filter: /^@fragments-sdk\/cli\/core$/ }, (args) => {
823
- return {
824
- path: args.path,
825
- namespace: BRAND.vitePluginNamespace
826
- };
827
- });
828
- build2.onLoad({ filter: /.*/, namespace: BRAND.vitePluginNamespace }, () => {
829
- return {
830
- contents: DEFINE_FRAGMENT_SHIM,
831
- loader: "js"
832
- };
833
- });
834
- }
835
- };
836
- }
837
- async function loadFragmentFile(absolutePath) {
838
- const unwrapFragmentExport = (value) => {
839
- if (!value) return null;
840
- const asObject = (v) => v && typeof v === "object" ? v : null;
841
- const isFragmentLike = (v) => {
842
- const obj = asObject(v);
843
- return !!obj && ("component" in obj || "meta" in obj || "variants" in obj);
844
- };
845
- if (isFragmentLike(value)) {
846
- return value;
847
- }
848
- const first = asObject(value)?.default;
849
- if (isFragmentLike(first)) {
850
- return first;
851
- }
852
- const second = asObject(first)?.default;
853
- if (isFragmentLike(second)) {
854
- return second;
855
- }
856
- return value ?? null;
857
- };
858
- const ext = absolutePath.split(".").pop()?.toLowerCase();
859
- const needsTransform = ext === "tsx" || ext === "ts" || ext === "jsx";
860
- if (!needsTransform) {
861
- const fileUrl = pathToFileURL(absolutePath).href;
862
- const module = await import(fileUrl);
863
- return unwrapFragmentExport(module.default ?? null);
864
- }
865
- const sourceDir = dirname3(absolutePath);
866
- const baseName = basename2(absolutePath, `.${ext}`);
867
- const tempFile = join2(sourceDir, `.${baseName}.fragments-temp-${Date.now()}.mjs`);
868
- try {
869
- await build({
870
- entryPoints: [absolutePath],
871
- outfile: tempFile,
872
- bundle: true,
873
- format: "esm",
874
- target: "es2022",
875
- jsx: "automatic",
876
- platform: "node",
877
- plugins: [createFragmentsCoreShimPlugin()],
878
- // Externalize all node_modules - we only need fragment metadata, not component code
879
- packages: "external",
880
- // Also explicitly list patterns for nested imports
881
- external: [
882
- // React and its subpaths
883
- "react",
884
- "react-dom",
885
- "react/*",
886
- "react-dom/*"
887
- ],
888
- // Don't emit sourcemaps for temp files
889
- sourcemap: false,
890
- // Suppress warnings
891
- logLevel: "silent",
892
- // Use loader to ignore style imports
893
- loader: {
894
- ".scss": "empty",
895
- ".css": "empty",
896
- ".svg": "empty",
897
- ".png": "empty",
898
- ".jpg": "empty",
899
- ".jpeg": "empty",
900
- ".gif": "empty",
901
- ".woff": "empty",
902
- ".woff2": "empty",
903
- ".ttf": "empty",
904
- ".eot": "empty"
905
- }
906
- });
907
- const fileUrl = pathToFileURL(tempFile).href;
908
- const module = await import(fileUrl);
909
- return unwrapFragmentExport(module.default ?? null);
910
- } finally {
911
- try {
912
- await unlink(tempFile);
913
- } catch {
914
- }
1509
+ // src/core/generators/context.ts
1510
+ function generateContextMd(registry, options = {}) {
1511
+ const {
1512
+ format = "markdown",
1513
+ compact = false,
1514
+ include = { props: true, relations: true, code: false }
1515
+ } = options;
1516
+ if (format === "json") {
1517
+ return generateJsonContext(registry, include, compact);
915
1518
  }
1519
+ return generateMarkdownContext(registry, include, compact);
916
1520
  }
917
-
918
- // src/core/parser.ts
919
- import ts2 from "typescript";
920
- function parseFragmentFile(fileContent, filePath) {
921
- const warnings = [];
922
- const sourceFile = ts2.createSourceFile(
923
- filePath ?? "fragment.tsx",
924
- fileContent,
925
- ts2.ScriptTarget.Latest,
926
- true,
927
- ts2.ScriptKind.TSX
928
- );
929
- const imports = extractImports(sourceFile);
930
- const defineFragmentCall = findDefineFragmentCall(sourceFile);
931
- if (!defineFragmentCall) {
932
- warnings.push("No defineFragment() call found");
933
- return {
934
- componentImport: null,
935
- componentName: null,
936
- meta: {},
937
- usage: { when: [], whenNot: [] },
938
- props: {},
939
- variants: [],
940
- relations: [],
941
- warnings
942
- };
1521
+ function generateMarkdownContext(registry, include, compact) {
1522
+ const lines = [];
1523
+ const componentNames = Object.keys(registry.components).sort();
1524
+ const componentCount = componentNames.length;
1525
+ lines.push("# Component Library Context");
1526
+ lines.push(`Generated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]} | Components: ${componentCount}`);
1527
+ lines.push("");
1528
+ lines.push("## Quick Reference");
1529
+ lines.push("");
1530
+ lines.push("| Component | Path | Category | Status |");
1531
+ lines.push("|-----------|------|----------|--------|");
1532
+ for (const name of componentNames) {
1533
+ const entry = registry.components[name];
1534
+ const status = entry.status || "stable";
1535
+ const category = entry.category || "-";
1536
+ lines.push(`| ${name} | ${entry.path} | ${category} | ${status} |`);
943
1537
  }
944
- const arg = defineFragmentCall.arguments[0];
945
- if (!arg || !ts2.isObjectLiteralExpression(arg)) {
946
- warnings.push("defineFragment() argument is not an object literal");
1538
+ lines.push("");
1539
+ if (compact) {
1540
+ const content2 = lines.join("\n");
947
1541
  return {
948
- componentImport: null,
949
- componentName: null,
950
- meta: {},
951
- usage: { when: [], whenNot: [] },
952
- props: {},
953
- variants: [],
954
- relations: [],
955
- warnings
1542
+ content: content2,
1543
+ tokenEstimate: estimateTokens(content2),
1544
+ componentCount
956
1545
  };
957
1546
  }
958
- const componentProp = findProperty(arg, "component");
959
- let componentName = null;
960
- let componentImport = null;
961
- if (componentProp && ts2.isIdentifier(componentProp)) {
962
- componentName = componentProp.text;
963
- componentImport = imports.get(componentName) ?? null;
964
- }
965
- const meta = extractMeta(arg, warnings);
966
- const usage = extractUsage(arg, warnings);
967
- const props = extractProps(arg, warnings);
968
- const variants = extractVariants(arg, sourceFile, warnings);
969
- const relations = extractRelations(arg, warnings);
970
- const ai = extractAIMetadata(arg, warnings);
971
- const contract = extractContractMetadata(arg);
972
- return {
973
- componentImport,
974
- componentName,
975
- meta,
976
- usage,
977
- props,
978
- variants,
979
- relations,
980
- ai,
981
- contract,
982
- warnings
983
- };
984
- }
985
- function extractImports(sourceFile) {
986
- const imports = /* @__PURE__ */ new Map();
987
- ts2.forEachChild(sourceFile, (node) => {
988
- if (ts2.isImportDeclaration(node)) {
989
- const moduleSpecifier = node.moduleSpecifier;
990
- if (ts2.isStringLiteral(moduleSpecifier)) {
991
- const modulePath = moduleSpecifier.text;
992
- const importClause = node.importClause;
993
- if (importClause) {
994
- if (importClause.name) {
995
- imports.set(importClause.name.text, modulePath);
996
- }
997
- const namedBindings = importClause.namedBindings;
998
- if (namedBindings && ts2.isNamedImports(namedBindings)) {
999
- for (const element of namedBindings.elements) {
1000
- imports.set(element.name.text, modulePath);
1547
+ lines.push("---");
1548
+ lines.push("");
1549
+ for (const name of componentNames) {
1550
+ const entry = registry.components[name];
1551
+ const fragment = entry.fragment;
1552
+ lines.push(`## ${name}`);
1553
+ lines.push(`**Path:** \`${entry.path}\``);
1554
+ if (entry.category) {
1555
+ lines.push(`**Category:** ${entry.category} | **Status:** ${entry.status || "stable"}`);
1556
+ }
1557
+ lines.push("");
1558
+ if (entry.description || fragment?.description) {
1559
+ lines.push("### Description");
1560
+ lines.push(entry.description || fragment?.description || "");
1561
+ lines.push("");
1562
+ }
1563
+ if (fragment?.usage) {
1564
+ if (fragment.usage.when && fragment.usage.when.length > 0) {
1565
+ lines.push("### When to Use");
1566
+ for (const when of fragment.usage.when) {
1567
+ lines.push(`- ${when}`);
1568
+ }
1569
+ lines.push("");
1570
+ }
1571
+ if (fragment.usage.doNot && fragment.usage.doNot.length > 0) {
1572
+ lines.push("### Do Not");
1573
+ for (const doNotItem of fragment.usage.doNot) {
1574
+ if (typeof doNotItem === "string") {
1575
+ lines.push(`- ${doNotItem}`);
1576
+ } else {
1577
+ const item = doNotItem;
1578
+ if (item.instead) {
1579
+ const alternativePath = resolveComponentPath2(item.instead, registry);
1580
+ if (alternativePath) {
1581
+ lines.push(`- ${item.text} \u2192 use **${item.instead}** (\`${alternativePath}\`)`);
1582
+ } else {
1583
+ lines.push(`- ${item.text} \u2192 use **${item.instead}**`);
1584
+ }
1585
+ } else {
1586
+ lines.push(`- ${item.text}`);
1001
1587
  }
1002
1588
  }
1003
1589
  }
1590
+ lines.push("");
1004
1591
  }
1005
- }
1006
- });
1007
- return imports;
1008
- }
1009
- function findDefineFragmentCall(sourceFile) {
1010
- let result = null;
1011
- function visit(node) {
1012
- if (ts2.isCallExpression(node)) {
1013
- const expression = node.expression;
1014
- if (ts2.isIdentifier(expression) && expression.text === "defineFragment") {
1015
- result = node;
1016
- return;
1592
+ if (include.code && fragment.usage.patterns && fragment.usage.patterns.length > 0) {
1593
+ lines.push("### Patterns");
1594
+ for (const pattern of fragment.usage.patterns) {
1595
+ lines.push(`**${pattern.name}**`);
1596
+ if (pattern.description) {
1597
+ lines.push(pattern.description);
1598
+ }
1599
+ lines.push("```tsx");
1600
+ lines.push(pattern.code);
1601
+ lines.push("```");
1602
+ lines.push("");
1603
+ }
1017
1604
  }
1018
1605
  }
1019
- ts2.forEachChild(node, visit);
1020
- }
1021
- visit(sourceFile);
1022
- return result;
1023
- }
1024
- function findProperty(obj, name) {
1025
- for (const prop of obj.properties) {
1026
- if (ts2.isPropertyAssignment(prop)) {
1027
- const propName = prop.name;
1028
- if (ts2.isIdentifier(propName) && propName.text === name) {
1029
- return prop.initializer;
1606
+ if (include.props && entry.props && Object.keys(entry.props).length > 0) {
1607
+ lines.push("### Props");
1608
+ lines.push("| Prop | Type | Default | Description |");
1609
+ lines.push("|------|------|---------|-------------|");
1610
+ for (const [propName, prop] of Object.entries(entry.props)) {
1611
+ const type = formatPropType(prop);
1612
+ const defaultVal = prop.default !== void 0 ? `\`${JSON.stringify(prop.default)}\`` : "-";
1613
+ const desc = prop.description || "-";
1614
+ const required = prop.required ? " (required)" : "";
1615
+ lines.push(`| ${propName}${required} | ${type} | ${defaultVal} | ${desc} |`);
1030
1616
  }
1617
+ lines.push("");
1031
1618
  }
1032
- }
1033
- return null;
1034
- }
1035
- function extractMeta(arg, warnings) {
1036
- const metaProp = findProperty(arg, "meta");
1037
- if (!metaProp || !ts2.isObjectLiteralExpression(metaProp)) {
1038
- warnings.push("No meta object found");
1039
- return {};
1040
- }
1041
- const meta = {};
1042
- const name = extractStringProperty(metaProp, "name");
1043
- if (name) meta.name = name;
1044
- const description = extractStringProperty(metaProp, "description");
1045
- if (description) meta.description = description;
1046
- const category = extractStringProperty(metaProp, "category");
1047
- if (category) meta.category = category;
1048
- const status = extractStringProperty(metaProp, "status");
1049
- if (status) meta.status = status;
1050
- const since = extractStringProperty(metaProp, "since");
1051
- if (since) meta.since = since;
1052
- const figma = extractStringProperty(metaProp, "figma");
1053
- if (figma) meta.figma = figma;
1054
- const tags = extractStringArray(metaProp, "tags");
1055
- if (tags.length > 0) meta.tags = tags;
1056
- const depsProp = findProperty(metaProp, "dependencies");
1057
- if (depsProp && ts2.isArrayLiteralExpression(depsProp)) {
1058
- const deps = extractLiteralValue(depsProp);
1059
- if (Array.isArray(deps) && deps.length > 0) {
1060
- meta.dependencies = deps;
1061
- }
1062
- }
1063
- return meta;
1064
- }
1065
- function extractUsage(arg, warnings) {
1066
- const usageProp = findProperty(arg, "usage");
1067
- if (!usageProp || !ts2.isObjectLiteralExpression(usageProp)) {
1068
- return { when: [], whenNot: [] };
1069
- }
1070
- return {
1071
- when: extractStringArray(usageProp, "when"),
1072
- whenNot: extractStringArray(usageProp, "whenNot"),
1073
- guidelines: extractStringArray(usageProp, "guidelines"),
1074
- accessibility: extractStringArray(usageProp, "accessibility")
1075
- };
1076
- }
1077
- function extractProps(arg, warnings) {
1078
- const propsProp = findProperty(arg, "props");
1079
- if (!propsProp || !ts2.isObjectLiteralExpression(propsProp)) {
1080
- return {};
1081
- }
1082
- const props = {};
1083
- for (const prop of propsProp.properties) {
1084
- if (ts2.isPropertyAssignment(prop) && ts2.isIdentifier(prop.name)) {
1085
- const propName = prop.name.text;
1086
- const propValue = prop.initializer;
1087
- if (ts2.isObjectLiteralExpression(propValue)) {
1088
- props[propName] = extractPropDefinition(propValue);
1619
+ if (fragment?.accessibility) {
1620
+ lines.push("### Accessibility");
1621
+ if (fragment.accessibility.role) {
1622
+ lines.push(`**Role:** ${fragment.accessibility.role}`);
1089
1623
  }
1090
- }
1091
- }
1092
- return props;
1093
- }
1094
- function extractPropDefinition(obj) {
1095
- const def = {};
1096
- const type = extractStringProperty(obj, "type");
1097
- if (type) def.type = type;
1098
- const description = extractStringProperty(obj, "description");
1099
- if (description) def.description = description;
1100
- const values = extractStringArray(obj, "values");
1101
- if (values.length > 0) def.values = values;
1102
- const required = extractBooleanProperty(obj, "required");
1103
- if (required !== null) def.required = required;
1104
- const defaultProp = findProperty(obj, "default");
1105
- if (defaultProp) {
1106
- def.default = extractLiteralValue(defaultProp);
1107
- }
1108
- const constraints = extractStringArray(obj, "constraints");
1109
- if (constraints.length > 0) def.constraints = constraints;
1110
- return def;
1111
- }
1112
- function extractVariants(arg, sourceFile, warnings) {
1113
- const variantsProp = findProperty(arg, "variants");
1114
- if (!variantsProp || !ts2.isArrayLiteralExpression(variantsProp)) {
1115
- return [];
1116
- }
1117
- const variants = [];
1118
- for (const element of variantsProp.elements) {
1119
- if (ts2.isObjectLiteralExpression(element)) {
1120
- const name = extractStringProperty(element, "name");
1121
- const description = extractStringProperty(element, "description");
1122
- if (name) {
1123
- const variant = {
1124
- name,
1125
- description: description ?? ""
1126
- };
1127
- const codeProp = findProperty(element, "code");
1128
- if (codeProp && (ts2.isStringLiteral(codeProp) || ts2.isNoSubstitutionTemplateLiteral(codeProp))) {
1129
- variant.code = codeProp.text;
1130
- }
1131
- const renderProp = findProperty(element, "render");
1132
- if (renderProp && !variant.code) {
1133
- variant.code = extractRenderCode(renderProp, sourceFile);
1134
- }
1135
- const figma = extractStringProperty(element, "figma");
1136
- if (figma) {
1137
- variant.figma = figma;
1624
+ if (fragment.accessibility.requirements && fragment.accessibility.requirements.length > 0) {
1625
+ for (const req of fragment.accessibility.requirements) {
1626
+ lines.push(`- ${req}`);
1138
1627
  }
1139
- const argsProp = findProperty(element, "args");
1140
- if (argsProp && ts2.isObjectLiteralExpression(argsProp)) {
1141
- const argsValue = extractLiteralValue(argsProp);
1142
- if (argsValue && typeof argsValue === "object" && !Array.isArray(argsValue)) {
1143
- variant.args = argsValue;
1144
- }
1628
+ }
1629
+ if (fragment.accessibility.keyboard) {
1630
+ lines.push("");
1631
+ lines.push("**Keyboard:**");
1632
+ for (const [key, action] of Object.entries(fragment.accessibility.keyboard)) {
1633
+ lines.push(`- \`${key}\`: ${action}`);
1145
1634
  }
1146
- variants.push(variant);
1147
1635
  }
1636
+ lines.push("");
1148
1637
  }
1149
- }
1150
- return variants;
1151
- }
1152
- function dedent(str) {
1153
- const lines = str.split("\n");
1154
- if (lines.length <= 1) {
1155
- return str;
1156
- }
1157
- const firstLineIndent = lines[0].match(/^(\s*)/)?.[1].length ?? 0;
1158
- const startIndex = firstLineIndent === 0 ? 1 : 0;
1159
- let minIndent = Infinity;
1160
- for (let i = startIndex; i < lines.length; i++) {
1161
- const line = lines[i];
1162
- if (line.trim() === "") continue;
1163
- const match = line.match(/^(\s*)/);
1164
- if (match) {
1165
- minIndent = Math.min(minIndent, match[1].length);
1638
+ if (include.relations && fragment?.related) {
1639
+ lines.push("### Related");
1640
+ if (fragment.related.similar && fragment.related.similar.length > 0) {
1641
+ const resolved = fragment.related.similar.map((comp) => {
1642
+ const path = resolveComponentPath2(comp, registry);
1643
+ return path ? `${comp} (\`${path}\`)` : comp;
1644
+ });
1645
+ lines.push(`- **Similar:** ${resolved.join(", ")}`);
1646
+ }
1647
+ if (fragment.related.composedWith && fragment.related.composedWith.length > 0) {
1648
+ const resolved = fragment.related.composedWith.map((comp) => {
1649
+ const path = resolveComponentPath2(comp, registry);
1650
+ return path ? `${comp} (\`${path}\`)` : comp;
1651
+ });
1652
+ lines.push(`- **Composed with:** ${resolved.join(", ")}`);
1653
+ }
1654
+ if (fragment.related.usedIn && fragment.related.usedIn.length > 0) {
1655
+ const resolved = fragment.related.usedIn.map((comp) => {
1656
+ const path = resolveComponentPath2(comp, registry);
1657
+ return path ? `${comp} (\`${path}\`)` : comp;
1658
+ });
1659
+ lines.push(`- **Used in:** ${resolved.join(", ")}`);
1660
+ }
1661
+ lines.push("");
1166
1662
  }
1663
+ lines.push("---");
1664
+ lines.push("");
1167
1665
  }
1168
- if (minIndent === Infinity || minIndent === 0) {
1169
- return str;
1170
- }
1171
- return lines.map((line, index) => {
1172
- if (index === 0 && firstLineIndent === 0) {
1173
- return line;
1174
- }
1175
- return line.slice(minIndent);
1176
- }).join("\n");
1666
+ const content = lines.join("\n");
1667
+ return {
1668
+ content,
1669
+ tokenEstimate: estimateTokens(content),
1670
+ componentCount
1671
+ };
1177
1672
  }
1178
- function extractRenderCode(renderProp, sourceFile) {
1179
- if (ts2.isArrowFunction(renderProp)) {
1180
- const body = renderProp.body;
1181
- const start = body.getStart(sourceFile);
1182
- const end = body.getEnd();
1183
- let code = sourceFile.text.substring(start, end).trim();
1184
- if (code.startsWith("(") && code.endsWith(")")) {
1185
- code = code.slice(1, -1).trim();
1673
+ function generateJsonContext(registry, include, compact) {
1674
+ const componentNames = Object.keys(registry.components).sort();
1675
+ const componentCount = componentNames.length;
1676
+ const components = {};
1677
+ for (const name of componentNames) {
1678
+ const entry = registry.components[name];
1679
+ const fragment = entry.fragment;
1680
+ const component = {
1681
+ path: entry.path
1682
+ };
1683
+ if (entry.category) component.category = entry.category;
1684
+ if (entry.status) component.status = entry.status;
1685
+ if (entry.description || fragment?.description) {
1686
+ component.description = entry.description || fragment?.description;
1186
1687
  }
1187
- code = dedent(code);
1188
- return code;
1189
- }
1190
- return void 0;
1191
- }
1192
- function extractRelations(arg, warnings) {
1193
- const relationsProp = findProperty(arg, "relations");
1194
- if (!relationsProp || !ts2.isArrayLiteralExpression(relationsProp)) {
1195
- return [];
1196
- }
1197
- const relations = [];
1198
- for (const element of relationsProp.elements) {
1199
- if (ts2.isObjectLiteralExpression(element)) {
1200
- const component = extractStringProperty(element, "component");
1201
- const relationship = extractStringProperty(element, "relationship");
1202
- const note = extractStringProperty(element, "note");
1203
- if (component && relationship) {
1204
- relations.push({
1205
- component,
1206
- relationship,
1207
- note: note ?? ""
1688
+ if (!compact && fragment?.usage) {
1689
+ if (fragment.usage.when && fragment.usage.when.length > 0) {
1690
+ component.whenToUse = fragment.usage.when;
1691
+ }
1692
+ if (fragment.usage.doNot && fragment.usage.doNot.length > 0) {
1693
+ component.doNot = fragment.usage.doNot.map((item) => {
1694
+ if (typeof item === "string") {
1695
+ return { text: item };
1696
+ }
1697
+ const doNotItem = item;
1698
+ const result = {
1699
+ text: doNotItem.text
1700
+ };
1701
+ if (doNotItem.instead) {
1702
+ result.instead = doNotItem.instead;
1703
+ result.insteadPath = resolveComponentPath2(doNotItem.instead, registry);
1704
+ }
1705
+ return result;
1208
1706
  });
1209
1707
  }
1210
1708
  }
1709
+ if (!compact && include.props && entry.props) {
1710
+ component.props = {};
1711
+ for (const [propName, prop] of Object.entries(entry.props)) {
1712
+ component.props[propName] = {
1713
+ type: formatPropType(prop)
1714
+ };
1715
+ if (prop.required) component.props[propName].required = true;
1716
+ if (prop.default !== void 0) component.props[propName].default = prop.default;
1717
+ if (prop.description) component.props[propName].description = prop.description;
1718
+ }
1719
+ }
1720
+ if (!compact && include.relations && fragment?.related) {
1721
+ component.related = {};
1722
+ if (fragment.related.similar) {
1723
+ component.related.similar = fragment.related.similar.map((name2) => ({
1724
+ name: name2,
1725
+ path: resolveComponentPath2(name2, registry)
1726
+ }));
1727
+ }
1728
+ if (fragment.related.composedWith) {
1729
+ component.related.composedWith = fragment.related.composedWith.map((name2) => ({
1730
+ name: name2,
1731
+ path: resolveComponentPath2(name2, registry)
1732
+ }));
1733
+ }
1734
+ if (fragment.related.usedIn) {
1735
+ component.related.usedIn = fragment.related.usedIn.map((name2) => ({
1736
+ name: name2,
1737
+ path: resolveComponentPath2(name2, registry)
1738
+ }));
1739
+ }
1740
+ }
1741
+ components[name] = component;
1211
1742
  }
1212
- return relations;
1743
+ const output = {
1744
+ version: "1.0",
1745
+ generatedAt: registry.generatedAt,
1746
+ componentCount,
1747
+ categories: registry.categories,
1748
+ components
1749
+ };
1750
+ const content = JSON.stringify(output, null, 2);
1751
+ return {
1752
+ content,
1753
+ tokenEstimate: estimateTokens(content),
1754
+ componentCount
1755
+ };
1213
1756
  }
1214
- function extractAIMetadata(arg, warnings) {
1215
- const aiProp = findProperty(arg, "ai");
1216
- if (!aiProp || !ts2.isObjectLiteralExpression(aiProp)) {
1217
- return void 0;
1218
- }
1219
- const ai = {};
1220
- const compositionPattern = extractStringProperty(aiProp, "compositionPattern");
1221
- if (compositionPattern && ["compound", "simple", "controlled"].includes(compositionPattern)) {
1222
- ai.compositionPattern = compositionPattern;
1223
- }
1224
- const subComponents = extractStringArray(aiProp, "subComponents");
1225
- if (subComponents.length > 0) {
1226
- ai.subComponents = subComponents;
1227
- }
1228
- const requiredChildren = extractStringArray(aiProp, "requiredChildren");
1229
- if (requiredChildren.length > 0) {
1230
- ai.requiredChildren = requiredChildren;
1231
- }
1232
- const commonPatterns = extractStringArray(aiProp, "commonPatterns");
1233
- if (commonPatterns.length > 0) {
1234
- ai.commonPatterns = commonPatterns;
1235
- }
1236
- if (Object.keys(ai).length > 0) {
1237
- return ai;
1238
- }
1239
- return void 0;
1757
+ function resolveComponentPath2(componentName, registry) {
1758
+ return registry.components[componentName]?.path;
1240
1759
  }
1241
- function extractContractMetadata(arg) {
1242
- const contractProp = findProperty(arg, "contract");
1243
- if (!contractProp || !ts2.isObjectLiteralExpression(contractProp)) {
1244
- return void 0;
1245
- }
1246
- const contract = {};
1247
- const propsSummary = extractStringArray(contractProp, "propsSummary");
1248
- if (propsSummary.length > 0) {
1249
- contract.propsSummary = propsSummary;
1250
- }
1251
- const a11yRules = extractStringArray(contractProp, "a11yRules");
1252
- if (a11yRules.length > 0) {
1253
- contract.a11yRules = a11yRules;
1254
- }
1255
- if (Object.keys(contract).length > 0) {
1256
- return contract;
1760
+ function formatPropType(prop) {
1761
+ if (prop.options && prop.options.length > 0) {
1762
+ return prop.options.map((o) => `"${o}"`).join(" \\| ");
1257
1763
  }
1258
- return void 0;
1764
+ return prop.type || "unknown";
1259
1765
  }
1260
- function extractStringProperty(obj, name) {
1261
- const prop = findProperty(obj, name);
1262
- if (prop && ts2.isStringLiteral(prop)) {
1263
- return prop.text;
1264
- }
1265
- if (prop && ts2.isNoSubstitutionTemplateLiteral(prop)) {
1266
- return prop.text;
1267
- }
1268
- return null;
1766
+ function estimateTokens(text) {
1767
+ return Math.ceil(text.length / 4);
1269
1768
  }
1270
- function extractBooleanProperty(obj, name) {
1271
- const prop = findProperty(obj, name);
1272
- if (prop) {
1273
- if (prop.kind === ts2.SyntaxKind.TrueKeyword) return true;
1274
- if (prop.kind === ts2.SyntaxKind.FalseKeyword) return false;
1275
- }
1276
- return null;
1769
+
1770
+ // src/core/importAnalyzer.ts
1771
+ import ts3 from "typescript";
1772
+ import { readFileSync as readFileSync3 } from "fs";
1773
+ import { dirname as dirname5, basename as basename4 } from "path";
1774
+ function extractComponentNameFromPath(filePath) {
1775
+ const fileName = basename4(filePath);
1776
+ if (fileName === "index.tsx" || fileName === "index.ts" || fileName === "index.jsx" || fileName === "index.js") {
1777
+ const parentDir = basename4(dirname5(filePath));
1778
+ return parentDir;
1779
+ }
1780
+ return fileName.replace(/\.(tsx?|jsx?)$/, "").replace(/\.stories$/, "").replace(/\.fragment$/, "").replace(/\.fragment$/, "");
1277
1781
  }
1278
- function extractStringArray(obj, name) {
1279
- const prop = findProperty(obj, name);
1280
- if (!prop || !ts2.isArrayLiteralExpression(prop)) {
1281
- return [];
1782
+ function isComponentImportPath(importPath) {
1783
+ if (!importPath.startsWith(".") && !importPath.startsWith("/")) {
1784
+ return false;
1282
1785
  }
1283
- const result = [];
1284
- for (const element of prop.elements) {
1285
- if (ts2.isStringLiteral(element)) {
1286
- result.push(element.text);
1287
- } else if (ts2.isNoSubstitutionTemplateLiteral(element)) {
1288
- result.push(element.text);
1786
+ const skipPatterns = [
1787
+ /\/hooks\//,
1788
+ /\/utils\//,
1789
+ /\/helpers\//,
1790
+ /\/lib\//,
1791
+ /\/types\//,
1792
+ /\/constants\//,
1793
+ /\/styles\//,
1794
+ /\/context\//,
1795
+ /\.css$/,
1796
+ /\.scss$/,
1797
+ /\.less$/,
1798
+ /\.json$/
1799
+ ];
1800
+ for (const pattern of skipPatterns) {
1801
+ if (pattern.test(importPath)) {
1802
+ return false;
1289
1803
  }
1290
1804
  }
1291
- return result;
1805
+ return true;
1292
1806
  }
1293
- function extractLiteralValue(expr) {
1294
- if (ts2.isStringLiteral(expr)) {
1295
- return expr.text;
1296
- }
1297
- if (ts2.isNumericLiteral(expr)) {
1298
- return Number(expr.text);
1299
- }
1300
- if (expr.kind === ts2.SyntaxKind.TrueKeyword) {
1301
- return true;
1302
- }
1303
- if (expr.kind === ts2.SyntaxKind.FalseKeyword) {
1304
- return false;
1305
- }
1306
- if (expr.kind === ts2.SyntaxKind.NullKeyword) {
1307
- return null;
1308
- }
1309
- if (ts2.isArrayLiteralExpression(expr)) {
1310
- return expr.elements.map(extractLiteralValue);
1807
+ function isPascalCase(name) {
1808
+ return /^[A-Z][a-zA-Z0-9]*$/.test(name);
1809
+ }
1810
+ function analyzeFileImports(filePath) {
1811
+ const componentName = extractComponentNameFromPath(filePath);
1812
+ const imports = [];
1813
+ let sourceText;
1814
+ try {
1815
+ sourceText = readFileSync3(filePath, "utf-8");
1816
+ } catch {
1817
+ return { filePath, componentName, imports };
1311
1818
  }
1312
- if (ts2.isObjectLiteralExpression(expr)) {
1313
- const obj = {};
1314
- for (const prop of expr.properties) {
1315
- if (ts2.isPropertyAssignment(prop) && ts2.isIdentifier(prop.name)) {
1316
- obj[prop.name.text] = extractLiteralValue(prop.initializer);
1819
+ const sourceFile = ts3.createSourceFile(
1820
+ filePath,
1821
+ sourceText,
1822
+ ts3.ScriptTarget.Latest,
1823
+ true,
1824
+ filePath.endsWith(".tsx") || filePath.endsWith(".jsx") ? ts3.ScriptKind.TSX : ts3.ScriptKind.TS
1825
+ );
1826
+ ts3.forEachChild(sourceFile, (node) => {
1827
+ if (ts3.isImportDeclaration(node)) {
1828
+ const moduleSpecifier = node.moduleSpecifier;
1829
+ if (!ts3.isStringLiteral(moduleSpecifier)) return;
1830
+ const importPath = moduleSpecifier.text;
1831
+ if (!isComponentImportPath(importPath)) return;
1832
+ const importClause = node.importClause;
1833
+ if (!importClause) return;
1834
+ if (importClause.name) {
1835
+ const name = importClause.name.text;
1836
+ if (isPascalCase(name)) {
1837
+ imports.push({
1838
+ name,
1839
+ path: importPath,
1840
+ isDefault: true,
1841
+ isNamespace: false
1842
+ });
1843
+ }
1844
+ }
1845
+ const namedBindings = importClause.namedBindings;
1846
+ if (namedBindings) {
1847
+ if (ts3.isNamedImports(namedBindings)) {
1848
+ for (const element of namedBindings.elements) {
1849
+ const name = element.name.text;
1850
+ if (isPascalCase(name)) {
1851
+ imports.push({
1852
+ name,
1853
+ path: importPath,
1854
+ isDefault: false,
1855
+ isNamespace: false
1856
+ });
1857
+ }
1858
+ }
1859
+ } else if (ts3.isNamespaceImport(namedBindings)) {
1860
+ const name = namedBindings.name.text;
1861
+ imports.push({
1862
+ name,
1863
+ path: importPath,
1864
+ isDefault: false,
1865
+ isNamespace: true
1866
+ });
1867
+ }
1317
1868
  }
1318
1869
  }
1319
- return obj;
1320
- }
1321
- return void 0;
1322
- }
1323
-
1324
- // src/core/previewLoader.ts
1325
- import { existsSync as existsSync3 } from "fs";
1326
- import { join as join3, resolve as resolve2 } from "path";
1327
- var PREVIEW_FILES = [
1328
- "preview.tsx",
1329
- "preview.ts",
1330
- "preview.jsx",
1331
- "preview.js"
1332
- ];
1333
- function findPreviewConfigPath(storybookDir) {
1334
- for (const fileName of PREVIEW_FILES) {
1335
- const filePath = join3(storybookDir, fileName);
1336
- if (existsSync3(filePath)) {
1337
- return filePath;
1338
- }
1339
- }
1340
- return null;
1870
+ });
1871
+ return { filePath, componentName, imports };
1341
1872
  }
1342
- function findStorybookDir(projectRoot) {
1343
- const possiblePaths = [
1344
- join3(projectRoot, ".storybook"),
1345
- join3(projectRoot, "storybook")
1346
- ];
1347
- for (const dir of possiblePaths) {
1348
- if (existsSync3(dir)) {
1349
- return dir;
1873
+ function buildImportGraph(filePaths) {
1874
+ const importedBy = /* @__PURE__ */ new Map();
1875
+ for (const filePath of filePaths) {
1876
+ const result = analyzeFileImports(filePath);
1877
+ for (const imp of result.imports) {
1878
+ if (imp.isNamespace) continue;
1879
+ const importedComponent = imp.name;
1880
+ const importingComponent = result.componentName;
1881
+ if (importedComponent === importingComponent) continue;
1882
+ const existing = importedBy.get(importedComponent) || [];
1883
+ if (!existing.includes(importingComponent)) {
1884
+ existing.push(importingComponent);
1885
+ importedBy.set(importedComponent, existing);
1886
+ }
1350
1887
  }
1351
1888
  }
1352
- return null;
1889
+ return importedBy;
1353
1890
  }
1354
- function generatePreviewModule(previewPath) {
1355
- if (!previewPath) {
1356
- return `
1357
- export const decorators = [];
1358
- export const parameters = {};
1359
- export const globalTypes = {};
1360
- export const args = {};
1361
- export const argTypes = {};
1362
- export const loaders = [];
1363
-
1364
- export default {
1365
- decorators,
1366
- parameters,
1367
- globalTypes,
1368
- args,
1369
- argTypes,
1370
- loaders,
1371
- };
1372
- `;
1373
- }
1374
- return `
1375
- import * as preview from "${previewPath}";
1376
-
1377
- export const decorators = preview.decorators ?? preview.default?.decorators ?? [];
1378
- export const parameters = preview.parameters ?? preview.default?.parameters ?? {};
1379
- export const globalTypes = preview.globalTypes ?? preview.default?.globalTypes ?? {};
1380
- export const args = preview.args ?? preview.default?.args ?? {};
1381
- export const argTypes = preview.argTypes ?? preview.default?.argTypes ?? {};
1382
- export const loaders = preview.loaders ?? preview.default?.loaders ?? [];
1383
-
1384
- export default {
1385
- decorators,
1386
- parameters,
1387
- globalTypes,
1388
- args,
1389
- argTypes,
1390
- loaders,
1391
- };
1392
- `;
1891
+ function getImportedBy(componentName, importGraph) {
1892
+ return importGraph.get(componentName) || [];
1393
1893
  }
1394
1894
 
1395
- // src/core/importAnalyzer.ts
1396
- import ts3 from "typescript";
1397
- import { readFileSync as readFileSync3 } from "fs";
1398
- import { dirname as dirname4, basename as basename3 } from "path";
1399
-
1400
1895
  export {
1401
1896
  findConfigFile,
1402
1897
  loadConfig,
1898
+ discoverBlockFiles,
1899
+ discoverRecipeFiles,
1900
+ discoverFragmentFiles,
1901
+ discoverComponentFiles,
1902
+ extractComponentName,
1903
+ discoverComponentsFromSource,
1904
+ discoverComponentsFromBarrel,
1905
+ discoverTokenFiles,
1906
+ discoverInstalledFragments,
1907
+ discoverAllComponents,
1403
1908
  loadFragmentFile,
1909
+ loadFragmentFiles,
1404
1910
  parseFragmentFile,
1405
1911
  findPreviewConfigPath,
1406
1912
  findStorybookDir,
1913
+ loadPreviewConfig,
1914
+ autoLoadPreviewConfig,
1407
1915
  generatePreviewModule,
1408
1916
  extractPropsFromFile,
1917
+ extractPropsFromSource,
1409
1918
  generateRegistry,
1410
- generateContextMd
1919
+ resolveComponentPath,
1920
+ getComponentsByCategory,
1921
+ generateContextMd,
1922
+ analyzeFileImports,
1923
+ buildImportGraph,
1924
+ getImportedBy
1411
1925
  };
1412
- //# sourceMappingURL=chunk-55KERLWL.js.map
1926
+ //# sourceMappingURL=chunk-HQ6A6DTV.js.map