@agent-scope/manifest 1.0.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,731 @@
1
+ 'use strict';
2
+
3
+ var path = require('path');
4
+ var tsMorph = require('ts-morph');
5
+
6
+ // src/parser.ts
7
+ function collectCallExpressions(root) {
8
+ const results = [];
9
+ root.forEachDescendant((n) => {
10
+ if (tsMorph.Node.isCallExpression(n)) {
11
+ results.push(n);
12
+ }
13
+ });
14
+ return results;
15
+ }
16
+ function calleeText(callExpr) {
17
+ if (!tsMorph.Node.isCallExpression(callExpr)) return "";
18
+ return callExpr.getExpression().getText().trim();
19
+ }
20
+ var COMPLEX_STYLE_KEYS = /* @__PURE__ */ new Set([
21
+ "position",
22
+ "gridTemplate",
23
+ "gridTemplateColumns",
24
+ "gridTemplateRows",
25
+ "gridArea",
26
+ "gridColumn",
27
+ "gridRow",
28
+ "grid",
29
+ "animation",
30
+ "animationName",
31
+ "animationDuration",
32
+ "transition",
33
+ "transform",
34
+ "transformOrigin",
35
+ "clip",
36
+ "clipPath",
37
+ "willChange",
38
+ "contain"
39
+ ]);
40
+ var COMPLEX_POSITION_VALUES = /* @__PURE__ */ new Set(["absolute", "fixed", "sticky"]);
41
+ var COMPLEX_KEY_PREFIXES = ["grid", "animation", "transition"];
42
+ function isComplexStyleKey(key) {
43
+ if (COMPLEX_STYLE_KEYS.has(key)) return true;
44
+ return COMPLEX_KEY_PREFIXES.some((p) => key.startsWith(p));
45
+ }
46
+ function hasCssComplexity(root) {
47
+ let complex = false;
48
+ root.forEachDescendant((n) => {
49
+ if (complex) return;
50
+ if (tsMorph.Node.isJsxAttribute(n)) {
51
+ const nameNode = n.getNameNode();
52
+ if (nameNode.getText() !== "style") return;
53
+ const initializer = n.getInitializer();
54
+ if (!initializer) return;
55
+ if (tsMorph.Node.isJsxExpression(initializer)) {
56
+ const inner = initializer.getExpression();
57
+ if (!inner || !tsMorph.Node.isObjectLiteralExpression(inner)) return;
58
+ for (const prop of inner.getProperties()) {
59
+ if (complex) break;
60
+ if (!tsMorph.Node.isPropertyAssignment(prop) && !tsMorph.Node.isShorthandPropertyAssignment(prop)) {
61
+ continue;
62
+ }
63
+ const keyText = prop.getNameNode().getText();
64
+ if (isComplexStyleKey(keyText)) {
65
+ complex = true;
66
+ break;
67
+ }
68
+ if (keyText === "position" && tsMorph.Node.isPropertyAssignment(prop)) {
69
+ const val = prop.getInitializer();
70
+ if (val) {
71
+ const raw = val.getText().replace(/['"]/g, "").trim().toLowerCase();
72
+ if (COMPLEX_POSITION_VALUES.has(raw)) {
73
+ complex = true;
74
+ break;
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ return;
81
+ }
82
+ if (tsMorph.Node.isTaggedTemplateExpression(n)) {
83
+ const tag = n.getTag().getText();
84
+ if (tag.startsWith("styled") || tag === "css" || tag === "keyframes") {
85
+ complex = true;
86
+ }
87
+ return;
88
+ }
89
+ if (tsMorph.Node.isJsxAttribute(n)) {
90
+ const nameNode = n.getNameNode();
91
+ if (nameNode.getText() !== "className") return;
92
+ const initializer = n.getInitializer();
93
+ if (!initializer) return;
94
+ if (tsMorph.Node.isJsxExpression(initializer)) {
95
+ const inner = initializer.getExpression();
96
+ if (inner && (tsMorph.Node.isIdentifier(inner) || tsMorph.Node.isCallExpression(inner) || tsMorph.Node.isPropertyAccessExpression(inner))) {
97
+ complex = true;
98
+ }
99
+ }
100
+ }
101
+ });
102
+ return complex;
103
+ }
104
+ function analyzeComplexity(bodyNode) {
105
+ return hasCssComplexity(bodyNode) ? "complex" : "simple";
106
+ }
107
+ var HOOK_REGEX = /^use[A-Z]/;
108
+ function detectHooks(root) {
109
+ const names = /* @__PURE__ */ new Set();
110
+ collectCallExpressions(root).forEach((callExpr) => {
111
+ const callee = calleeText(callExpr);
112
+ const base = callee.split(".").pop() ?? callee;
113
+ if (HOOK_REGEX.test(base)) {
114
+ names.add(base);
115
+ }
116
+ });
117
+ return Array.from(names).sort();
118
+ }
119
+ function extractDirectContextNames(root) {
120
+ const names = /* @__PURE__ */ new Set();
121
+ collectCallExpressions(root).forEach((callExpr) => {
122
+ const callee = calleeText(callExpr);
123
+ const base = callee.split(".").pop() ?? callee;
124
+ if (base !== "useContext") return;
125
+ const args = (tsMorph.Node.isCallExpression(callExpr) ? callExpr : null)?.getArguments() ?? [];
126
+ const firstArg = args[0];
127
+ if (!firstArg) return;
128
+ const argText = firstArg.getText().trim();
129
+ if (argText) {
130
+ names.add(argText);
131
+ }
132
+ });
133
+ return Array.from(names);
134
+ }
135
+ function resolveHookContexts(hookName, importingFile, importSpecifier, project) {
136
+ const allFiles = project.getSourceFiles();
137
+ const importingDir = importingFile.getDirectoryPath();
138
+ const specParts = importSpecifier.replace(/^\.\.?\//, "");
139
+ const candidates = allFiles.filter((sf) => {
140
+ const fp = sf.getFilePath();
141
+ if (!fp.startsWith(importingDir.split("/src/")[0] ?? importingDir)) return false;
142
+ const basename = fp.split("/").pop() ?? "";
143
+ const specBase = specParts.split("/").pop() ?? specParts;
144
+ return basename === `${specBase}.ts` || basename === `${specBase}.tsx` || basename === `${specBase}.js` || basename === `${specBase}.jsx` || fp.endsWith(`${specParts}.ts`) || fp.endsWith(`${specParts}.tsx`) || fp.endsWith(`${importSpecifier}.ts`) || fp.endsWith(`${importSpecifier}.tsx`);
145
+ });
146
+ for (const candidate of candidates) {
147
+ const hookFunctions = [
148
+ ...candidate.getFunctions().filter((f) => f.getName() === hookName),
149
+ ...candidate.getVariableDeclarations().filter((v) => v.getName() === hookName)
150
+ ];
151
+ for (const fn of hookFunctions) {
152
+ const ctxNames = extractDirectContextNames(fn);
153
+ if (ctxNames.length > 0) return ctxNames;
154
+ }
155
+ }
156
+ return [];
157
+ }
158
+ function detectRequiredContexts(bodyNode, sourceFile, project) {
159
+ const contextNames = /* @__PURE__ */ new Set();
160
+ for (const name of extractDirectContextNames(bodyNode)) {
161
+ contextNames.add(name);
162
+ }
163
+ const hookedCalls = /* @__PURE__ */ new Set();
164
+ collectCallExpressions(bodyNode).forEach((callExpr) => {
165
+ const callee = calleeText(callExpr);
166
+ const base = callee.split(".").pop() ?? callee;
167
+ if (HOOK_REGEX.test(base) && base !== "useContext") {
168
+ hookedCalls.add(base);
169
+ }
170
+ });
171
+ if (hookedCalls.size === 0) {
172
+ return Array.from(contextNames).sort();
173
+ }
174
+ for (const importDecl of sourceFile.getImportDeclarations()) {
175
+ const specifier = importDecl.getModuleSpecifierValue();
176
+ if (!specifier.startsWith(".")) continue;
177
+ const namedImports = importDecl.getNamedImports();
178
+ for (const ni of namedImports) {
179
+ const hookName = ni.getName();
180
+ if (!hookedCalls.has(hookName)) continue;
181
+ const resolved = resolveHookContexts(hookName, sourceFile, specifier, project);
182
+ for (const ctx of resolved) {
183
+ contextNames.add(ctx);
184
+ }
185
+ }
186
+ }
187
+ return Array.from(contextNames).sort();
188
+ }
189
+ var FETCH_PATTERNS = [
190
+ /^fetch$/,
191
+ /^axios(\.[a-zA-Z]+)?$/,
192
+ /^useQuery$/,
193
+ /^useMutation$/,
194
+ /^useSWR$/,
195
+ /^useInfiniteQuery$/,
196
+ /^request$/
197
+ ];
198
+ var TIMER_PATTERNS = [
199
+ /^setTimeout$/,
200
+ /^setInterval$/,
201
+ /^requestAnimationFrame$/,
202
+ /^clearTimeout$/,
203
+ /^clearInterval$/,
204
+ /^cancelAnimationFrame$/
205
+ ];
206
+ var SUBSCRIPTION_PATTERNS = [
207
+ /\.subscribe$/,
208
+ /\.onSnapshot$/,
209
+ /\.on$/,
210
+ /\.listen$/,
211
+ /\.addListener$/
212
+ ];
213
+ var GLOBAL_LISTENER_PATTERNS = [
214
+ /^window\.addEventListener$/,
215
+ /^document\.addEventListener$/,
216
+ /^window\.removeEventListener$/,
217
+ /^document\.removeEventListener$/
218
+ ];
219
+ var BARE_ADD_EVENT_LISTENER = /^addEventListener$/;
220
+ function matchesAny(text, patterns) {
221
+ return patterns.some((p) => p.test(text));
222
+ }
223
+ function detectSideEffects(root) {
224
+ const fetches = /* @__PURE__ */ new Set();
225
+ let timers = false;
226
+ const subscriptions = /* @__PURE__ */ new Set();
227
+ let globalListeners = false;
228
+ for (const callExpr of collectCallExpressions(root)) {
229
+ const callee = calleeText(callExpr);
230
+ if (matchesAny(callee, FETCH_PATTERNS)) {
231
+ const name = callee.split(".")[0] ?? callee;
232
+ fetches.add(name);
233
+ continue;
234
+ }
235
+ if (matchesAny(callee, TIMER_PATTERNS)) {
236
+ timers = true;
237
+ continue;
238
+ }
239
+ if (matchesAny(callee, GLOBAL_LISTENER_PATTERNS)) {
240
+ globalListeners = true;
241
+ continue;
242
+ }
243
+ if (matchesAny(callee, SUBSCRIPTION_PATTERNS)) {
244
+ const parts = callee.split(".");
245
+ const method = parts[parts.length - 1] ?? callee;
246
+ subscriptions.add(method);
247
+ continue;
248
+ }
249
+ if (BARE_ADD_EVENT_LISTENER.test(callee)) {
250
+ globalListeners = true;
251
+ }
252
+ }
253
+ root.forEachDescendant((n) => {
254
+ if (tsMorph.Node.isPropertyAccessExpression(n)) {
255
+ const text = n.getText();
256
+ if ((text.startsWith("window.") || text.startsWith("document.")) && (text.endsWith("addEventListener") || text.endsWith("removeEventListener"))) {
257
+ globalListeners = true;
258
+ }
259
+ }
260
+ });
261
+ return {
262
+ fetches: Array.from(fetches).sort(),
263
+ timers,
264
+ subscriptions: Array.from(subscriptions).sort(),
265
+ globalListeners
266
+ };
267
+ }
268
+ function propagateComplexity(components) {
269
+ const queue = [];
270
+ for (const [name, desc] of Object.entries(components)) {
271
+ if (desc.complexityClass === "complex") {
272
+ queue.push(name);
273
+ }
274
+ }
275
+ const visited = new Set(queue);
276
+ while (queue.length > 0) {
277
+ const current = queue.shift();
278
+ const desc = components[current];
279
+ if (!desc) continue;
280
+ for (const parentName of desc.composedBy) {
281
+ const parent = components[parentName];
282
+ if (!parent) continue;
283
+ parent.complexityClass = "complex";
284
+ if (!visited.has(parentName)) {
285
+ visited.add(parentName);
286
+ queue.push(parentName);
287
+ }
288
+ }
289
+ }
290
+ }
291
+
292
+ // src/parser.ts
293
+ function isReactNode(typeName) {
294
+ return [
295
+ "ReactNode",
296
+ "ReactElement",
297
+ "JSX.Element",
298
+ "React.ReactNode",
299
+ "React.ReactElement"
300
+ ].includes(typeName);
301
+ }
302
+ function resolvePropKind(type) {
303
+ if (type.isString() || type.isStringLiteral()) return "string";
304
+ if (type.isNumber() || type.isNumberLiteral()) return "number";
305
+ if (type.isBoolean() || type.isBooleanLiteral()) return "boolean";
306
+ if (type.isNull()) return "null";
307
+ if (type.isUndefined()) return "undefined";
308
+ if (type.isNever()) return "never";
309
+ if (type.isAny()) return "any";
310
+ if (type.isUnknown()) return "unknown";
311
+ if (type.isArray()) return "array";
312
+ if (type.isTuple()) return "array";
313
+ const typeText = type.getText();
314
+ if (isReactNode(typeText)) return "node";
315
+ if (type.isUnion()) return "union";
316
+ if (typeText.includes("=>") || typeText.startsWith("(")) return "function";
317
+ if (type.isObject()) return "object";
318
+ return "other";
319
+ }
320
+ function expandUnionValues(type) {
321
+ if (!type.isUnion()) return void 0;
322
+ const values = [];
323
+ for (const member of type.getUnionTypes()) {
324
+ if (member.isStringLiteral()) {
325
+ values.push(member.getLiteralValue());
326
+ } else if (member.isNumberLiteral()) {
327
+ values.push(String(member.getLiteralValue()));
328
+ } else if (member.isBooleanLiteral()) {
329
+ values.push(String(member.getLiteralValue()));
330
+ }
331
+ }
332
+ return values.length > 0 ? values : void 0;
333
+ }
334
+ function buildPropDescriptor(type, required, defaultValue) {
335
+ const kind = resolvePropKind(type);
336
+ const desc = {
337
+ type: kind,
338
+ required,
339
+ rawType: type.getText().replace(/import\("[^"]*"\)\./g, "")
340
+ };
341
+ if (kind === "union") {
342
+ const expanded = expandUnionValues(type);
343
+ if (expanded) desc.values = expanded;
344
+ }
345
+ if (defaultValue !== void 0) {
346
+ desc.default = defaultValue;
347
+ desc.required = false;
348
+ }
349
+ return desc;
350
+ }
351
+ function extractPropsFromType(typeName, sourceFile, defaultValues = {}) {
352
+ const props = {};
353
+ const iface = sourceFile.getInterface(typeName);
354
+ if (iface) {
355
+ for (const prop of iface.getProperties()) {
356
+ const name = prop.getName();
357
+ if (name.startsWith("[")) continue;
358
+ const type = prop.getType();
359
+ const required = !prop.hasQuestionToken();
360
+ props[name] = buildPropDescriptor(type, required, defaultValues[name]);
361
+ }
362
+ return props;
363
+ }
364
+ const typeAlias = sourceFile.getTypeAlias(typeName);
365
+ if (typeAlias) {
366
+ const aliasType = typeAlias.getType();
367
+ if (aliasType.isObject()) {
368
+ for (const prop of aliasType.getProperties()) {
369
+ const name = prop.getName();
370
+ if (name.startsWith("[")) continue;
371
+ const decls = prop.getDeclarations();
372
+ const required = decls.length === 0 || !prop.getDeclarations().some((d) => tsMorph.Node.isPropertySignature(d) && d.hasQuestionToken());
373
+ const valType = prop.getTypeAtLocation(sourceFile);
374
+ props[name] = buildPropDescriptor(valType, required, defaultValues[name]);
375
+ }
376
+ }
377
+ return props;
378
+ }
379
+ return props;
380
+ }
381
+ function inferPropsTypeName(params) {
382
+ if (params.length === 0) return void 0;
383
+ const firstParam = params[0];
384
+ if (!firstParam) return void 0;
385
+ const typeNode = firstParam.getTypeNode?.();
386
+ if (!typeNode) return void 0;
387
+ return typeNode.getText().trim();
388
+ }
389
+ function extractDefaultsFromDestructuring(params) {
390
+ const defaults = {};
391
+ if (params.length === 0) return defaults;
392
+ const firstParam = params[0];
393
+ if (!firstParam) return defaults;
394
+ const nameNode = firstParam.getNameNode();
395
+ if (!tsMorph.Node.isObjectBindingPattern(nameNode)) return defaults;
396
+ for (const element of nameNode.getElements()) {
397
+ const initializer = element.getInitializer();
398
+ if (initializer) {
399
+ const propName = element.getPropertyNameNode()?.getText() ?? element.getName();
400
+ defaults[propName] = initializer.getText();
401
+ }
402
+ }
403
+ return defaults;
404
+ }
405
+ function collectJsxCompositions(node) {
406
+ const names = /* @__PURE__ */ new Set();
407
+ function visit(n) {
408
+ if (tsMorph.Node.isJsxOpeningElement(n) || tsMorph.Node.isJsxSelfClosingElement(n)) {
409
+ const tagNameNode = n.getTagNameNode();
410
+ const tagName = tagNameNode.getText();
411
+ if (/^[A-Z]/.test(tagName)) {
412
+ const base = tagName.split(".")[0] ?? tagName;
413
+ if (base && /^[A-Z]/.test(base) && !["React", "Fragment"].includes(base)) {
414
+ names.add(base);
415
+ }
416
+ }
417
+ }
418
+ n.forEachChild(visit);
419
+ }
420
+ visit(node);
421
+ return Array.from(names);
422
+ }
423
+ function detectWrappers(node) {
424
+ let memoized = false;
425
+ let forwardedRef = false;
426
+ const hocWrappers = [];
427
+ function visitCall(n) {
428
+ if (!tsMorph.Node.isCallExpression(n)) return;
429
+ const expr = n.getExpression();
430
+ const name = expr.getText();
431
+ if (name === "React.memo" || name === "memo") {
432
+ memoized = true;
433
+ const args = n.getArguments();
434
+ if (args[0]) visitCall(args[0]);
435
+ } else if (name === "React.forwardRef" || name === "forwardRef") {
436
+ forwardedRef = true;
437
+ const args = n.getArguments();
438
+ if (args[0]) visitCall(args[0]);
439
+ } else {
440
+ const args = n.getArguments();
441
+ if (args.length > 0) {
442
+ const firstArg = args[0];
443
+ if (firstArg && (tsMorph.Node.isIdentifier(firstArg) || tsMorph.Node.isCallExpression(firstArg))) {
444
+ const calleeName = name.split(".").pop() ?? name;
445
+ if (/^[a-z]/.test(calleeName)) {
446
+ hocWrappers.push(calleeName);
447
+ }
448
+ if (tsMorph.Node.isCallExpression(firstArg)) {
449
+ visitCall(firstArg);
450
+ }
451
+ }
452
+ }
453
+ }
454
+ }
455
+ visitCall(node);
456
+ return { memoized, forwardedRef, hocWrappers };
457
+ }
458
+ function extractNameFromWrappedCall(node) {
459
+ if (!tsMorph.Node.isCallExpression(node)) return void 0;
460
+ const args = node.getArguments();
461
+ if (args.length === 0) return void 0;
462
+ const firstArg = args[0];
463
+ if (!firstArg) return void 0;
464
+ if (tsMorph.Node.isFunctionExpression(firstArg)) {
465
+ return firstArg.getName() ?? void 0;
466
+ }
467
+ if (tsMorph.Node.isIdentifier(firstArg)) {
468
+ return firstArg.getText();
469
+ }
470
+ if (tsMorph.Node.isCallExpression(firstArg)) {
471
+ return extractNameFromWrappedCall(firstArg);
472
+ }
473
+ return void 0;
474
+ }
475
+ function nodeReturnsJsx(node) {
476
+ let found = false;
477
+ function visit(n) {
478
+ if (found) return;
479
+ if (tsMorph.Node.isJsxElement(n) || tsMorph.Node.isJsxFragment(n) || tsMorph.Node.isJsxSelfClosingElement(n)) {
480
+ found = true;
481
+ return;
482
+ }
483
+ n.forEachChild(visit);
484
+ }
485
+ visit(node);
486
+ return found;
487
+ }
488
+ function processSourceFile(sourceFile, rootDir, project) {
489
+ const results = [];
490
+ const filePath = path.relative(rootDir, sourceFile.getFilePath());
491
+ let defaultExportName;
492
+ const defaultExportWrappers = /* @__PURE__ */ new Map();
493
+ sourceFile.forEachChild((node) => {
494
+ if (tsMorph.Node.isExportAssignment(node)) {
495
+ const expr = node.getExpression();
496
+ if (tsMorph.Node.isIdentifier(expr)) {
497
+ defaultExportName = expr.getText();
498
+ } else if (tsMorph.Node.isCallExpression(expr)) {
499
+ const innerName = extractNameFromWrappedCall(expr);
500
+ if (innerName) {
501
+ defaultExportName = innerName;
502
+ defaultExportWrappers.set(innerName, detectWrappers(expr));
503
+ }
504
+ }
505
+ }
506
+ });
507
+ const namedExports = /* @__PURE__ */ new Set();
508
+ for (const exportDecl of sourceFile.getExportSymbols()) {
509
+ namedExports.add(exportDecl.getName());
510
+ }
511
+ for (const fn of sourceFile.getFunctions()) {
512
+ const name = fn.getName();
513
+ if (!name) continue;
514
+ if (!/^[A-Z]/.test(name)) continue;
515
+ if (!nodeReturnsJsx(fn)) continue;
516
+ const params = fn.getParameters();
517
+ const propsTypeName = inferPropsTypeName(params);
518
+ const defaults = extractDefaultsFromDestructuring(params);
519
+ const props = propsTypeName ? extractPropsFromType(propsTypeName, sourceFile, defaults) : {};
520
+ const composes = collectJsxCompositions(fn);
521
+ const start = fn.getStartLineNumber();
522
+ const end = fn.getEndLineNumber();
523
+ let exportType = "none";
524
+ if (fn.isDefaultExport() || defaultExportName === name) exportType = "default";
525
+ else if (fn.isExported() || namedExports.has(name)) exportType = "named";
526
+ const fnWrappers = defaultExportWrappers.get(name) ?? {
527
+ memoized: false,
528
+ forwardedRef: false,
529
+ hocWrappers: []
530
+ };
531
+ results.push({
532
+ name,
533
+ descriptor: {
534
+ filePath,
535
+ exportType,
536
+ displayName: name,
537
+ props,
538
+ composes,
539
+ composedBy: [],
540
+ forwardedRef: fnWrappers.forwardedRef,
541
+ hocWrappers: fnWrappers.hocWrappers,
542
+ memoized: fnWrappers.memoized,
543
+ loc: { start, end },
544
+ complexityClass: analyzeComplexity(fn),
545
+ detectedHooks: detectHooks(fn),
546
+ requiredContexts: detectRequiredContexts(fn, sourceFile, project),
547
+ sideEffects: detectSideEffects(fn)
548
+ }
549
+ });
550
+ }
551
+ for (const varStmt of sourceFile.getVariableStatements()) {
552
+ const isExported = varStmt.isExported();
553
+ for (const varDecl of varStmt.getDeclarations()) {
554
+ const varName = varDecl.getName();
555
+ if (!/^[A-Z]/.test(varName)) continue;
556
+ const initializer = varDecl.getInitializer();
557
+ if (!initializer) continue;
558
+ const wrappers = detectWrappers(initializer);
559
+ let innerName;
560
+ let bodyNode = initializer;
561
+ if (tsMorph.Node.isCallExpression(initializer)) {
562
+ innerName = extractNameFromWrappedCall(initializer);
563
+ const args = initializer.getArguments();
564
+ const firstArg = args[0];
565
+ if (firstArg) {
566
+ if (tsMorph.Node.isArrowFunction(firstArg) || tsMorph.Node.isFunctionExpression(firstArg)) {
567
+ bodyNode = firstArg;
568
+ } else if (tsMorph.Node.isCallExpression(firstArg)) {
569
+ const innerArgs = firstArg.getArguments();
570
+ const innerFirst = innerArgs[0];
571
+ if (innerFirst && (tsMorph.Node.isArrowFunction(innerFirst) || tsMorph.Node.isFunctionExpression(innerFirst))) {
572
+ bodyNode = innerFirst;
573
+ }
574
+ }
575
+ }
576
+ }
577
+ if (!nodeReturnsJsx(bodyNode)) continue;
578
+ const componentName = innerName ?? varName;
579
+ let params = [];
580
+ if (tsMorph.Node.isArrowFunction(bodyNode) || tsMorph.Node.isFunctionExpression(bodyNode)) {
581
+ params = bodyNode.getParameters();
582
+ }
583
+ const propsTypeName = inferPropsTypeName(params);
584
+ const defaults = extractDefaultsFromDestructuring(params);
585
+ const props = propsTypeName ? extractPropsFromType(propsTypeName, sourceFile, defaults) : {};
586
+ const composes = collectJsxCompositions(bodyNode);
587
+ const startLine = varDecl.getStartLineNumber();
588
+ const endLine = varDecl.getEndLineNumber();
589
+ let exportType = "none";
590
+ if (defaultExportName === varName || defaultExportName === componentName) {
591
+ exportType = "default";
592
+ } else if (isExported || namedExports.has(varName)) {
593
+ exportType = "named";
594
+ }
595
+ results.push({
596
+ name: componentName === varName ? componentName : varName,
597
+ descriptor: {
598
+ filePath,
599
+ exportType,
600
+ displayName: componentName,
601
+ props,
602
+ composes,
603
+ composedBy: [],
604
+ forwardedRef: wrappers.forwardedRef,
605
+ hocWrappers: wrappers.hocWrappers,
606
+ memoized: wrappers.memoized,
607
+ loc: { start: startLine, end: endLine },
608
+ complexityClass: analyzeComplexity(bodyNode),
609
+ detectedHooks: detectHooks(bodyNode),
610
+ requiredContexts: detectRequiredContexts(bodyNode, sourceFile, project),
611
+ sideEffects: detectSideEffects(bodyNode)
612
+ }
613
+ });
614
+ }
615
+ }
616
+ for (const cls of sourceFile.getClasses()) {
617
+ const name = cls.getName();
618
+ if (!name) continue;
619
+ if (!/^[A-Z]/.test(name)) continue;
620
+ const baseClass = cls.getBaseClass()?.getName();
621
+ if (!baseClass && !cls.getExtends()) continue;
622
+ const extendsText = cls.getExtends()?.getText() ?? "";
623
+ if (!extendsText.includes("Component") && !extendsText.includes("PureComponent")) {
624
+ continue;
625
+ }
626
+ const renderMethod = cls.getMethod("render");
627
+ if (!renderMethod || !nodeReturnsJsx(renderMethod)) continue;
628
+ const extendsNode = cls.getExtends();
629
+ let propsTypeName;
630
+ if (extendsNode) {
631
+ const typeArgs = extendsNode.getTypeArguments();
632
+ if (typeArgs[0]) {
633
+ propsTypeName = typeArgs[0].getText().trim();
634
+ }
635
+ }
636
+ const props = propsTypeName ? extractPropsFromType(propsTypeName, sourceFile) : {};
637
+ const composes = collectJsxCompositions(renderMethod);
638
+ const start = cls.getStartLineNumber();
639
+ const end = cls.getEndLineNumber();
640
+ let exportType = "none";
641
+ if (cls.isDefaultExport() || defaultExportName === name) exportType = "default";
642
+ else if (cls.isExported() || namedExports.has(name)) exportType = "named";
643
+ results.push({
644
+ name,
645
+ descriptor: {
646
+ filePath,
647
+ exportType,
648
+ displayName: name,
649
+ props,
650
+ composes,
651
+ composedBy: [],
652
+ forwardedRef: false,
653
+ hocWrappers: [],
654
+ memoized: false,
655
+ loc: { start, end },
656
+ complexityClass: "complex",
657
+ detectedHooks: [],
658
+ requiredContexts: [],
659
+ sideEffects: detectSideEffects(cls)
660
+ }
661
+ });
662
+ }
663
+ return results;
664
+ }
665
+ function generateManifest(config) {
666
+ const {
667
+ rootDir,
668
+ include = ["src/**/*.tsx", "src/**/*.ts"],
669
+ exclude = ["**/node_modules/**", "**/*.test.*", "**/*.spec.*", "**/dist/**", "**/*.d.ts"],
670
+ tsConfigFilePath = path.join(rootDir, "tsconfig.json")
671
+ } = config;
672
+ const project = new tsMorph.Project({
673
+ tsConfigFilePath,
674
+ skipAddingFilesFromTsConfig: true
675
+ });
676
+ const includePatterns = include.map((g) => path.join(rootDir, g));
677
+ project.addSourceFilesFromTsConfig(tsConfigFilePath);
678
+ for (const pattern of includePatterns) {
679
+ project.addSourceFilesAtPaths(pattern);
680
+ }
681
+ for (const sf of project.getSourceFiles()) {
682
+ const fp = sf.getFilePath();
683
+ const shouldExclude = exclude.some((ex) => {
684
+ const pattern = ex.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\./g, "\\.");
685
+ return new RegExp(pattern).test(fp);
686
+ });
687
+ if (shouldExclude) {
688
+ project.removeSourceFile(sf);
689
+ }
690
+ }
691
+ for (const sf of project.getSourceFiles()) {
692
+ if (!sf.getFilePath().startsWith(rootDir)) {
693
+ project.removeSourceFile(sf);
694
+ }
695
+ }
696
+ const allComponents = {};
697
+ for (const sf of project.getSourceFiles()) {
698
+ const rawComponents = processSourceFile(sf, rootDir, project);
699
+ for (const { name, descriptor } of rawComponents) {
700
+ if (allComponents[name] && descriptor.exportType === "none") continue;
701
+ allComponents[name] = descriptor;
702
+ }
703
+ }
704
+ for (const [name, desc] of Object.entries(allComponents)) {
705
+ for (const child of desc.composes) {
706
+ if (allComponents[child]) {
707
+ const childDesc = allComponents[child];
708
+ if (childDesc && !childDesc.composedBy.includes(name)) {
709
+ childDesc.composedBy.push(name);
710
+ }
711
+ }
712
+ }
713
+ }
714
+ propagateComplexity(allComponents);
715
+ const tree = {};
716
+ for (const [name, desc] of Object.entries(allComponents)) {
717
+ const children = desc.composes.filter((c) => c in allComponents);
718
+ const parents = desc.composedBy.filter((p) => p in allComponents);
719
+ tree[name] = { children, parents };
720
+ }
721
+ return {
722
+ version: "0.1",
723
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
724
+ components: allComponents,
725
+ tree
726
+ };
727
+ }
728
+
729
+ exports.generateManifest = generateManifest;
730
+ //# sourceMappingURL=index.cjs.map
731
+ //# sourceMappingURL=index.cjs.map