@fragments-sdk/cli 0.2.2

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 (259) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/dist/bin.d.ts +1 -0
  4. package/dist/bin.js +4783 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/chunk-4FDQSGKX.js +786 -0
  7. package/dist/chunk-4FDQSGKX.js.map +1 -0
  8. package/dist/chunk-7H2MMGYG.js +369 -0
  9. package/dist/chunk-7H2MMGYG.js.map +1 -0
  10. package/dist/chunk-BSCG3IP7.js +619 -0
  11. package/dist/chunk-BSCG3IP7.js.map +1 -0
  12. package/dist/chunk-LY2CFFPY.js +898 -0
  13. package/dist/chunk-LY2CFFPY.js.map +1 -0
  14. package/dist/chunk-MUZ6CM66.js +6636 -0
  15. package/dist/chunk-MUZ6CM66.js.map +1 -0
  16. package/dist/chunk-OAENNG3G.js +1489 -0
  17. package/dist/chunk-OAENNG3G.js.map +1 -0
  18. package/dist/chunk-XHNKNI6J.js +235 -0
  19. package/dist/chunk-XHNKNI6J.js.map +1 -0
  20. package/dist/core-DWKLGY4N.js +68 -0
  21. package/dist/core-DWKLGY4N.js.map +1 -0
  22. package/dist/generate-4LQNJ7SX.js +249 -0
  23. package/dist/generate-4LQNJ7SX.js.map +1 -0
  24. package/dist/index.d.ts +775 -0
  25. package/dist/index.js +41 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/init-EMVI47QG.js +416 -0
  28. package/dist/init-EMVI47QG.js.map +1 -0
  29. package/dist/mcp-bin.d.ts +1 -0
  30. package/dist/mcp-bin.js +1117 -0
  31. package/dist/mcp-bin.js.map +1 -0
  32. package/dist/scan-4YPRF7FV.js +12 -0
  33. package/dist/scan-4YPRF7FV.js.map +1 -0
  34. package/dist/service-QSZMZJBJ.js +208 -0
  35. package/dist/service-QSZMZJBJ.js.map +1 -0
  36. package/dist/static-viewer-MIPGZ4Z7.js +12 -0
  37. package/dist/static-viewer-MIPGZ4Z7.js.map +1 -0
  38. package/dist/test-SQ5ZHXWU.js +1067 -0
  39. package/dist/test-SQ5ZHXWU.js.map +1 -0
  40. package/dist/tokens-HSGMYK64.js +173 -0
  41. package/dist/tokens-HSGMYK64.js.map +1 -0
  42. package/dist/viewer-YRF4SQE4.js +11101 -0
  43. package/dist/viewer-YRF4SQE4.js.map +1 -0
  44. package/package.json +107 -0
  45. package/src/ai.ts +266 -0
  46. package/src/analyze.ts +265 -0
  47. package/src/bin.ts +916 -0
  48. package/src/build.ts +248 -0
  49. package/src/commands/a11y.ts +302 -0
  50. package/src/commands/add.ts +313 -0
  51. package/src/commands/audit.ts +195 -0
  52. package/src/commands/baseline.ts +221 -0
  53. package/src/commands/build.ts +144 -0
  54. package/src/commands/compare.ts +337 -0
  55. package/src/commands/context.ts +107 -0
  56. package/src/commands/dev.ts +107 -0
  57. package/src/commands/enhance.ts +858 -0
  58. package/src/commands/generate.ts +391 -0
  59. package/src/commands/init.ts +531 -0
  60. package/src/commands/link/figma.ts +645 -0
  61. package/src/commands/link/index.ts +10 -0
  62. package/src/commands/link/storybook.ts +267 -0
  63. package/src/commands/list.ts +49 -0
  64. package/src/commands/metrics.ts +114 -0
  65. package/src/commands/reset.ts +242 -0
  66. package/src/commands/scan.ts +537 -0
  67. package/src/commands/storygen.ts +207 -0
  68. package/src/commands/tokens.ts +251 -0
  69. package/src/commands/validate.ts +93 -0
  70. package/src/commands/verify.ts +215 -0
  71. package/src/core/composition.test.ts +262 -0
  72. package/src/core/composition.ts +255 -0
  73. package/src/core/config.ts +84 -0
  74. package/src/core/constants.ts +111 -0
  75. package/src/core/context.ts +380 -0
  76. package/src/core/defineSegment.ts +137 -0
  77. package/src/core/discovery.ts +337 -0
  78. package/src/core/figma.ts +263 -0
  79. package/src/core/fragment-types.ts +214 -0
  80. package/src/core/generators/context.ts +389 -0
  81. package/src/core/generators/index.ts +23 -0
  82. package/src/core/generators/registry.ts +364 -0
  83. package/src/core/generators/typescript-extractor.ts +374 -0
  84. package/src/core/importAnalyzer.ts +217 -0
  85. package/src/core/index.ts +149 -0
  86. package/src/core/loader.ts +155 -0
  87. package/src/core/node.ts +63 -0
  88. package/src/core/parser.ts +551 -0
  89. package/src/core/previewLoader.ts +172 -0
  90. package/src/core/schema/fragment.schema.json +189 -0
  91. package/src/core/schema/registry.schema.json +137 -0
  92. package/src/core/schema.ts +182 -0
  93. package/src/core/storyAdapter.test.ts +571 -0
  94. package/src/core/storyAdapter.ts +761 -0
  95. package/src/core/token-types.ts +287 -0
  96. package/src/core/types.ts +754 -0
  97. package/src/diff.ts +323 -0
  98. package/src/index.ts +43 -0
  99. package/src/mcp/__tests__/projectFields.test.ts +130 -0
  100. package/src/mcp/bin.ts +36 -0
  101. package/src/mcp/index.ts +8 -0
  102. package/src/mcp/server.ts +1310 -0
  103. package/src/mcp/utils.ts +54 -0
  104. package/src/mcp-bin.ts +36 -0
  105. package/src/migrate/__tests__/argTypes/argTypes.test.ts +189 -0
  106. package/src/migrate/__tests__/args/args.test.ts +452 -0
  107. package/src/migrate/__tests__/meta/meta.test.ts +198 -0
  108. package/src/migrate/__tests__/stories/stories.test.ts +278 -0
  109. package/src/migrate/__tests__/utils/utils.test.ts +371 -0
  110. package/src/migrate/__tests__/values/values.test.ts +303 -0
  111. package/src/migrate/bin.ts +108 -0
  112. package/src/migrate/converter.ts +658 -0
  113. package/src/migrate/detect.ts +196 -0
  114. package/src/migrate/index.ts +45 -0
  115. package/src/migrate/migrate.ts +163 -0
  116. package/src/migrate/parser.ts +1136 -0
  117. package/src/migrate/report.ts +624 -0
  118. package/src/migrate/types.ts +169 -0
  119. package/src/screenshot.ts +249 -0
  120. package/src/service/__tests__/ast-utils.test.ts +426 -0
  121. package/src/service/__tests__/enhance-scanner.test.ts +200 -0
  122. package/src/service/__tests__/figma/figma.test.ts +652 -0
  123. package/src/service/__tests__/metrics-store.test.ts +409 -0
  124. package/src/service/__tests__/patch-generator.test.ts +186 -0
  125. package/src/service/__tests__/props-extractor.test.ts +365 -0
  126. package/src/service/__tests__/token-registry.test.ts +267 -0
  127. package/src/service/analytics.ts +659 -0
  128. package/src/service/ast-utils.ts +444 -0
  129. package/src/service/browser-pool.ts +339 -0
  130. package/src/service/capture.ts +267 -0
  131. package/src/service/diff.ts +279 -0
  132. package/src/service/enhance/aggregator.ts +489 -0
  133. package/src/service/enhance/cache.ts +275 -0
  134. package/src/service/enhance/codebase-scanner.ts +357 -0
  135. package/src/service/enhance/context-generator.ts +529 -0
  136. package/src/service/enhance/doc-extractor.ts +523 -0
  137. package/src/service/enhance/index.ts +131 -0
  138. package/src/service/enhance/props-extractor.ts +665 -0
  139. package/src/service/enhance/scanner.ts +445 -0
  140. package/src/service/enhance/storybook-parser.ts +552 -0
  141. package/src/service/enhance/types.ts +346 -0
  142. package/src/service/enhance/variant-renderer.ts +479 -0
  143. package/src/service/figma.ts +1008 -0
  144. package/src/service/index.ts +249 -0
  145. package/src/service/metrics-store.ts +333 -0
  146. package/src/service/patch-generator.ts +349 -0
  147. package/src/service/report.ts +854 -0
  148. package/src/service/storage.ts +401 -0
  149. package/src/service/token-fixes.ts +281 -0
  150. package/src/service/token-parser.ts +504 -0
  151. package/src/service/token-registry.ts +721 -0
  152. package/src/service/utils.ts +172 -0
  153. package/src/setup.ts +241 -0
  154. package/src/shared/command-wrapper.ts +81 -0
  155. package/src/shared/dev-server-client.ts +199 -0
  156. package/src/shared/index.ts +8 -0
  157. package/src/shared/segment-loader.ts +59 -0
  158. package/src/shared/types.ts +147 -0
  159. package/src/static-viewer.ts +715 -0
  160. package/src/test/discovery.ts +172 -0
  161. package/src/test/index.ts +281 -0
  162. package/src/test/reporters/console.ts +194 -0
  163. package/src/test/reporters/json.ts +190 -0
  164. package/src/test/reporters/junit.ts +186 -0
  165. package/src/test/runner.ts +598 -0
  166. package/src/test/types.ts +245 -0
  167. package/src/test/watch.ts +200 -0
  168. package/src/validators.ts +152 -0
  169. package/src/viewer/__tests__/jsx-parser.test.ts +502 -0
  170. package/src/viewer/__tests__/render-utils.test.ts +232 -0
  171. package/src/viewer/__tests__/style-utils.test.ts +404 -0
  172. package/src/viewer/bin.ts +86 -0
  173. package/src/viewer/cli/health.ts +256 -0
  174. package/src/viewer/cli/index.ts +33 -0
  175. package/src/viewer/cli/scan.ts +124 -0
  176. package/src/viewer/cli/utils.ts +174 -0
  177. package/src/viewer/components/AccessibilityPanel.tsx +1404 -0
  178. package/src/viewer/components/ActionCapture.tsx +172 -0
  179. package/src/viewer/components/ActionsPanel.tsx +371 -0
  180. package/src/viewer/components/App.tsx +638 -0
  181. package/src/viewer/components/BottomPanel.tsx +224 -0
  182. package/src/viewer/components/CodePanel.tsx +589 -0
  183. package/src/viewer/components/CommandPalette.tsx +336 -0
  184. package/src/viewer/components/ComponentGraph.tsx +394 -0
  185. package/src/viewer/components/ComponentHeader.tsx +85 -0
  186. package/src/viewer/components/ContractPanel.tsx +234 -0
  187. package/src/viewer/components/ErrorBoundary.tsx +85 -0
  188. package/src/viewer/components/FigmaEmbed.tsx +231 -0
  189. package/src/viewer/components/FragmentEditor.tsx +485 -0
  190. package/src/viewer/components/HealthDashboard.tsx +452 -0
  191. package/src/viewer/components/HmrStatusIndicator.tsx +71 -0
  192. package/src/viewer/components/Icons.tsx +417 -0
  193. package/src/viewer/components/InteractionsPanel.tsx +720 -0
  194. package/src/viewer/components/IsolatedPreviewFrame.tsx +321 -0
  195. package/src/viewer/components/IsolatedRender.tsx +111 -0
  196. package/src/viewer/components/KeyboardShortcutsHelp.tsx +89 -0
  197. package/src/viewer/components/LandingPage.tsx +441 -0
  198. package/src/viewer/components/Layout.tsx +22 -0
  199. package/src/viewer/components/LeftSidebar.tsx +391 -0
  200. package/src/viewer/components/MultiViewportPreview.tsx +429 -0
  201. package/src/viewer/components/PreviewArea.tsx +404 -0
  202. package/src/viewer/components/PreviewFrameHost.tsx +310 -0
  203. package/src/viewer/components/PreviewPane.tsx +150 -0
  204. package/src/viewer/components/PreviewToolbar.tsx +176 -0
  205. package/src/viewer/components/PropsEditor.tsx +512 -0
  206. package/src/viewer/components/PropsTable.tsx +98 -0
  207. package/src/viewer/components/RelationsSection.tsx +57 -0
  208. package/src/viewer/components/ResizablePanel.tsx +328 -0
  209. package/src/viewer/components/RightSidebar.tsx +118 -0
  210. package/src/viewer/components/ScreenshotButton.tsx +90 -0
  211. package/src/viewer/components/Sidebar.tsx +169 -0
  212. package/src/viewer/components/SkeletonLoader.tsx +156 -0
  213. package/src/viewer/components/StoryRenderer.tsx +128 -0
  214. package/src/viewer/components/ThemeProvider.tsx +96 -0
  215. package/src/viewer/components/Toast.tsx +67 -0
  216. package/src/viewer/components/TokenStylePanel.tsx +708 -0
  217. package/src/viewer/components/UsageSection.tsx +95 -0
  218. package/src/viewer/components/VariantMatrix.tsx +350 -0
  219. package/src/viewer/components/VariantRenderer.tsx +131 -0
  220. package/src/viewer/components/VariantTabs.tsx +84 -0
  221. package/src/viewer/components/ViewportSelector.tsx +165 -0
  222. package/src/viewer/components/_future/CreatePage.tsx +836 -0
  223. package/src/viewer/composition-renderer.ts +381 -0
  224. package/src/viewer/constants/index.ts +1 -0
  225. package/src/viewer/constants/ui.ts +185 -0
  226. package/src/viewer/entry.tsx +299 -0
  227. package/src/viewer/hooks/index.ts +2 -0
  228. package/src/viewer/hooks/useA11yCache.ts +383 -0
  229. package/src/viewer/hooks/useA11yService.ts +498 -0
  230. package/src/viewer/hooks/useActions.ts +138 -0
  231. package/src/viewer/hooks/useAppState.ts +124 -0
  232. package/src/viewer/hooks/useFigmaIntegration.ts +132 -0
  233. package/src/viewer/hooks/useHmrStatus.ts +109 -0
  234. package/src/viewer/hooks/useKeyboardShortcuts.ts +222 -0
  235. package/src/viewer/hooks/usePreviewBridge.ts +347 -0
  236. package/src/viewer/hooks/useScrollSpy.ts +78 -0
  237. package/src/viewer/hooks/useUrlState.ts +330 -0
  238. package/src/viewer/hooks/useViewSettings.ts +125 -0
  239. package/src/viewer/index.html +28 -0
  240. package/src/viewer/index.ts +14 -0
  241. package/src/viewer/intelligence/healthReport.ts +505 -0
  242. package/src/viewer/intelligence/styleDrift.ts +340 -0
  243. package/src/viewer/intelligence/usageScanner.ts +309 -0
  244. package/src/viewer/jsx-parser.ts +485 -0
  245. package/src/viewer/postcss.config.js +6 -0
  246. package/src/viewer/preview-frame-entry.tsx +25 -0
  247. package/src/viewer/preview-frame.html +109 -0
  248. package/src/viewer/render-template.html +68 -0
  249. package/src/viewer/render-utils.ts +170 -0
  250. package/src/viewer/server.ts +276 -0
  251. package/src/viewer/style-utils.ts +414 -0
  252. package/src/viewer/styles/globals.css +355 -0
  253. package/src/viewer/tailwind.config.js +37 -0
  254. package/src/viewer/types/a11y.ts +197 -0
  255. package/src/viewer/utils/a11y-fixes.ts +471 -0
  256. package/src/viewer/utils/actionExport.ts +372 -0
  257. package/src/viewer/utils/colorSchemes.ts +201 -0
  258. package/src/viewer/utils/detectRelationships.ts +256 -0
  259. package/src/viewer/vite-plugin.ts +2143 -0
