@fragments-sdk/cli 0.11.1 → 0.12.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 (86) hide show
  1. package/dist/ai-client-I6MDWNYA.js +21 -0
  2. package/dist/bin.js +275 -368
  3. package/dist/bin.js.map +1 -1
  4. package/dist/{chunk-PW7QTQA6.js → chunk-4OC7FTJB.js} +2 -2
  5. package/dist/{chunk-HRFUSSZI.js → chunk-AM4MRTMN.js} +2 -2
  6. package/dist/{chunk-5G3VZH43.js → chunk-GVDSFQ4E.js} +281 -351
  7. package/dist/chunk-GVDSFQ4E.js.map +1 -0
  8. package/dist/chunk-JJ2VRTBU.js +626 -0
  9. package/dist/chunk-JJ2VRTBU.js.map +1 -0
  10. package/dist/{chunk-D5PYOXEI.js → chunk-LVWFOLUZ.js} +148 -13
  11. package/dist/{chunk-D5PYOXEI.js.map → chunk-LVWFOLUZ.js.map} +1 -1
  12. package/dist/{chunk-WXSR2II7.js → chunk-OQKMEFOS.js} +58 -6
  13. package/dist/chunk-OQKMEFOS.js.map +1 -0
  14. package/dist/chunk-SXTKFDCR.js +104 -0
  15. package/dist/chunk-SXTKFDCR.js.map +1 -0
  16. package/dist/chunk-T5OMVL7E.js +443 -0
  17. package/dist/chunk-T5OMVL7E.js.map +1 -0
  18. package/dist/{chunk-ZM4ZQZWZ.js → chunk-TPWGL2XS.js} +39 -37
  19. package/dist/chunk-TPWGL2XS.js.map +1 -0
  20. package/dist/{chunk-OQO55NKV.js → chunk-WFS63PCW.js} +85 -11
  21. package/dist/chunk-WFS63PCW.js.map +1 -0
  22. package/dist/core/index.js +9 -1
  23. package/dist/{discovery-NEOY4MPN.js → discovery-ZJQSXF56.js} +3 -3
  24. package/dist/{generate-FBHSXR3D.js → generate-RJFS2JWA.js} +4 -4
  25. package/dist/index.js +7 -6
  26. package/dist/index.js.map +1 -1
  27. package/dist/init-ZSX3NRCZ.js +636 -0
  28. package/dist/init-ZSX3NRCZ.js.map +1 -0
  29. package/dist/mcp-bin.js +2 -2
  30. package/dist/{scan-CJF2DOQW.js → scan-3PMCJ4RB.js} +6 -6
  31. package/dist/scan-generate-SYU4PYZD.js +1115 -0
  32. package/dist/scan-generate-SYU4PYZD.js.map +1 -0
  33. package/dist/{service-TQYWY65E.js → service-VMGNJZ42.js} +3 -3
  34. package/dist/{snapshot-SV2JOFZH.js → snapshot-XOISO2IS.js} +2 -2
  35. package/dist/{static-viewer-NUBFPKWH.js → static-viewer-5GXH2MGE.js} +3 -3
  36. package/dist/static-viewer-5GXH2MGE.js.map +1 -0
  37. package/dist/{test-Z5LVO724.js → test-SI4NSHQX.js} +4 -4
  38. package/dist/{tokens-CE46OTMD.js → tokens-T6SIVUT5.js} +5 -5
  39. package/dist/{viewer-DLLJIMCK.js → viewer-7ZEAFBVN.js} +13 -13
  40. package/package.json +4 -4
  41. package/src/ai-client.ts +156 -0
  42. package/src/bin.ts +44 -2
  43. package/src/build.ts +95 -33
  44. package/src/commands/__tests__/drift-sync.test.ts +252 -0
  45. package/src/commands/__tests__/scan-generate.test.ts +497 -45
  46. package/src/commands/enhance.ts +11 -35
  47. package/src/commands/init.ts +288 -260
  48. package/src/commands/scan-generate.ts +740 -139
  49. package/src/commands/scan.ts +37 -32
  50. package/src/commands/setup.ts +143 -52
  51. package/src/commands/sync.ts +357 -0
  52. package/src/commands/validate.ts +43 -1
  53. package/src/core/component-extractor.test.ts +282 -0
  54. package/src/core/component-extractor.ts +1030 -0
  55. package/src/core/discovery.ts +93 -7
  56. package/src/service/enhance/props-extractor.ts +235 -13
  57. package/src/validators.ts +236 -0
  58. package/dist/chunk-5G3VZH43.js.map +0 -1
  59. package/dist/chunk-OQO55NKV.js.map +0 -1
  60. package/dist/chunk-WXSR2II7.js.map +0 -1
  61. package/dist/chunk-ZM4ZQZWZ.js.map +0 -1
  62. package/dist/init-UFGK5TCN.js +0 -867
  63. package/dist/init-UFGK5TCN.js.map +0 -1
  64. package/dist/scan-generate-SJAN5MVI.js +0 -691
  65. package/dist/scan-generate-SJAN5MVI.js.map +0 -1
  66. package/src/ai.ts +0 -266
  67. package/src/commands/init-framework.ts +0 -414
  68. package/src/mcp/bin.ts +0 -36
  69. package/src/migrate/bin.ts +0 -114
  70. package/src/theme/index.ts +0 -77
  71. package/src/viewer/bin.ts +0 -86
  72. package/src/viewer/cli/health.ts +0 -256
  73. package/src/viewer/cli/index.ts +0 -33
  74. package/src/viewer/cli/scan.ts +0 -124
  75. package/src/viewer/cli/utils.ts +0 -174
  76. /package/dist/{discovery-NEOY4MPN.js.map → ai-client-I6MDWNYA.js.map} +0 -0
  77. /package/dist/{chunk-PW7QTQA6.js.map → chunk-4OC7FTJB.js.map} +0 -0
  78. /package/dist/{chunk-HRFUSSZI.js.map → chunk-AM4MRTMN.js.map} +0 -0
  79. /package/dist/{scan-CJF2DOQW.js.map → discovery-ZJQSXF56.js.map} +0 -0
  80. /package/dist/{generate-FBHSXR3D.js.map → generate-RJFS2JWA.js.map} +0 -0
  81. /package/dist/{service-TQYWY65E.js.map → scan-3PMCJ4RB.js.map} +0 -0
  82. /package/dist/{static-viewer-NUBFPKWH.js.map → service-VMGNJZ42.js.map} +0 -0
  83. /package/dist/{snapshot-SV2JOFZH.js.map → snapshot-XOISO2IS.js.map} +0 -0
  84. /package/dist/{test-Z5LVO724.js.map → test-SI4NSHQX.js.map} +0 -0
  85. /package/dist/{tokens-CE46OTMD.js.map → tokens-T6SIVUT5.js.map} +0 -0
  86. /package/dist/{viewer-DLLJIMCK.js.map → viewer-7ZEAFBVN.js.map} +0 -0