@@ -0,0 +1,523 @@
1
+ /**
2
+ * Documentation Extractor
3
+ *
4
+ * Extracts JSDoc, TSDoc, and TypeScript interface information from component files.
5
+ */
6
+
7
+ import { parse } from "@babel/parser";
8
+ import _traverse from "@babel/traverse";
9
+ import * as t from "@babel/types";
10
+
11
+ // Handle CommonJS/ESM interop
12
+ const traverse = (_traverse as unknown as { default: typeof _traverse }).default || _traverse;
13
+ import { readFile } from "node:fs/promises";
14
+ import { existsSync } from "node:fs";
15
+ import { basename, dirname, join } from "node:path";
16
+ import type { ExtractedDocs } from "./types.js";
17
+
18
+ /**
19
+ * Extract documentation from a component source file
20
+ */
21
+ export async function extractComponentDocs(
22
+ filePath: string
23
+ ): Promise<ExtractedDocs> {
24
+ const content = await readFile(filePath, "utf-8");
25
+ return extractDocsFromSource(content, filePath);
26
+ }
27
+
28
+ /**
29
+ * Extract documentation from source code
30
+ */
31
+ export function extractDocsFromSource(
32
+ source: string,
33
+ filePath: string
34
+ ): ExtractedDocs {
35
+ const isTypeScript = filePath.endsWith(".ts") || filePath.endsWith(".tsx");
36
+ const isJSX = filePath.endsWith(".tsx") || filePath.endsWith(".jsx");
37
+
38
+ const ast = parse(source, {
39
+ sourceType: "module",
40
+ plugins: [
41
+ ...(isTypeScript ? (["typescript"] as const) : []),
42
+ ...(isJSX ? (["jsx"] as const) : []),
43
+ "decorators-legacy",
44
+ ],
45
+ });
46
+
47
+ const docs: ExtractedDocs = {
48
+ filePath,
49
+ componentName: inferComponentName(filePath),
50
+ description: "",
51
+ props: [],
52
+ examples: [],
53
+ tags: {},
54
+ };
55
+
56
+ // Track leading comments for the main export
57
+ let mainExportComment: string | undefined;
58
+
59
+ traverse(ast, {
60
+ // Extract JSDoc from function declarations
61
+ FunctionDeclaration(path) {
62
+ const leadingComments = path.node.leadingComments;
63
+ if (leadingComments) {
64
+ const jsdoc = extractJSDoc(leadingComments);
65
+ if (jsdoc && isExportedComponent(path)) {
66
+ mergeJSDoc(docs, jsdoc);
67
+ }
68
+ }
69
+ },
70
+
71
+ // Extract JSDoc from arrow function variable declarations
72
+ VariableDeclaration(path) {
73
+ const leadingComments = path.node.leadingComments;
74
+ if (leadingComments && hasExportedArrowFunction(path)) {
75
+ const jsdoc = extractJSDoc(leadingComments);
76
+ if (jsdoc) {
77
+ mergeJSDoc(docs, jsdoc);
78
+ }
79
+ }
80
+ },
81
+
82
+ // Extract JSDoc from export default
83
+ ExportDefaultDeclaration(path) {
84
+ const leadingComments = path.node.leadingComments;
85
+ if (leadingComments) {
86
+ const jsdoc = extractJSDoc(leadingComments);
87
+ if (jsdoc) {
88
+ mergeJSDoc(docs, jsdoc);
89
+ }
90
+ }
91
+ },
92
+
93
+ // Extract props from TypeScript interface
94
+ TSInterfaceDeclaration(path) {
95
+ const name = path.node.id.name;
96
+ if (isPropsInterface(name)) {
97
+ const props = extractPropsFromInterface(path.node);
98
+ docs.props.push(...props);
99
+ }
100
+ },
101
+
102
+ // Extract props from TypeScript type alias
103
+ TSTypeAliasDeclaration(path) {
104
+ const name = path.node.id.name;
105
+ if (isPropsInterface(name)) {
106
+ const props = extractPropsFromTypeAlias(path.node);
107
+ docs.props.push(...props);
108
+ }
109
+ },
110
+ });
111
+
112
+ // Clean up duplicates
113
+ docs.props = deduplicateProps(docs.props);
114
+
115
+ return docs;
116
+ }
117
+
118
+ /**
119
+ * Extract JSDoc information from comments
120
+ */
121
+ function extractJSDoc(
122
+ comments: readonly t.Comment[]
123
+ ): Partial<ExtractedDocs> | null {
124
+ const blockComments = comments.filter(
125
+ (c) => c.type === "CommentBlock" && c.value.startsWith("*")
126
+ );
127
+
128
+ if (blockComments.length === 0) return null;
129
+
130
+ const comment = blockComments[blockComments.length - 1];
131
+ const content = comment.value;
132
+
133
+ const result: Partial<ExtractedDocs> = {
134
+ description: "",
135
+ props: [],
136
+ examples: [],
137
+ tags: {},
138
+ };
139
+
140
+ // Parse JSDoc content
141
+ const lines = content.split("\n");
142
+ let currentDescription: string[] = [];
143
+ let currentTag: string | null = null;
144
+ let currentTagContent: string[] = [];
145
+
146
+ for (const line of lines) {
147
+ const trimmed = line.replace(/^\s*\*\s?/, "").trim();
148
+
149
+ // Check for JSDoc tag
150
+ const tagMatch = trimmed.match(/^@(\w+)(?:\s+(.*))?$/);
151
+
152
+ if (tagMatch) {
153
+ // Save previous tag if exists
154
+ if (currentTag) {
155
+ processTag(result, currentTag, currentTagContent.join("\n").trim());
156
+ } else if (currentDescription.length > 0) {
157
+ result.description = currentDescription.join("\n").trim();
158
+ }
159
+
160
+ currentTag = tagMatch[1];
161
+ currentTagContent = tagMatch[2] ? [tagMatch[2]] : [];
162
+ } else if (currentTag) {
163
+ currentTagContent.push(trimmed);
164
+ } else if (trimmed) {
165
+ currentDescription.push(trimmed);
166
+ }
167
+ }
168
+
169
+ // Process final tag
170
+ if (currentTag) {
171
+ processTag(result, currentTag, currentTagContent.join("\n").trim());
172
+ } else if (currentDescription.length > 0) {
173
+ result.description = currentDescription.join("\n").trim();
174
+ }
175
+
176
+ return result;
177
+ }
178
+
179
+ /**
180
+ * Process a JSDoc tag
181
+ */
182
+ function processTag(
183
+ docs: Partial<ExtractedDocs>,
184
+ tag: string,
185
+ content: string
186
+ ): void {
187
+ switch (tag) {
188
+ case "description":
189
+ docs.description = content;
190
+ break;
191
+
192
+ case "param":
193
+ case "prop": {
194
+ const propMatch = content.match(
195
+ /^\{([^}]+)\}\s+(\[?\w+\]?)\s*-?\s*(.*)/
196
+ );
197
+ if (propMatch) {
198
+ const [, type, nameRaw, description] = propMatch;
199
+ const isOptional = nameRaw.startsWith("[");
200
+ const name = nameRaw.replace(/[\[\]]/g, "");
201
+ docs.props?.push({
202
+ name,
203
+ type,
204
+ description,
205
+ required: !isOptional,
206
+ });
207
+ }
208
+ break;
209
+ }
210
+
211
+ case "example": {
212
+ docs.examples?.push(content);
213
+ break;
214
+ }
215
+
216
+ case "deprecated":
217
+ case "since":
218
+ case "version":
219
+ case "see":
220
+ case "link":
221
+ case "category":
222
+ docs.tags = docs.tags ?? {};
223
+ docs.tags[tag] = content;
224
+ break;
225
+
226
+ default:
227
+ // Store other tags generically
228
+ docs.tags = docs.tags ?? {};
229
+ docs.tags[tag] = content;
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Extract props from TypeScript interface
235
+ */
236
+ function extractPropsFromInterface(
237
+ node: t.TSInterfaceDeclaration
238
+ ): ExtractedDocs["props"] {
239
+ const props: ExtractedDocs["props"] = [];
240
+
241
+ for (const member of node.body.body) {
242
+ if (t.isTSPropertySignature(member) && t.isIdentifier(member.key)) {
243
+ const name = member.key.name;
244
+ const type = member.typeAnnotation
245
+ ? typeAnnotationToString(member.typeAnnotation.typeAnnotation)
246
+ : "unknown";
247
+ const required = !member.optional;
248
+
249
+ // Extract description from leading comments
250
+ let description = "";
251
+ if (member.leadingComments) {
252
+ const comment = member.leadingComments[member.leadingComments.length - 1];
253
+ if (comment.type === "CommentBlock") {
254
+ description = comment.value
255
+ .replace(/^\s*\*\s?/gm, "")
256
+ .trim();
257
+ } else if (comment.type === "CommentLine") {
258
+ description = comment.value.trim();
259
+ }
260
+ }
261
+
262
+ props.push({ name, type, description, required });
263
+ }
264
+ }
265
+
266
+ return props;
267
+ }
268
+
269
+ /**
270
+ * Extract props from TypeScript type alias
271
+ */
272
+ function extractPropsFromTypeAlias(
273
+ node: t.TSTypeAliasDeclaration
274
+ ): ExtractedDocs["props"] {
275
+ const props: ExtractedDocs["props"] = [];
276
+
277
+ if (t.isTSTypeLiteral(node.typeAnnotation)) {
278
+ for (const member of node.typeAnnotation.members) {
279
+ if (t.isTSPropertySignature(member) && t.isIdentifier(member.key)) {
280
+ const name = member.key.name;
281
+ const type = member.typeAnnotation
282
+ ? typeAnnotationToString(member.typeAnnotation.typeAnnotation)
283
+ : "unknown";
284
+ const required = !member.optional;
285
+
286
+ // Extract description from leading comments
287
+ let description = "";
288
+ if (member.leadingComments) {
289
+ const comment = member.leadingComments[member.leadingComments.length - 1];
290
+ description = comment.value.replace(/^\s*\*\s?/gm, "").trim();
291
+ }
292
+
293
+ props.push({ name, type, description, required });
294
+ }
295
+ }
296
+ }
297
+
298
+ return props;
299
+ }
300
+
301
+ /**
302
+ * Convert TypeScript type annotation to string representation
303
+ */
304
+ function typeAnnotationToString(node: t.TSType): string {
305
+ if (t.isTSStringKeyword(node)) return "string";
306
+ if (t.isTSNumberKeyword(node)) return "number";
307
+ if (t.isTSBooleanKeyword(node)) return "boolean";
308
+ if (t.isTSNullKeyword(node)) return "null";
309
+ if (t.isTSUndefinedKeyword(node)) return "undefined";
310
+ if (t.isTSVoidKeyword(node)) return "void";
311
+ if (t.isTSAnyKeyword(node)) return "any";
312
+ if (t.isTSNeverKeyword(node)) return "never";
313
+ if (t.isTSUnknownKeyword(node)) return "unknown";
314
+
315
+ if (t.isTSLiteralType(node)) {
316
+ if (t.isStringLiteral(node.literal)) return `"${node.literal.value}"`;
317
+ if (t.isNumericLiteral(node.literal)) return String(node.literal.value);
318
+ if (t.isBooleanLiteral(node.literal)) return String(node.literal.value);
319
+ return "literal";
320
+ }
321
+
322
+ if (t.isTSTypeReference(node)) {
323
+ if (t.isIdentifier(node.typeName)) {
324
+ const name = node.typeName.name;
325
+ if (node.typeParameters) {
326
+ const params = node.typeParameters.params
327
+ .map(typeAnnotationToString)
328
+ .join(", ");
329
+ return `${name}<${params}>`;
330
+ }
331
+ return name;
332
+ }
333
+ }
334
+
335
+ if (t.isTSUnionType(node)) {
336
+ return node.types.map(typeAnnotationToString).join(" | ");
337
+ }
338
+
339
+ if (t.isTSIntersectionType(node)) {
340
+ return node.types.map(typeAnnotationToString).join(" & ");
341
+ }
342
+
343
+ if (t.isTSArrayType(node)) {
344
+ return `${typeAnnotationToString(node.elementType)}[]`;
345
+ }
346
+
347
+ if (t.isTSFunctionType(node)) {
348
+ return "(...args: any[]) => any";
349
+ }
350
+
351
+ if (t.isTSTupleType(node)) {
352
+ const elements = node.elementTypes
353
+ .map((el) => {
354
+ // Handle named tuple members: [name: string]
355
+ if (t.isTSNamedTupleMember(el)) {
356
+ return typeAnnotationToString(el.elementType);
357
+ }
358
+ return typeAnnotationToString(el);
359
+ })
360
+ .join(", ");
361
+ return `[${elements}]`;
362
+ }
363
+
364
+ if (t.isTSTypeLiteral(node)) {
365
+ return "object";
366
+ }
367
+
368
+ return "unknown";
369
+ }
370
+
371
+ /**
372
+ * Check if interface name looks like props
373
+ */
374
+ function isPropsInterface(name: string): boolean {
375
+ return (
376
+ name.endsWith("Props") ||
377
+ name.endsWith("Properties") ||
378
+ name === "Props"
379
+ );
380
+ }
381
+
382
+ /**
383
+ * Check if a function declaration is exported
384
+ */
385
+ function isExportedComponent(
386
+ path: babel.NodePath<t.FunctionDeclaration>
387
+ ): boolean {
388
+ const parent = path.parent;
389
+ if (t.isExportDefaultDeclaration(parent)) return true;
390
+ if (t.isExportNamedDeclaration(parent)) return true;
391
+ if (t.isProgram(parent) && path.node.id && /^[A-Z]/.test(path.node.id.name)) {
392
+ return true;
393
+ }
394
+ return false;
395
+ }
396
+
397
+ /**
398
+ * Check if variable declaration has an exported arrow function component
399
+ */
400
+ function hasExportedArrowFunction(
401
+ path: babel.NodePath<t.VariableDeclaration>
402
+ ): boolean {
403
+ const parent = path.parent;
404
+ if (!t.isExportNamedDeclaration(parent)) return false;
405
+
406
+ for (const declarator of path.node.declarations) {
407
+ if (
408
+ t.isIdentifier(declarator.id) &&
409
+ /^[A-Z]/.test(declarator.id.name) &&
410
+ (t.isArrowFunctionExpression(declarator.init) ||
411
+ t.isFunctionExpression(declarator.init))
412
+ ) {
413
+ return true;
414
+ }
415
+ }
416
+
417
+ return false;
418
+ }
419
+
420
+ /**
421
+ * Infer component name from file path
422
+ */
423
+ function inferComponentName(filePath: string): string {
424
+ const fileName = basename(filePath);
425
+ // Remove extension
426
+ let name = fileName.replace(/\.(tsx?|jsx?)$/, "");
427
+ // Handle index files
428
+ if (name === "index") {
429
+ name = basename(dirname(filePath));
430
+ }
431
+ return name;
432
+ }
433
+
434
+ /**
435
+ * Merge JSDoc results into docs
436
+ */
437
+ function mergeJSDoc(docs: ExtractedDocs, jsdoc: Partial<ExtractedDocs>): void {
438
+ if (jsdoc.description && !docs.description) {
439
+ docs.description = jsdoc.description;
440
+ }
441
+ if (jsdoc.props) {
442
+ docs.props.push(...jsdoc.props);
443
+ }
444
+ if (jsdoc.examples) {
445
+ docs.examples.push(...jsdoc.examples);
446
+ }
447
+ if (jsdoc.tags) {
448
+ docs.tags = { ...docs.tags, ...jsdoc.tags };
449
+ }
450
+ }
451
+
452
+ /**
453
+ * Remove duplicate props
454
+ */
455
+ function deduplicateProps(
456
+ props: ExtractedDocs["props"]
457
+ ): ExtractedDocs["props"] {
458
+ const seen = new Map<string, ExtractedDocs["props"][0]>();
459
+
460
+ for (const prop of props) {
461
+ const existing = seen.get(prop.name);
462
+ if (!existing || (prop.description && !existing.description)) {
463
+ seen.set(prop.name, prop);
464
+ }
465
+ }
466
+
467
+ return Array.from(seen.values());
468
+ }
469
+
470
+ /**
471
+ * Find component source file from various patterns
472
+ */
473
+ export async function findComponentSource(
474
+ componentName: string,
475
+ searchDirs: string[]
476
+ ): Promise<string | null> {
477
+ const patterns = [
478
+ `${componentName}.tsx`,
479
+ `${componentName}.ts`,
480
+ `${componentName}/index.tsx`,
481
+ `${componentName}/index.ts`,
482
+ `${componentName}/${componentName}.tsx`,
483
+ `${componentName}/${componentName}.ts`,
484
+ ];
485
+
486
+ for (const dir of searchDirs) {
487
+ for (const pattern of patterns) {
488
+ const fullPath = join(dir, pattern);
489
+ if (existsSync(fullPath)) {
490
+ return fullPath;
491
+ }
492
+ }
493
+ }
494
+
495
+ return null;
496
+ }
497
+
498
+ /**
499
+ * Extract documentation from multiple component files
500
+ */
501
+ export async function extractAllComponentDocs(
502
+ componentFiles: Map<string, string>
503
+ ): Promise<Map<string, ExtractedDocs>> {
504
+ const results = new Map<string, ExtractedDocs>();
505
+
506
+ for (const [componentName, filePath] of componentFiles) {
507
+ try {
508
+ const docs = await extractComponentDocs(filePath);
509
+ docs.componentName = componentName;
510
+ results.set(componentName, docs);
511
+ } catch (error) {
512
+ console.warn(
513
+ `Failed to extract docs for ${componentName}:`,
514
+ (error as Error).message
515
+ );
516
+ }
517
+ }
518
+
519
+ return results;
520
+ }
521
+
522
+ // Type import for babel NodePath
523
+ import type * as babel from "@babel/traverse";
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Enhancement Module
3
+ *
4
+ * AI-powered documentation generation through codebase analysis.
5
+ */
6
+
7
+ // Types
8
+ export type {
9
+ ComponentUsage,
10
+ UsageProps,
11
+ ComponentImport,
12
+ UsagePattern,
13
+ FileContext,
14
+ ComponentAnalysis,
15
+ UsageAnalysis,
16
+ FileCacheEntry,
17
+ AnalysisCache,
18
+ ScanProgress,
19
+ ScanOptions,
20
+ FileChanges,
21
+ ExtractedDocs,
22
+ ComponentEnhancement,
23
+ EnhancementResult,
24
+ } from "./types.js";
25
+
26
+ export { CACHE_VERSION } from "./types.js";
27
+
28
+ // Scanner
29
+ export {
30
+ scanFileForImports,
31
+ scanFileForUsages,
32
+ scanFile,
33
+ } from "./scanner.js";
34
+
35
+ // Aggregator
36
+ export {
37
+ aggregateComponentUsages,
38
+ aggregateAllUsages,
39
+ findCommonPropCombinations,
40
+ summarizePatternsForPrompt,
41
+ inferRelations,
42
+ inferAllRelations,
43
+ type ComponentRelation,
44
+ } from "./aggregator.js";
45
+
46
+ // Cache
47
+ export {
48
+ getCachePath,
49
+ loadCache,
50
+ saveCache,
51
+ createEmptyCache,
52
+ computeFileHash,
53
+ computeFileHashFromDisk,
54
+ isFileCached,
55
+ getCachedFile,
56
+ updateCacheFile,
57
+ removeCacheFile,
58
+ invalidateCache,
59
+ detectFileChanges,
60
+ getAllCachedImports,
61
+ getAllCachedUsages,
62
+ getCacheStats,
63
+ } from "./cache.js";
64
+
65
+ // Codebase Scanner
66
+ export {
67
+ scanCodebase,
68
+ incrementalScan,
69
+ getScanStats,
70
+ hasCachedAnalysis,
71
+ } from "./codebase-scanner.js";
72
+
73
+ // Documentation Extractor
74
+ export {
75
+ extractComponentDocs,
76
+ extractDocsFromSource,
77
+ findComponentSource,
78
+ extractAllComponentDocs,
79
+ } from "./doc-extractor.js";
80
+
81
+ // Storybook Parser
82
+ export {
83
+ parseStoryFile,
84
+ parseStorySource,
85
+ findStoryFiles,
86
+ parseAllStories,
87
+ mergeStorybookIntoDoc,
88
+ type StoryExample,
89
+ type StorybookMeta,
90
+ type ArgType,
91
+ type ParsedStoryFile,
92
+ } from "./storybook-parser.js";
93
+
94
+ // AI Context Generator
95
+ export {
96
+ generateComponentContext,
97
+ generateAIContextPackage,
98
+ generatePromptContext,
99
+ generateEnhancementSuggestions,
100
+ generateSystemPrompt,
101
+ generateUserPrompt,
102
+ isBoilerplate,
103
+ filterBoilerplate,
104
+ type ComponentContext,
105
+ type AIContextPackage,
106
+ type EnhancedProp,
107
+ } from "./context-generator.js";
108
+
109
+ // TypeScript Props Extractor
110
+ export {
111
+ extractPropsFromFile,
112
+ extractPropsFromSource,
113
+ extractPropsForComponent,
114
+ extractAllComponentProps,
115
+ convertToSegmentProps,
116
+ type ExtractedProp,
117
+ type PropsExtractionResult,
118
+ type PropsExtractionOptions,
119
+ } from "./props-extractor.js";
120
+
121
+ // Variant Renderer (Playwright-based)
122
+ export {
123
+ renderVariants,
124
+ renderAllComponentVariants,
125
+ checkStorybookRunning,
126
+ getStorybookStoryIds,
127
+ shutdownSharedPool,
128
+ type RenderedVariant,
129
+ type VariantRenderResult,
130
+ type VariantRenderOptions,
131
+ } from "./variant-renderer.js";