@@ -0,0 +1,626 @@
1
+ import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
+
3
+ // src/core/component-extractor.ts
4
+ import ts from "typescript";
5
+ import { readFileSync } from "fs";
6
+ import { resolve, dirname } from "path";
7
+ function createComponentExtractor(tsconfigPath) {
8
+ let projectVersion = 0;
9
+ const fileVersions = /* @__PURE__ */ new Map();
10
+ const fileSnapshots = /* @__PURE__ */ new Map();
11
+ const rootDir = tsconfigPath ? dirname(resolve(tsconfigPath)) : process.cwd();
12
+ const parsedCommandLine = tsconfigPath ? parseTsConfig(tsconfigPath) : inferCompilerOptions(rootDir);
13
+ const scriptFileNames = new Set(parsedCommandLine.fileNames);
14
+ const host = {
15
+ getProjectVersion: () => projectVersion.toString(),
16
+ getScriptVersion: (fileName) => (fileVersions.get(fileName) ?? 0).toString(),
17
+ getScriptSnapshot: (fileName) => {
18
+ const cached = fileSnapshots.get(fileName);
19
+ if (cached) return cached;
20
+ let text;
21
+ try {
22
+ text = readFileSync(fileName, "utf-8");
23
+ } catch {
24
+ return void 0;
25
+ }
26
+ const snapshot = ts.ScriptSnapshot.fromString(text);
27
+ fileSnapshots.set(fileName, snapshot);
28
+ return snapshot;
29
+ },
30
+ getScriptFileNames: () => [...scriptFileNames],
31
+ getCompilationSettings: () => parsedCommandLine.options,
32
+ getCurrentDirectory: () => rootDir,
33
+ getDefaultLibFileName: ts.getDefaultLibFilePath,
34
+ fileExists: ts.sys.fileExists,
35
+ readFile: ts.sys.readFile,
36
+ readDirectory: ts.sys.readDirectory,
37
+ directoryExists: ts.sys.directoryExists,
38
+ getDirectories: ts.sys.getDirectories
39
+ };
40
+ const languageService = ts.createLanguageService(host, ts.createDocumentRegistry());
41
+ function ensureFile(filePath) {
42
+ const resolved = resolve(filePath);
43
+ if (!scriptFileNames.has(resolved)) {
44
+ scriptFileNames.add(resolved);
45
+ projectVersion++;
46
+ }
47
+ }
48
+ function getChecker() {
49
+ const program = languageService.getProgram();
50
+ if (!program) throw new Error("Failed to get program from LanguageService");
51
+ return program.getTypeChecker();
52
+ }
53
+ function getSourceFile(filePath) {
54
+ return languageService.getProgram()?.getSourceFile(resolve(filePath));
55
+ }
56
+ return {
57
+ extract(filePath, exportName) {
58
+ const resolved = resolve(filePath);
59
+ ensureFile(resolved);
60
+ const sourceFile = getSourceFile(resolved);
61
+ if (!sourceFile) return null;
62
+ const checker = getChecker();
63
+ const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
64
+ if (!moduleSymbol) return null;
65
+ const exports = checker.getExportsOfModule(moduleSymbol);
66
+ const targetName = exportName ?? findPrimaryExport(exports, sourceFile);
67
+ if (!targetName) return null;
68
+ const exportSymbol = exports.find((s) => s.getName() === targetName);
69
+ if (!exportSymbol) return null;
70
+ const component = resolveExportedComponent(checker, exportSymbol, sourceFile);
71
+ if (!component) return null;
72
+ return buildComponentMeta(checker, component, resolved, sourceFile, exports);
73
+ },
74
+ extractAll(filePath) {
75
+ const resolved = resolve(filePath);
76
+ ensureFile(resolved);
77
+ const sourceFile = getSourceFile(resolved);
78
+ if (!sourceFile) return [];
79
+ const checker = getChecker();
80
+ const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
81
+ if (!moduleSymbol) return [];
82
+ const exports = checker.getExportsOfModule(moduleSymbol);
83
+ const results = [];
84
+ for (const exportSymbol of exports) {
85
+ const name = exportSymbol.getName();
86
+ if (!/^[A-Z]/.test(name)) continue;
87
+ const component = resolveExportedComponent(checker, exportSymbol, sourceFile);
88
+ if (!component) continue;
89
+ const meta = buildComponentMeta(checker, component, resolved, sourceFile, exports);
90
+ if (meta) results.push(meta);
91
+ }
92
+ return results;
93
+ },
94
+ invalidate(filePath) {
95
+ const resolved = resolve(filePath);
96
+ fileVersions.set(resolved, (fileVersions.get(resolved) ?? 0) + 1);
97
+ fileSnapshots.delete(resolved);
98
+ projectVersion++;
99
+ },
100
+ dispose() {
101
+ languageService.dispose();
102
+ fileSnapshots.clear();
103
+ fileVersions.clear();
104
+ }
105
+ };
106
+ }
107
+ function parseTsConfig(tsconfigPath) {
108
+ const resolved = resolve(tsconfigPath);
109
+ const configFile = ts.readConfigFile(resolved, ts.sys.readFile);
110
+ if (configFile.error) {
111
+ throw new Error(`Failed to read tsconfig: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`);
112
+ }
113
+ return ts.parseJsonConfigFileContent(
114
+ configFile.config,
115
+ ts.sys,
116
+ dirname(resolved),
117
+ void 0,
118
+ resolved
119
+ );
120
+ }
121
+ function inferCompilerOptions(rootDir) {
122
+ return {
123
+ options: {
124
+ target: ts.ScriptTarget.ES2022,
125
+ module: ts.ModuleKind.ESNext,
126
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
127
+ jsx: ts.JsxEmit.ReactJSX,
128
+ allowSyntheticDefaultImports: true,
129
+ esModuleInterop: true,
130
+ skipLibCheck: true,
131
+ strict: false,
132
+ noEmit: true
133
+ },
134
+ fileNames: [],
135
+ errors: []
136
+ };
137
+ }
138
+ function findPrimaryExport(exports, sourceFile) {
139
+ const defaultExport = exports.find((s) => s.getName() === "default");
140
+ if (defaultExport) return "default";
141
+ for (const s of exports) {
142
+ if (/^[A-Z][a-zA-Z0-9]*$/.test(s.getName())) {
143
+ return s.getName();
144
+ }
145
+ }
146
+ return null;
147
+ }
148
+ function resolveExportedComponent(checker, exportSymbol, sourceFile) {
149
+ const name = exportSymbol.getName();
150
+ let symbol = exportSymbol;
151
+ if (symbol.flags & ts.SymbolFlags.Alias) {
152
+ symbol = checker.getAliasedSymbol(symbol);
153
+ }
154
+ const declarations = symbol.getDeclarations();
155
+ if (!declarations || declarations.length === 0) return null;
156
+ const declaration = declarations[0];
157
+ if (ts.isVariableDeclaration(declaration) && declaration.initializer) {
158
+ return resolveFromExpression(checker, name, declaration.initializer, declaration, sourceFile);
159
+ }
160
+ if (ts.isFunctionDeclaration(declaration)) {
161
+ const propsType = extractPropsFromFunctionLike(checker, declaration);
162
+ return propsType ? { name, propsType, componentNode: declaration, compoundParts: null } : null;
163
+ }
164
+ if (ts.isExportAssignment(declaration) && declaration.expression) {
165
+ return resolveFromExpression(checker, name, declaration.expression, null, sourceFile);
166
+ }
167
+ return null;
168
+ }
169
+ function resolveFromExpression(checker, name, expression, variableDecl, sourceFile) {
170
+ expression = unwrapExpression(expression);
171
+ if (ts.isArrowFunction(expression) || ts.isFunctionExpression(expression)) {
172
+ const propsType = extractPropsFromFunctionLike(checker, expression);
173
+ return propsType ? { name, propsType, componentNode: expression, compoundParts: null } : null;
174
+ }
175
+ if (ts.isCallExpression(expression)) {
176
+ return resolveCallExpression(checker, name, expression, variableDecl, sourceFile);
177
+ }
178
+ if (ts.isIdentifier(expression)) {
179
+ const sym = checker.getSymbolAtLocation(expression);
180
+ if (sym) {
181
+ const decls = sym.getDeclarations();
182
+ if (decls && decls.length > 0) {
183
+ const decl = decls[0];
184
+ if (ts.isVariableDeclaration(decl) && decl.initializer) {
185
+ return resolveFromExpression(checker, name, decl.initializer, decl, sourceFile);
186
+ }
187
+ if (ts.isFunctionDeclaration(decl)) {
188
+ const propsType = extractPropsFromFunctionLike(checker, decl);
189
+ return propsType ? { name, propsType, componentNode: decl, compoundParts: null } : null;
190
+ }
191
+ }
192
+ }
193
+ }
194
+ if (variableDecl?.type && ts.isTypeReferenceNode(variableDecl.type)) {
195
+ const typeName = variableDecl.type.typeName.getText(sourceFile);
196
+ if (typeName.includes("FC") || typeName.includes("FunctionComponent")) {
197
+ const typeArg = variableDecl.type.typeArguments?.[0];
198
+ if (typeArg) {
199
+ const propsType = checker.getTypeFromTypeNode(typeArg);
200
+ return { name, propsType, componentNode: expression, compoundParts: null };
201
+ }
202
+ }
203
+ }
204
+ return null;
205
+ }
206
+ function resolveCallExpression(checker, name, call, variableDecl, sourceFile) {
207
+ const callee = call.expression;
208
+ if (isObjectAssignCall(callee, sourceFile)) {
209
+ return resolveObjectAssign(checker, name, call, sourceFile);
210
+ }
211
+ if (isForwardRefCall(callee)) {
212
+ return resolveForwardRef(checker, name, call, sourceFile);
213
+ }
214
+ if (isMemoCall(callee)) {
215
+ const innerArg = call.arguments[0];
216
+ if (innerArg) {
217
+ return resolveFromExpression(checker, name, innerArg, variableDecl, sourceFile);
218
+ }
219
+ }
220
+ return null;
221
+ }
222
+ function resolveObjectAssign(checker, name, call, sourceFile) {
223
+ if (call.arguments.length < 2) return null;
224
+ const rootExpr = call.arguments[0];
225
+ const rootResult = resolveFromExpression(checker, name, rootExpr, null, sourceFile);
226
+ const subsArg = call.arguments[1];
227
+ const compoundParts = /* @__PURE__ */ new Map();
228
+ if (ts.isObjectLiteralExpression(subsArg)) {
229
+ for (const prop of subsArg.properties) {
230
+ let subName = null;
231
+ let subExpression = null;
232
+ if (ts.isShorthandPropertyAssignment(prop)) {
233
+ subName = prop.name.text;
234
+ const sym = checker.getSymbolAtLocation(prop.name);
235
+ if (sym) {
236
+ const subPropsType = extractPropsFromComponentSymbol(checker, sym);
237
+ if (subPropsType) {
238
+ compoundParts.set(subName, subPropsType);
239
+ }
240
+ }
241
+ } else if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
242
+ subName = prop.name.text;
243
+ subExpression = prop.initializer;
244
+ if (subExpression) {
245
+ const subType = extractPropsFromExpression(checker, subExpression, sourceFile);
246
+ if (subType) {
247
+ compoundParts.set(subName, subType);
248
+ }
249
+ }
250
+ }
251
+ }
252
+ }
253
+ return {
254
+ name,
255
+ propsType: rootResult?.propsType ?? null,
256
+ componentNode: rootResult?.componentNode ?? rootExpr,
257
+ compoundParts: compoundParts.size > 0 ? compoundParts : null
258
+ };
259
+ }
260
+ function extractPropsFromComponentSymbol(checker, symbol) {
261
+ let sym = symbol;
262
+ if (sym.flags & ts.SymbolFlags.Alias) {
263
+ sym = checker.getAliasedSymbol(sym);
264
+ }
265
+ const decls = sym.getDeclarations();
266
+ if (!decls || decls.length === 0) return null;
267
+ const decl = decls[0];
268
+ if (ts.isFunctionDeclaration(decl)) {
269
+ return extractPropsFromFunctionLike(checker, decl);
270
+ }
271
+ if (ts.isVariableDeclaration(decl) && decl.initializer) {
272
+ return extractPropsFromExpressionDeep(checker, decl);
273
+ }
274
+ return null;
275
+ }
276
+ function extractPropsFromExpression(checker, expr, sourceFile) {
277
+ expr = unwrapExpression(expr);
278
+ if (ts.isIdentifier(expr)) {
279
+ const sym = checker.getSymbolAtLocation(expr);
280
+ if (sym) return extractPropsFromComponentSymbol(checker, sym);
281
+ }
282
+ if (ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) {
283
+ return extractPropsFromFunctionLike(checker, expr);
284
+ }
285
+ if (ts.isCallExpression(expr)) {
286
+ if (isForwardRefCall(expr.expression)) {
287
+ const typeArg = expr.typeArguments?.[1];
288
+ if (typeArg) return checker.getTypeFromTypeNode(typeArg);
289
+ const innerArg = expr.arguments[0];
290
+ if (innerArg && (ts.isArrowFunction(innerArg) || ts.isFunctionExpression(innerArg))) {
291
+ return extractPropsFromFunctionLike(checker, innerArg);
292
+ }
293
+ }
294
+ if (isMemoCall(expr.expression) && expr.arguments[0]) {
295
+ return extractPropsFromExpression(checker, expr.arguments[0], sourceFile);
296
+ }
297
+ }
298
+ return null;
299
+ }
300
+ function extractPropsFromExpressionDeep(checker, decl) {
301
+ if (!decl.initializer) return null;
302
+ let expr = unwrapExpression(decl.initializer);
303
+ if (ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) {
304
+ return extractPropsFromFunctionLike(checker, expr);
305
+ }
306
+ if (ts.isCallExpression(expr)) {
307
+ if (isForwardRefCall(expr.expression)) {
308
+ const typeArg = expr.typeArguments?.[1];
309
+ if (typeArg) return checker.getTypeFromTypeNode(typeArg);
310
+ const innerArg = expr.arguments[0];
311
+ if (innerArg && (ts.isArrowFunction(innerArg) || ts.isFunctionExpression(innerArg))) {
312
+ return extractPropsFromFunctionLike(checker, innerArg);
313
+ }
314
+ }
315
+ if (isMemoCall(expr.expression) && expr.arguments[0]) {
316
+ return extractPropsFromExpressionDeep(checker, {
317
+ ...decl,
318
+ initializer: expr.arguments[0]
319
+ });
320
+ }
321
+ }
322
+ return null;
323
+ }
324
+ function resolveForwardRef(checker, name, call, sourceFile) {
325
+ const propsTypeArg = call.typeArguments?.[1];
326
+ if (propsTypeArg) {
327
+ const propsType = checker.getTypeFromTypeNode(propsTypeArg);
328
+ const innerArg2 = call.arguments[0];
329
+ const componentNode = innerArg2 && (ts.isArrowFunction(innerArg2) || ts.isFunctionExpression(innerArg2)) ? innerArg2 : null;
330
+ return { name, propsType, componentNode, compoundParts: null };
331
+ }
332
+ const innerArg = call.arguments[0];
333
+ if (innerArg) {
334
+ if (ts.isArrowFunction(innerArg) || ts.isFunctionExpression(innerArg)) {
335
+ const propsType = extractPropsFromFunctionLike(checker, innerArg);
336
+ return propsType ? { name, propsType, componentNode: innerArg, compoundParts: null } : null;
337
+ }
338
+ if (ts.isIdentifier(innerArg)) {
339
+ const sym = checker.getSymbolAtLocation(innerArg);
340
+ if (sym) {
341
+ const propsType = extractPropsFromComponentSymbol(checker, sym);
342
+ if (propsType) return { name, propsType, componentNode: innerArg, compoundParts: null };
343
+ }
344
+ }
345
+ }
346
+ return null;
347
+ }
348
+ function extractPropsFromFunctionLike(checker, func) {
349
+ const firstParam = func.parameters[0];
350
+ if (!firstParam) return null;
351
+ if (firstParam.type) {
352
+ return checker.getTypeFromTypeNode(firstParam.type);
353
+ }
354
+ const paramSymbol = checker.getSymbolAtLocation(firstParam.name);
355
+ if (paramSymbol) {
356
+ return checker.getTypeOfSymbolAtLocation(paramSymbol, firstParam);
357
+ }
358
+ return null;
359
+ }
360
+ function buildComponentMeta(checker, component, filePath, sourceFile, moduleExports) {
361
+ const props = {};
362
+ const sourceFilePath = toPosixPath(sourceFile.fileName);
363
+ if (component.propsType) {
364
+ extractPropsFromType(checker, component.propsType, props, sourceFilePath);
365
+ }
366
+ const defaults = component.componentNode ? extractDefaultValues(component.componentNode) : {};
367
+ for (const [propName, defaultVal] of Object.entries(defaults)) {
368
+ if (props[propName]) {
369
+ props[propName].default = defaultVal;
370
+ }
371
+ }
372
+ let composition = null;
373
+ if (component.compoundParts && component.compoundParts.size > 0) {
374
+ const parts = [];
375
+ for (const [partName, partType] of component.compoundParts) {
376
+ const partProps = {};
377
+ extractPropsFromType(checker, partType, partProps, sourceFilePath);
378
+ parts.push({ name: partName, props: partProps });
379
+ }
380
+ composition = {
381
+ pattern: "compound",
382
+ parts,
383
+ required: []
384
+ // Could be inferred from usage patterns
385
+ };
386
+ }
387
+ let description = "";
388
+ const componentSymbol = moduleExports.find((s) => s.getName() === component.name);
389
+ if (componentSymbol) {
390
+ description = extractJSDocDescription(checker, componentSymbol);
391
+ }
392
+ const exportNames = moduleExports.filter((s) => /^[A-Z]/.test(s.getName())).map((s) => s.getName());
393
+ const dependencies = extractDependencies(sourceFile);
394
+ return {
395
+ name: component.name,
396
+ filePath,
397
+ description,
398
+ props,
399
+ composition,
400
+ exports: exportNames,
401
+ dependencies
402
+ };
403
+ }
404
+ function extractPropsFromType(checker, propsType, result, sourceFilePath) {
405
+ for (const symbol of checker.getPropertiesOfType(propsType)) {
406
+ const propName = symbol.getName();
407
+ if (propName.startsWith("_") || propName.startsWith("$")) continue;
408
+ if (propName === "key" || propName === "ref") continue;
409
+ const declarations = symbol.getDeclarations() ?? [];
410
+ const isLocal = declarations.some(
411
+ (d) => toPosixPath(d.getSourceFile().fileName) === sourceFilePath
412
+ );
413
+ const referenceNode = declarations[0];
414
+ if (!referenceNode) continue;
415
+ const propType = checker.getTypeOfSymbolAtLocation(symbol, referenceNode);
416
+ const serialized = serializePropType(checker, propType);
417
+ const description = ts.displayPartsToString(symbol.getDocumentationComment(checker)).trim();
418
+ const required = (symbol.flags & ts.SymbolFlags.Optional) === 0;
419
+ let jsDocDefault;
420
+ const jsDocTags = symbol.getJsDocTags(checker);
421
+ const defaultTag = jsDocTags.find((t) => t.name === "default");
422
+ if (defaultTag?.text) {
423
+ jsDocDefault = ts.displayPartsToString(defaultTag.text).trim();
424
+ }
425
+ result[propName] = {
426
+ name: propName,
427
+ type: serialized.type,
428
+ typeKind: serialized.typeKind,
429
+ values: serialized.values,
430
+ default: jsDocDefault,
431
+ description: description || void 0,
432
+ required,
433
+ source: isLocal ? "local" : "inherited"
434
+ };
435
+ }
436
+ }
437
+ function serializePropType(checker, type) {
438
+ const aliasSymbol = type.aliasSymbol;
439
+ if (aliasSymbol) {
440
+ const aliasName = aliasSymbol.getName();
441
+ if (aliasName === "ReactNode") {
442
+ return { type: "ReactNode", typeKind: "node" };
443
+ }
444
+ if (aliasName === "ReactElement") {
445
+ return { type: "ReactElement", typeKind: "element" };
446
+ }
447
+ }
448
+ if (type.isUnion()) {
449
+ const nonNullableTypes = type.types.filter(
450
+ (t) => !(t.flags & ts.TypeFlags.Undefined || t.flags & ts.TypeFlags.Null || t.flags & ts.TypeFlags.Void)
451
+ );
452
+ if (nonNullableTypes.length === 1) {
453
+ return serializePropType(checker, nonNullableTypes[0]);
454
+ }
455
+ if (nonNullableTypes.length > 0 && nonNullableTypes.every((t) => t.isStringLiteral())) {
456
+ const values = nonNullableTypes.map((t) => t.value);
457
+ return {
458
+ type: values.map((v) => `"${v}"`).join(" | "),
459
+ typeKind: "enum",
460
+ values
461
+ };
462
+ }
463
+ if (nonNullableTypes.every((t) => isBooleanLike(t))) {
464
+ return { type: "boolean", typeKind: "boolean" };
465
+ }
466
+ const typeStr2 = checker.typeToString(type, void 0, ts.TypeFormatFlags.NoTruncation);
467
+ return { type: typeStr2, typeKind: "union" };
468
+ }
469
+ const typeStr = checker.typeToString(type, void 0, ts.TypeFormatFlags.NoTruncation);
470
+ if (typeStr.includes("ReactNode")) {
471
+ return { type: "ReactNode", typeKind: "node" };
472
+ }
473
+ if (typeStr.includes("ReactElement") || typeStr.includes("JSX.Element")) {
474
+ return { type: "ReactElement", typeKind: "element" };
475
+ }
476
+ if (type.getCallSignatures().length > 0) {
477
+ return { type: typeStr, typeKind: "function" };
478
+ }
479
+ if (type.flags & ts.TypeFlags.String) return { type: "string", typeKind: "string" };
480
+ if (type.flags & ts.TypeFlags.Number) return { type: "number", typeKind: "number" };
481
+ if (type.flags & ts.TypeFlags.Boolean || type.flags & ts.TypeFlags.BooleanLiteral) {
482
+ return { type: "boolean", typeKind: "boolean" };
483
+ }
484
+ if (type.isStringLiteral()) {
485
+ return { type: `"${type.value}"`, typeKind: "enum", values: [type.value] };
486
+ }
487
+ if (checker.isArrayType(type) || checker.isTupleType(type)) {
488
+ return { type: typeStr, typeKind: "array" };
489
+ }
490
+ if (type.flags & ts.TypeFlags.Object) {
491
+ return { type: typeStr, typeKind: "object" };
492
+ }
493
+ return { type: typeStr, typeKind: "custom" };
494
+ }
495
+ function extractDefaultValues(node) {
496
+ const defaults = {};
497
+ let funcNode = null;
498
+ if (ts.isFunctionDeclaration(node) || ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
499
+ funcNode = node;
500
+ }
501
+ if (!funcNode?.parameters?.length) return defaults;
502
+ const firstParam = funcNode.parameters[0];
503
+ if (!ts.isObjectBindingPattern(firstParam.name)) return defaults;
504
+ for (const element of firstParam.name.elements) {
505
+ let propName = null;
506
+ if (element.propertyName) {
507
+ if (ts.isIdentifier(element.propertyName) || ts.isStringLiteral(element.propertyName)) {
508
+ propName = element.propertyName.text;
509
+ }
510
+ } else if (ts.isIdentifier(element.name)) {
511
+ propName = element.name.text;
512
+ }
513
+ if (!propName || !element.initializer) continue;
514
+ const value = readLiteralValue(element.initializer);
515
+ if (value !== void 0) {
516
+ defaults[propName] = value;
517
+ }
518
+ }
519
+ return defaults;
520
+ }
521
+ function readLiteralValue(expression) {
522
+ if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) {
523
+ return expression.text;
524
+ }
525
+ if (ts.isNumericLiteral(expression)) {
526
+ return expression.text;
527
+ }
528
+ if (expression.kind === ts.SyntaxKind.TrueKeyword) return "true";
529
+ if (expression.kind === ts.SyntaxKind.FalseKeyword) return "false";
530
+ if (expression.kind === ts.SyntaxKind.NullKeyword) return "null";
531
+ if (ts.isPrefixUnaryExpression(expression) && expression.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(expression.operand)) {
532
+ return `-${expression.operand.text}`;
533
+ }
534
+ return void 0;
535
+ }
536
+ function extractJSDocDescription(checker, symbol) {
537
+ let sym = symbol;
538
+ if (sym.flags & ts.SymbolFlags.Alias) {
539
+ sym = checker.getAliasedSymbol(sym);
540
+ }
541
+ const docComment = ts.displayPartsToString(sym.getDocumentationComment(checker)).trim();
542
+ if (docComment) return docComment;
543
+ const decls = sym.getDeclarations();
544
+ if (decls) {
545
+ for (const decl of decls) {
546
+ const sourceFile = decl.getSourceFile();
547
+ for (const stmt of sourceFile.statements) {
548
+ if ((ts.isInterfaceDeclaration(stmt) || ts.isTypeAliasDeclaration(stmt)) && stmt.name.text === `${symbol.getName()}Props`) {
549
+ const propsDoc = ts.displayPartsToString(
550
+ checker.getSymbolAtLocation(stmt.name)?.getDocumentationComment(checker) ?? []
551
+ ).trim();
552
+ if (propsDoc) return propsDoc;
553
+ }
554
+ }
555
+ }
556
+ }
557
+ return "";
558
+ }
559
+ function extractDependencies(sourceFile) {
560
+ const deps = [];
561
+ for (const stmt of sourceFile.statements) {
562
+ if (!ts.isImportDeclaration(stmt)) continue;
563
+ if (!ts.isStringLiteral(stmt.moduleSpecifier)) continue;
564
+ const modulePath = stmt.moduleSpecifier.text;
565
+ if (!modulePath.startsWith(".") && !modulePath.startsWith("/")) continue;
566
+ const clause = stmt.importClause;
567
+ if (!clause) continue;
568
+ if (clause.name && /^[A-Z]/.test(clause.name.text)) {
569
+ deps.push(clause.name.text);
570
+ }
571
+ if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
572
+ for (const element of clause.namedBindings.elements) {
573
+ if (/^[A-Z]/.test(element.name.text)) {
574
+ deps.push(element.name.text);
575
+ }
576
+ }
577
+ }
578
+ }
579
+ return deps;
580
+ }
581
+ function unwrapExpression(expr) {
582
+ while (true) {
583
+ if (ts.isParenthesizedExpression(expr)) {
584
+ expr = expr.expression;
585
+ } else if (ts.isAsExpression(expr) || ts.isTypeAssertionExpression(expr)) {
586
+ expr = expr.expression;
587
+ } else {
588
+ return expr;
589
+ }
590
+ }
591
+ }
592
+ function isObjectAssignCall(callee, sourceFile) {
593
+ if (ts.isPropertyAccessExpression(callee) && ts.isIdentifier(callee.expression) && callee.expression.text === "Object" && callee.name.text === "assign") {
594
+ return true;
595
+ }
596
+ return false;
597
+ }
598
+ function isForwardRefCall(callee) {
599
+ if (ts.isPropertyAccessExpression(callee) && callee.name.text === "forwardRef") {
600
+ return true;
601
+ }
602
+ if (ts.isIdentifier(callee) && callee.text === "forwardRef") {
603
+ return true;
604
+ }
605
+ return false;
606
+ }
607
+ function isMemoCall(callee) {
608
+ if (ts.isPropertyAccessExpression(callee) && callee.name.text === "memo") {
609
+ return true;
610
+ }
611
+ if (ts.isIdentifier(callee) && callee.text === "memo") {
612
+ return true;
613
+ }
614
+ return false;
615
+ }
616
+ function isBooleanLike(type) {
617
+ return (type.flags & ts.TypeFlags.BooleanLike) !== 0 || type.flags === ts.TypeFlags.BooleanLiteral;
618
+ }
619
+ function toPosixPath(filePath) {
620
+ return filePath.replace(/\\/g, "/");
621
+ }
622
+
623
+ export {
624
+ createComponentExtractor
625
+ };
626
+ //# sourceMappingURL=chunk-JJ2VRTBU.js.map