@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.
- package/README.md +0 -3
- package/dist/{ai-client-I6MDWNYA.js → ai-client-LSLQGOMM.js} +1 -2
- package/dist/bin.js +4745 -3817
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-TXFCEDOC.js → chunk-2WXKALIG.js} +2 -2
- package/dist/{chunk-I34BC3CU.js → chunk-32LIWN2P.js} +1006 -3
- package/dist/chunk-32LIWN2P.js.map +1 -0
- package/dist/chunk-5JF26E55.js +1255 -0
- package/dist/chunk-5JF26E55.js.map +1 -0
- package/dist/{chunk-APTQIBS5.js → chunk-6SQPP47U.js} +153 -1342
- package/dist/chunk-6SQPP47U.js.map +1 -0
- package/dist/chunk-7DZC4YEV.js +294 -0
- package/dist/chunk-7DZC4YEV.js.map +1 -0
- package/dist/{chunk-PJT5IZ37.js → chunk-BJE3425I.js} +19 -52
- package/dist/{chunk-PJT5IZ37.js.map → chunk-BJE3425I.js.map} +1 -1
- package/dist/{chunk-55KERLWL.js → chunk-HQ6A6DTV.js} +1587 -1073
- package/dist/chunk-HQ6A6DTV.js.map +1 -0
- package/dist/chunk-MHIBEEW4.js +511 -0
- package/dist/chunk-MHIBEEW4.js.map +1 -0
- package/dist/{chunk-5A6X2Y73.js → chunk-ONUP6Z4W.js} +25 -13
- package/dist/chunk-ONUP6Z4W.js.map +1 -0
- package/dist/chunk-QCN35LJU.js +630 -0
- package/dist/chunk-QCN35LJU.js.map +1 -0
- package/dist/chunk-T47OLCSF.js +36 -0
- package/dist/chunk-T47OLCSF.js.map +1 -0
- package/dist/codebase-scanner-MQHUZC2G.js +21 -0
- package/dist/converter-7XM3Y6NJ.js +33 -0
- package/dist/converter-7XM3Y6NJ.js.map +1 -0
- package/dist/core/index.js +43 -2
- package/dist/create-IH4R45GE.js +806 -0
- package/dist/create-IH4R45GE.js.map +1 -0
- package/dist/{generate-RYWIPDN2.js → generate-PVOLUAAC.js} +4 -6
- package/dist/{generate-RYWIPDN2.js.map → generate-PVOLUAAC.js.map} +1 -1
- package/dist/govern-scan-OYFZYOQW.js +413 -0
- package/dist/govern-scan-OYFZYOQW.js.map +1 -0
- package/dist/index.d.ts +4 -23
- package/dist/index.js +15 -14
- package/dist/index.js.map +1 -1
- package/dist/{init-WRUSW7R5.js → init-SSGUSP7Z.js} +131 -129
- package/dist/init-SSGUSP7Z.js.map +1 -0
- package/dist/{init-cloud-REQ3XLHO.js → init-cloud-3DNKPWFB.js} +30 -5
- package/dist/{init-cloud-REQ3XLHO.js.map → init-cloud-3DNKPWFB.js.map} +1 -1
- package/dist/mcp-bin.js +5 -37
- package/dist/mcp-bin.js.map +1 -1
- package/dist/node-37AUE74M.js +65 -0
- package/dist/push-contracts-WY32TFP6.js +84 -0
- package/dist/push-contracts-WY32TFP6.js.map +1 -0
- package/dist/scan-PKSYSTRR.js +15 -0
- package/dist/{scan-generate-TFZVL3BT.js → scan-generate-VY27PIOX.js} +340 -52
- package/dist/scan-generate-VY27PIOX.js.map +1 -0
- package/dist/scanner-4KZNOXAK.js +12 -0
- package/dist/{service-HKJ6B7P7.js → service-QJGWUIVL.js} +41 -30
- package/dist/{snapshot-C5DYIGIV.js → snapshot-WIJMEIFT.js} +2 -3
- package/dist/{snapshot-C5DYIGIV.js.map → snapshot-WIJMEIFT.js.map} +1 -1
- package/dist/{static-viewer-DUVC4UIM.js → static-viewer-7QIBQZRC.js} +3 -4
- package/dist/static-viewer-7QIBQZRC.js.map +1 -0
- package/dist/{test-JW7JIDFG.js → test-64Z5BKBA.js} +4 -7
- package/dist/{test-JW7JIDFG.js.map → test-64Z5BKBA.js.map} +1 -1
- package/dist/token-normalizer-TEPOVBPV.js +312 -0
- package/dist/token-normalizer-TEPOVBPV.js.map +1 -0
- package/dist/token-parser-32KOIOFN.js +22 -0
- package/dist/token-parser-32KOIOFN.js.map +1 -0
- package/dist/{tokens-KE73G5JC.js → tokens-NZWFQIAB.js} +10 -9
- package/dist/{tokens-KE73G5JC.js.map → tokens-NZWFQIAB.js.map} +1 -1
- package/dist/tokens-generate-5JQSJ27E.js +85 -0
- package/dist/tokens-generate-5JQSJ27E.js.map +1 -0
- package/dist/tokens-push-HY3KO36V.js +148 -0
- package/dist/tokens-push-HY3KO36V.js.map +1 -0
- package/package.json +8 -6
- package/src/bin.ts +300 -48
- package/src/commands/__fixtures__/shadcn-label-wrapper/package.json +7 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.contract.json +42 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.tsx +11 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.contract.json +20 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.tsx +14 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/tsconfig.app.json +23 -0
- package/src/commands/__tests__/build-freshness.test.ts +231 -0
- package/src/commands/__tests__/create.test.ts +71 -0
- package/src/commands/__tests__/drift-sync.test.ts +1 -1
- package/src/commands/__tests__/govern.test.ts +258 -0
- package/src/commands/__tests__/init.test.ts +113 -0
- package/src/commands/__tests__/scan-generate.test.ts +189 -70
- package/src/commands/__tests__/verify.test.ts +91 -0
- package/src/commands/build.ts +54 -1
- package/src/commands/context.ts +1 -1
- package/src/commands/create.ts +536 -0
- package/src/commands/discover.ts +151 -0
- package/src/commands/doctor.ts +3 -2
- package/src/commands/enhance.ts +3 -1
- package/src/commands/govern-scan.ts +565 -0
- package/src/commands/govern.ts +67 -4
- package/src/commands/init-cloud.ts +32 -4
- package/src/commands/init.ts +152 -28
- package/src/commands/inspect.ts +290 -0
- package/src/commands/migrate-contract.ts +85 -0
- package/src/commands/push-contracts.ts +112 -0
- package/src/commands/scan-generate.ts +439 -51
- package/src/commands/scan.ts +14 -0
- package/src/commands/setup.ts +27 -50
- package/src/commands/sync.ts +2 -2
- package/src/commands/tokens-generate.ts +113 -0
- package/src/commands/tokens-push.ts +199 -0
- package/src/commands/verify.ts +195 -1
- package/src/core/__fixtures__/shadcn-input/input.tsx +7 -0
- package/src/core/__fixtures__/shadcn-input/tsconfig.json +14 -0
- package/src/core/__fixtures__/shadcn-label/label.tsx +11 -0
- package/src/core/__fixtures__/shadcn-label/primitive.tsx +14 -0
- package/src/core/__fixtures__/shadcn-label/tsconfig.json +14 -0
- package/src/core/__fixtures__/shadcn-radix-label/label.tsx +11 -0
- package/src/core/__fixtures__/shadcn-radix-label/node_modules/radix-ui/index.d.ts +12 -0
- package/src/core/__fixtures__/shadcn-radix-label/tsconfig.json +14 -0
- package/src/core/__tests__/contract-parity.test.ts +316 -0
- package/src/core/__tests__/token-resolver.test.ts +1 -1
- package/src/core/component-extractor.test.ts +40 -1
- package/src/core/config.ts +2 -1
- package/src/core/discovery.ts +13 -2
- package/src/core/drift-verifier.ts +123 -0
- package/src/core/extractor-adapter.ts +80 -0
- package/src/index.ts +3 -3
- package/src/mcp/__tests__/projectFields.test.ts +1 -1
- package/src/mcp/utils.ts +1 -50
- package/src/migrate/converter.ts +3 -3
- package/src/migrate/fragment-to-contract.ts +253 -0
- package/src/migrate/report.ts +1 -1
- package/src/scripts/token-benchmark.ts +121 -0
- package/src/service/__tests__/props-extractor.test.ts +94 -0
- package/src/service/__tests__/token-normalizer.test.ts +690 -0
- package/src/service/ast-utils.ts +4 -23
- package/src/service/babel-config.ts +23 -0
- package/src/service/enhance/converter.ts +61 -0
- package/src/service/enhance/props-extractor.ts +25 -8
- package/src/service/enhance/scanner.ts +5 -24
- package/src/service/index.ts +8 -0
- package/src/service/snippet-validation.ts +9 -3
- package/src/service/tailwind-v4-parser.ts +314 -0
- package/src/service/token-normalizer.ts +510 -0
- package/src/service/token-parser.ts +56 -0
- package/src/setup.ts +10 -39
- package/src/shared/index.ts +1 -0
- package/src/shared/project-fields.ts +46 -0
- package/src/theme/__tests__/component-contrast.test.ts +2 -2
- package/src/theme/__tests__/serializer.test.ts +1 -1
- package/src/theme/generator.ts +16 -1
- package/src/theme/schema.ts +8 -0
- package/src/theme/serializer.ts +13 -9
- package/src/theme/types.ts +8 -0
- package/src/validators.ts +1 -2
- package/src/viewer/__tests__/viewer-integration.test.ts +8 -8
- package/src/viewer/style-utils.ts +27 -412
- package/src/viewer/vite-plugin.ts +2 -2
- package/dist/chunk-55KERLWL.js.map +0 -1
- package/dist/chunk-5A6X2Y73.js.map +0 -1
- package/dist/chunk-APTQIBS5.js.map +0 -1
- package/dist/chunk-EYXVAMEX.js +0 -626
- package/dist/chunk-EYXVAMEX.js.map +0 -1
- package/dist/chunk-I34BC3CU.js.map +0 -1
- package/dist/chunk-LOYS64QS.js +0 -2453
- package/dist/chunk-LOYS64QS.js.map +0 -1
- package/dist/chunk-Z7EY4VHE.js +0 -50
- package/dist/chunk-ZKTFKHWN.js +0 -324
- package/dist/chunk-ZKTFKHWN.js.map +0 -1
- package/dist/discovery-VDANZAJ2.js +0 -28
- package/dist/init-WRUSW7R5.js.map +0 -1
- package/dist/sass.node-4XJK6YBF.js +0 -130708
- package/dist/sass.node-4XJK6YBF.js.map +0 -1
- package/dist/scan-YJHQIRKG.js +0 -14
- package/dist/scan-generate-TFZVL3BT.js.map +0 -1
- package/dist/viewer-2TZS3NDL.js +0 -2730
- package/dist/viewer-2TZS3NDL.js.map +0 -1
- package/src/build.ts +0 -612
- package/src/commands/dev.ts +0 -107
- package/src/core/auto-props.ts +0 -464
- package/src/core/component-extractor.ts +0 -1030
- package/src/core/token-resolver.ts +0 -155
- /package/dist/{ai-client-I6MDWNYA.js.map → ai-client-LSLQGOMM.js.map} +0 -0
- /package/dist/{chunk-TXFCEDOC.js.map → chunk-2WXKALIG.js.map} +0 -0
- /package/dist/{chunk-Z7EY4VHE.js.map → codebase-scanner-MQHUZC2G.js.map} +0 -0
- /package/dist/{discovery-VDANZAJ2.js.map → node-37AUE74M.js.map} +0 -0
- /package/dist/{scan-YJHQIRKG.js.map → scan-PKSYSTRR.js.map} +0 -0
- /package/dist/{service-HKJ6B7P7.js.map → scanner-4KZNOXAK.js.map} +0 -0
- /package/dist/{static-viewer-DUVC4UIM.js.map → service-QJGWUIVL.js.map} +0 -0
|
@@ -2,7 +2,15 @@ import { createRequire as __banner_createRequire } from 'module'; const require
|
|
|
2
2
|
import {
|
|
3
3
|
BRAND,
|
|
4
4
|
DEFAULTS
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-32LIWN2P.js";
|
|
6
|
+
import {
|
|
7
|
+
hexToRgb,
|
|
8
|
+
parseRgb,
|
|
9
|
+
parseTokenFiles
|
|
10
|
+
} from "./chunk-MHIBEEW4.js";
|
|
11
|
+
import {
|
|
12
|
+
BABEL_PARSER_OPTIONS
|
|
13
|
+
} from "./chunk-7DZC4YEV.js";
|
|
6
14
|
|
|
7
15
|
// src/service/browser-pool.ts
|
|
8
16
|
var BrowserPool = class {
|
|
@@ -72,8 +80,8 @@ var BrowserPool = class {
|
|
|
72
80
|
}
|
|
73
81
|
await this.clearContext(context);
|
|
74
82
|
if (this.waitingQueue.length > 0) {
|
|
75
|
-
const
|
|
76
|
-
|
|
83
|
+
const resolve3 = this.waitingQueue.shift();
|
|
84
|
+
resolve3(context);
|
|
77
85
|
return;
|
|
78
86
|
}
|
|
79
87
|
this.available.push(context);
|
|
@@ -100,7 +108,7 @@ var BrowserPool = class {
|
|
|
100
108
|
clearTimeout(this.idleTimeout);
|
|
101
109
|
this.idleTimeout = null;
|
|
102
110
|
}
|
|
103
|
-
for (const
|
|
111
|
+
for (const resolve3 of this.waitingQueue) {
|
|
104
112
|
}
|
|
105
113
|
this.waitingQueue = [];
|
|
106
114
|
for (const context of this.contexts) {
|
|
@@ -187,9 +195,9 @@ var BrowserPool = class {
|
|
|
187
195
|
* Wait for an available context.
|
|
188
196
|
*/
|
|
189
197
|
waitForAvailable() {
|
|
190
|
-
return new Promise((
|
|
198
|
+
return new Promise((resolve3, reject) => {
|
|
191
199
|
const timeout = setTimeout(() => {
|
|
192
|
-
const index = this.waitingQueue.indexOf(
|
|
200
|
+
const index = this.waitingQueue.indexOf(resolve3);
|
|
193
201
|
if (index > -1) {
|
|
194
202
|
this.waitingQueue.splice(index, 1);
|
|
195
203
|
}
|
|
@@ -202,7 +210,7 @@ var BrowserPool = class {
|
|
|
202
210
|
}, 3e4);
|
|
203
211
|
const wrappedResolve = (ctx) => {
|
|
204
212
|
clearTimeout(timeout);
|
|
205
|
-
|
|
213
|
+
resolve3(ctx);
|
|
206
214
|
};
|
|
207
215
|
this.waitingQueue.push(wrappedResolve);
|
|
208
216
|
});
|
|
@@ -285,16 +293,16 @@ var Timer = class {
|
|
|
285
293
|
}
|
|
286
294
|
};
|
|
287
295
|
function createDeferred() {
|
|
288
|
-
let
|
|
296
|
+
let resolve3;
|
|
289
297
|
let reject;
|
|
290
298
|
const promise = new Promise((res, rej) => {
|
|
291
|
-
|
|
299
|
+
resolve3 = res;
|
|
292
300
|
reject = rej;
|
|
293
301
|
});
|
|
294
|
-
return { promise, resolve:
|
|
302
|
+
return { promise, resolve: resolve3, reject };
|
|
295
303
|
}
|
|
296
304
|
function sleep(ms) {
|
|
297
|
-
return new Promise((
|
|
305
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
298
306
|
}
|
|
299
307
|
function bufferToBase64Url(buffer, mimeType = "image/png") {
|
|
300
308
|
return `data:${mimeType};base64,${buffer.toString("base64")}`;
|
|
@@ -450,7 +458,7 @@ var CaptureEngine = class {
|
|
|
450
458
|
await page.evaluate(async (timeoutMs) => {
|
|
451
459
|
await Promise.race([
|
|
452
460
|
document.fonts.ready,
|
|
453
|
-
new Promise((
|
|
461
|
+
new Promise((resolve3) => setTimeout(resolve3, timeoutMs))
|
|
454
462
|
]);
|
|
455
463
|
}, timeout);
|
|
456
464
|
} catch {
|
|
@@ -2548,289 +2556,6 @@ function getScripts() {
|
|
|
2548
2556
|
`;
|
|
2549
2557
|
}
|
|
2550
2558
|
|
|
2551
|
-
// src/service/token-parser.ts
|
|
2552
|
-
import { readFile as readFile2 } from "fs/promises";
|
|
2553
|
-
import { relative } from "path";
|
|
2554
|
-
import fastGlob from "fast-glob";
|
|
2555
|
-
var TOKEN_DECLARATION_PATTERN = /--([a-zA-Z0-9_-]+)\s*:\s*([^;]+);/g;
|
|
2556
|
-
var CATEGORY_PATTERNS = [
|
|
2557
|
-
{ pattern: /color|bg|background|border-color|fill|stroke/i, category: "color" },
|
|
2558
|
-
{ pattern: /spacing|margin|padding|gap|space|inset/i, category: "spacing" },
|
|
2559
|
-
{ pattern: /font|text|line-height|letter-spacing|typography/i, category: "typography" },
|
|
2560
|
-
{ pattern: /radius|rounded|corner/i, category: "radius" },
|
|
2561
|
-
{ pattern: /shadow|elevation/i, category: "shadow" },
|
|
2562
|
-
{ pattern: /size|width|height|min|max/i, category: "sizing" },
|
|
2563
|
-
{ pattern: /border(?!-color)|stroke-width|outline/i, category: "border" },
|
|
2564
|
-
{ pattern: /animation|transition|duration|timing|delay/i, category: "animation" },
|
|
2565
|
-
{ pattern: /z-index|layer|stack/i, category: "z-index" }
|
|
2566
|
-
];
|
|
2567
|
-
async function parseTokenFile(filePath, themeSelectors = { ":root": "default" }, projectRoot) {
|
|
2568
|
-
const startTime = performance.now();
|
|
2569
|
-
const tokens = [];
|
|
2570
|
-
const errors = [];
|
|
2571
|
-
const warnings = [];
|
|
2572
|
-
try {
|
|
2573
|
-
const content = await readFile2(filePath, "utf-8");
|
|
2574
|
-
const relativePath = projectRoot ? relative(projectRoot, filePath) : filePath;
|
|
2575
|
-
const tokensByName = /* @__PURE__ */ new Map();
|
|
2576
|
-
let lineNumber = 1;
|
|
2577
|
-
const lines = content.split("\n");
|
|
2578
|
-
let currentSelector = ":root";
|
|
2579
|
-
let braceDepth = 0;
|
|
2580
|
-
const selectorStack = [];
|
|
2581
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2582
|
-
const line = lines[i];
|
|
2583
|
-
lineNumber = i + 1;
|
|
2584
|
-
const openBraces = (line.match(/\{/g) || []).length;
|
|
2585
|
-
const closeBraces = (line.match(/\}/g) || []).length;
|
|
2586
|
-
if (openBraces > closeBraces) {
|
|
2587
|
-
const selectorMatch = line.match(/^\s*([^{]+)\s*\{/);
|
|
2588
|
-
if (selectorMatch) {
|
|
2589
|
-
selectorStack.push(selectorMatch[1].trim());
|
|
2590
|
-
currentSelector = selectorStack[selectorStack.length - 1];
|
|
2591
|
-
}
|
|
2592
|
-
braceDepth += openBraces - closeBraces;
|
|
2593
|
-
} else if (closeBraces > openBraces) {
|
|
2594
|
-
braceDepth -= closeBraces - openBraces;
|
|
2595
|
-
if (braceDepth >= 0 && selectorStack.length > 0) {
|
|
2596
|
-
selectorStack.pop();
|
|
2597
|
-
currentSelector = selectorStack.length > 0 ? selectorStack[selectorStack.length - 1] : ":root";
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
const tokenMatches = [...line.matchAll(TOKEN_DECLARATION_PATTERN)];
|
|
2601
|
-
for (const match of tokenMatches) {
|
|
2602
|
-
const [, name, rawValue] = match;
|
|
2603
|
-
const fullName = `--${name}`;
|
|
2604
|
-
tokensByName.set(fullName, { rawValue: rawValue.trim(), line: lineNumber });
|
|
2605
|
-
}
|
|
2606
|
-
}
|
|
2607
|
-
for (const [name, { rawValue, line }] of tokensByName) {
|
|
2608
|
-
const selector = findSelectorForLine(content, line || 1);
|
|
2609
|
-
const theme = themeSelectors[selector] || "default";
|
|
2610
|
-
const { resolvedValue, chain, hasCircular, unresolvedRef } = resolveValue(
|
|
2611
|
-
rawValue,
|
|
2612
|
-
tokensByName
|
|
2613
|
-
);
|
|
2614
|
-
if (hasCircular) {
|
|
2615
|
-
warnings.push(
|
|
2616
|
-
`Circular reference detected for ${name} at line ${line}`
|
|
2617
|
-
);
|
|
2618
|
-
}
|
|
2619
|
-
if (unresolvedRef) {
|
|
2620
|
-
warnings.push(
|
|
2621
|
-
`Unresolved reference in ${name}: ${unresolvedRef}`
|
|
2622
|
-
);
|
|
2623
|
-
}
|
|
2624
|
-
const category = inferCategory(name);
|
|
2625
|
-
const level = inferLevel(name, rawValue, chain);
|
|
2626
|
-
const description = extractDescription(content, line || 1);
|
|
2627
|
-
tokens.push({
|
|
2628
|
-
name,
|
|
2629
|
-
rawValue,
|
|
2630
|
-
resolvedValue,
|
|
2631
|
-
category,
|
|
2632
|
-
level,
|
|
2633
|
-
referenceChain: chain,
|
|
2634
|
-
sourceFile: relativePath,
|
|
2635
|
-
lineNumber: line,
|
|
2636
|
-
theme,
|
|
2637
|
-
selector,
|
|
2638
|
-
description
|
|
2639
|
-
});
|
|
2640
|
-
}
|
|
2641
|
-
} catch (error) {
|
|
2642
|
-
errors.push({
|
|
2643
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
2644
|
-
file: filePath
|
|
2645
|
-
});
|
|
2646
|
-
}
|
|
2647
|
-
return {
|
|
2648
|
-
tokens,
|
|
2649
|
-
errors,
|
|
2650
|
-
warnings,
|
|
2651
|
-
parseTimeMs: performance.now() - startTime
|
|
2652
|
-
};
|
|
2653
|
-
}
|
|
2654
|
-
async function parseTokenFiles(config, projectRoot) {
|
|
2655
|
-
const startTime = performance.now();
|
|
2656
|
-
const allTokens = [];
|
|
2657
|
-
const allErrors = [];
|
|
2658
|
-
const allWarnings = [];
|
|
2659
|
-
const files = await fastGlob(config.include, {
|
|
2660
|
-
cwd: projectRoot,
|
|
2661
|
-
ignore: config.exclude || ["**/node_modules/**"],
|
|
2662
|
-
absolute: true
|
|
2663
|
-
});
|
|
2664
|
-
if (files.length === 0) {
|
|
2665
|
-
allWarnings.push(
|
|
2666
|
-
`No token files found matching: ${config.include.join(", ")}`
|
|
2667
|
-
);
|
|
2668
|
-
}
|
|
2669
|
-
for (const file of files) {
|
|
2670
|
-
const result = await parseTokenFile(
|
|
2671
|
-
file,
|
|
2672
|
-
config.themeSelectors,
|
|
2673
|
-
projectRoot
|
|
2674
|
-
);
|
|
2675
|
-
allTokens.push(...result.tokens);
|
|
2676
|
-
allErrors.push(...result.errors);
|
|
2677
|
-
allWarnings.push(...result.warnings);
|
|
2678
|
-
}
|
|
2679
|
-
return {
|
|
2680
|
-
tokens: allTokens,
|
|
2681
|
-
errors: allErrors,
|
|
2682
|
-
warnings: allWarnings,
|
|
2683
|
-
parseTimeMs: performance.now() - startTime
|
|
2684
|
-
};
|
|
2685
|
-
}
|
|
2686
|
-
function resolveValue(rawValue, tokensByName, visited = /* @__PURE__ */ new Set()) {
|
|
2687
|
-
const chain = [];
|
|
2688
|
-
let current = rawValue;
|
|
2689
|
-
let hasCircular = false;
|
|
2690
|
-
let unresolvedRef;
|
|
2691
|
-
const maxIterations = 20;
|
|
2692
|
-
let iterations = 0;
|
|
2693
|
-
while (iterations < maxIterations) {
|
|
2694
|
-
iterations++;
|
|
2695
|
-
const varMatch = current.match(/var\(\s*--([a-zA-Z0-9_-]+)(?:\s*,\s*([^)]+))?\s*\)/);
|
|
2696
|
-
if (!varMatch) {
|
|
2697
|
-
break;
|
|
2698
|
-
}
|
|
2699
|
-
const [, refName, fallback] = varMatch;
|
|
2700
|
-
const fullRefName = `--${refName}`;
|
|
2701
|
-
if (visited.has(fullRefName)) {
|
|
2702
|
-
hasCircular = true;
|
|
2703
|
-
break;
|
|
2704
|
-
}
|
|
2705
|
-
visited.add(fullRefName);
|
|
2706
|
-
chain.push(fullRefName);
|
|
2707
|
-
const refToken = tokensByName.get(fullRefName);
|
|
2708
|
-
if (refToken) {
|
|
2709
|
-
current = current.replace(
|
|
2710
|
-
varMatch[0],
|
|
2711
|
-
refToken.rawValue
|
|
2712
|
-
);
|
|
2713
|
-
} else if (fallback) {
|
|
2714
|
-
current = current.replace(varMatch[0], fallback.trim());
|
|
2715
|
-
} else {
|
|
2716
|
-
unresolvedRef = fullRefName;
|
|
2717
|
-
break;
|
|
2718
|
-
}
|
|
2719
|
-
}
|
|
2720
|
-
return {
|
|
2721
|
-
resolvedValue: normalizeValue(current.trim()),
|
|
2722
|
-
chain,
|
|
2723
|
-
hasCircular,
|
|
2724
|
-
unresolvedRef
|
|
2725
|
-
};
|
|
2726
|
-
}
|
|
2727
|
-
function normalizeValue(value) {
|
|
2728
|
-
value = value.replace(/#[0-9a-fA-F]+/g, (match) => match.toLowerCase());
|
|
2729
|
-
value = value.replace(/\s+/g, " ").trim();
|
|
2730
|
-
value = value.replace(
|
|
2731
|
-
/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/g,
|
|
2732
|
-
(_, r, g, b, a) => a !== void 0 ? `rgba(${r}, ${g}, ${b}, ${a})` : `rgb(${r}, ${g}, ${b})`
|
|
2733
|
-
);
|
|
2734
|
-
return value;
|
|
2735
|
-
}
|
|
2736
|
-
function inferCategory(name) {
|
|
2737
|
-
const lowerName = name.toLowerCase();
|
|
2738
|
-
for (const { pattern, category } of CATEGORY_PATTERNS) {
|
|
2739
|
-
if (pattern.test(lowerName)) {
|
|
2740
|
-
return category;
|
|
2741
|
-
}
|
|
2742
|
-
}
|
|
2743
|
-
return "other";
|
|
2744
|
-
}
|
|
2745
|
-
function inferLevel(name, rawValue, referenceChain) {
|
|
2746
|
-
const lowerName = name.toLowerCase();
|
|
2747
|
-
if (/btn|button|input|card|modal|dialog|menu|nav|header|footer|table|form/i.test(
|
|
2748
|
-
lowerName
|
|
2749
|
-
)) {
|
|
2750
|
-
return 3;
|
|
2751
|
-
}
|
|
2752
|
-
if (referenceChain.length > 0) {
|
|
2753
|
-
return 2;
|
|
2754
|
-
}
|
|
2755
|
-
if (rawValue.match(/^#[0-9a-fA-F]+$/) || rawValue.match(/^\d+(\.\d+)?(px|rem|em|%|vh|vw)?$/)) {
|
|
2756
|
-
return 1;
|
|
2757
|
-
}
|
|
2758
|
-
return 2;
|
|
2759
|
-
}
|
|
2760
|
-
function findSelectorForLine(content, targetLine) {
|
|
2761
|
-
const lines = content.split("\n");
|
|
2762
|
-
let currentSelector = ":root";
|
|
2763
|
-
let braceDepth = 0;
|
|
2764
|
-
for (let i = 0; i < Math.min(targetLine, lines.length); i++) {
|
|
2765
|
-
const line = lines[i];
|
|
2766
|
-
const selectorMatch = line.match(/^\s*([^{]+)\s*\{/);
|
|
2767
|
-
if (selectorMatch) {
|
|
2768
|
-
const selector = selectorMatch[1].trim();
|
|
2769
|
-
if ((line.match(/\{/g) || []).length > (line.match(/\}/g) || []).length) {
|
|
2770
|
-
currentSelector = selector;
|
|
2771
|
-
}
|
|
2772
|
-
}
|
|
2773
|
-
braceDepth += (line.match(/\{/g) || []).length;
|
|
2774
|
-
braceDepth -= (line.match(/\}/g) || []).length;
|
|
2775
|
-
if (braceDepth === 0) {
|
|
2776
|
-
currentSelector = ":root";
|
|
2777
|
-
}
|
|
2778
|
-
}
|
|
2779
|
-
return currentSelector;
|
|
2780
|
-
}
|
|
2781
|
-
function extractDescription(content, line) {
|
|
2782
|
-
const lines = content.split("\n");
|
|
2783
|
-
if (line <= 1) return void 0;
|
|
2784
|
-
const prevLine = lines[line - 2]?.trim();
|
|
2785
|
-
const singleLineMatch = prevLine?.match(/\/\/\s*(.+)$/);
|
|
2786
|
-
if (singleLineMatch) {
|
|
2787
|
-
return singleLineMatch[1].trim();
|
|
2788
|
-
}
|
|
2789
|
-
const multiLineMatch = prevLine?.match(/\*\s*(.+)\s*\*\//);
|
|
2790
|
-
if (multiLineMatch) {
|
|
2791
|
-
return multiLineMatch[1].trim();
|
|
2792
|
-
}
|
|
2793
|
-
const inlineMatch = prevLine?.match(/\/\*\s*(.+)\s*\*\//);
|
|
2794
|
-
if (inlineMatch) {
|
|
2795
|
-
return inlineMatch[1].trim();
|
|
2796
|
-
}
|
|
2797
|
-
return void 0;
|
|
2798
|
-
}
|
|
2799
|
-
function hexToRgb(hex) {
|
|
2800
|
-
const match = hex.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);
|
|
2801
|
-
if (!match) return null;
|
|
2802
|
-
return {
|
|
2803
|
-
r: parseInt(match[1], 16),
|
|
2804
|
-
g: parseInt(match[2], 16),
|
|
2805
|
-
b: parseInt(match[3], 16)
|
|
2806
|
-
};
|
|
2807
|
-
}
|
|
2808
|
-
function rgbToHex(r, g, b) {
|
|
2809
|
-
return `#${[r, g, b].map((x) => Math.round(x).toString(16).padStart(2, "0")).join("")}`;
|
|
2810
|
-
}
|
|
2811
|
-
function parseRgb(color) {
|
|
2812
|
-
const match = color.match(
|
|
2813
|
-
/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/
|
|
2814
|
-
);
|
|
2815
|
-
if (!match) return null;
|
|
2816
|
-
return {
|
|
2817
|
-
r: parseInt(match[1], 10),
|
|
2818
|
-
g: parseInt(match[2], 10),
|
|
2819
|
-
b: parseInt(match[3], 10),
|
|
2820
|
-
a: match[4] ? parseFloat(match[4]) : void 0
|
|
2821
|
-
};
|
|
2822
|
-
}
|
|
2823
|
-
function normalizeColor(color) {
|
|
2824
|
-
if (color.startsWith("#")) {
|
|
2825
|
-
return color.toLowerCase();
|
|
2826
|
-
}
|
|
2827
|
-
const rgb = parseRgb(color);
|
|
2828
|
-
if (rgb) {
|
|
2829
|
-
return rgbToHex(rgb.r, rgb.g, rgb.b);
|
|
2830
|
-
}
|
|
2831
|
-
return color.toLowerCase();
|
|
2832
|
-
}
|
|
2833
|
-
|
|
2834
2559
|
// src/service/token-registry.ts
|
|
2835
2560
|
var TokenRegistryManager = class {
|
|
2836
2561
|
registry = null;
|
|
@@ -3116,7 +2841,7 @@ var TokenRegistryManager = class {
|
|
|
3116
2841
|
}
|
|
3117
2842
|
if (theme) {
|
|
3118
2843
|
candidates = candidates.filter(
|
|
3119
|
-
(
|
|
2844
|
+
(t4) => t4.theme === theme || t4.theme === "default"
|
|
3120
2845
|
);
|
|
3121
2846
|
}
|
|
3122
2847
|
if (isColor) {
|
|
@@ -3633,28 +3358,11 @@ import { parse } from "@babel/parser";
|
|
|
3633
3358
|
import traverse from "@babel/traverse";
|
|
3634
3359
|
import generate from "@babel/generator";
|
|
3635
3360
|
import * as t from "@babel/types";
|
|
3636
|
-
var PARSER_OPTIONS = {
|
|
3637
|
-
sourceType: "module",
|
|
3638
|
-
plugins: [
|
|
3639
|
-
"jsx",
|
|
3640
|
-
"typescript",
|
|
3641
|
-
["decorators", { decoratorsBeforeExport: true }],
|
|
3642
|
-
"classProperties",
|
|
3643
|
-
"classPrivateProperties",
|
|
3644
|
-
"classPrivateMethods",
|
|
3645
|
-
"exportDefaultFrom",
|
|
3646
|
-
"exportNamespaceFrom",
|
|
3647
|
-
"dynamicImport",
|
|
3648
|
-
"nullishCoalescingOperator",
|
|
3649
|
-
"optionalChaining",
|
|
3650
|
-
"objectRestSpread"
|
|
3651
|
-
]
|
|
3652
|
-
};
|
|
3653
3361
|
function extractStyleLocations(sourceCode, filePath) {
|
|
3654
3362
|
const locations = [];
|
|
3655
3363
|
let ast;
|
|
3656
3364
|
try {
|
|
3657
|
-
ast = parse(sourceCode,
|
|
3365
|
+
ast = parse(sourceCode, BABEL_PARSER_OPTIONS);
|
|
3658
3366
|
} catch (error) {
|
|
3659
3367
|
console.error(`Failed to parse ${filePath}:`, error);
|
|
3660
3368
|
return locations;
|
|
@@ -3760,7 +3468,7 @@ function extractFromTemplateLiteral(template, path, filePath, type, locations) {
|
|
|
3760
3468
|
function applyPatch(sourceCode, styleLocation, oldValue, newValue) {
|
|
3761
3469
|
let ast;
|
|
3762
3470
|
try {
|
|
3763
|
-
ast = parse(sourceCode,
|
|
3471
|
+
ast = parse(sourceCode, BABEL_PARSER_OPTIONS);
|
|
3764
3472
|
} catch (error) {
|
|
3765
3473
|
return {
|
|
3766
3474
|
success: false,
|
|
@@ -3868,7 +3576,7 @@ function applyPatches(sourceCode, patches) {
|
|
|
3868
3576
|
}
|
|
3869
3577
|
|
|
3870
3578
|
// src/service/metrics-store.ts
|
|
3871
|
-
import { readFile as
|
|
3579
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, readdir as readdir2 } from "fs/promises";
|
|
3872
3580
|
import { join as join2 } from "path";
|
|
3873
3581
|
var MetricsStore = class {
|
|
3874
3582
|
projectRoot;
|
|
@@ -3888,7 +3596,7 @@ var MetricsStore = class {
|
|
|
3888
3596
|
const filepath = join2(this.metricsDir, filename);
|
|
3889
3597
|
let snapshots = [];
|
|
3890
3598
|
try {
|
|
3891
|
-
const existing = await
|
|
3599
|
+
const existing = await readFile2(filepath, "utf-8");
|
|
3892
3600
|
snapshots = JSON.parse(existing);
|
|
3893
3601
|
} catch {
|
|
3894
3602
|
}
|
|
@@ -3915,7 +3623,7 @@ var MetricsStore = class {
|
|
|
3915
3623
|
continue;
|
|
3916
3624
|
}
|
|
3917
3625
|
try {
|
|
3918
|
-
const content = await
|
|
3626
|
+
const content = await readFile2(join2(this.metricsDir, file), "utf-8");
|
|
3919
3627
|
const fileSnapshots = JSON.parse(content);
|
|
3920
3628
|
const matching = component === "all" ? fileSnapshots : fileSnapshots.filter((s) => s.component === component);
|
|
3921
3629
|
snapshots.push(...matching);
|
|
@@ -4042,907 +3750,22 @@ function createMetricsStore(projectRoot) {
|
|
|
4042
3750
|
return new MetricsStore(projectRoot);
|
|
4043
3751
|
}
|
|
4044
3752
|
|
|
4045
|
-
// src/service/enhance/
|
|
3753
|
+
// src/service/enhance/doc-extractor.ts
|
|
4046
3754
|
import { parse as parse2 } from "@babel/parser";
|
|
4047
3755
|
import _traverse from "@babel/traverse";
|
|
4048
3756
|
import * as t2 from "@babel/types";
|
|
4049
|
-
import { readFile as
|
|
4050
|
-
var traverse2 = _traverse.default || _traverse;
|
|
4051
|
-
var PARSER_OPTIONS2 = {
|
|
4052
|
-
sourceType: "module",
|
|
4053
|
-
plugins: [
|
|
4054
|
-
"jsx",
|
|
4055
|
-
"typescript",
|
|
4056
|
-
["decorators", { decoratorsBeforeExport: true }],
|
|
4057
|
-
"classProperties",
|
|
4058
|
-
"classPrivateProperties",
|
|
4059
|
-
"classPrivateMethods",
|
|
4060
|
-
"exportDefaultFrom",
|
|
4061
|
-
"exportNamespaceFrom",
|
|
4062
|
-
"dynamicImport",
|
|
4063
|
-
"nullishCoalescingOperator",
|
|
4064
|
-
"optionalChaining",
|
|
4065
|
-
"objectRestSpread"
|
|
4066
|
-
]
|
|
4067
|
-
};
|
|
4068
|
-
async function scanFileForImports(filePath) {
|
|
4069
|
-
const imports = [];
|
|
4070
|
-
try {
|
|
4071
|
-
const sourceCode = await readFile4(filePath, "utf-8");
|
|
4072
|
-
const ast = parse2(sourceCode, PARSER_OPTIONS2);
|
|
4073
|
-
traverse2(ast, {
|
|
4074
|
-
ImportDeclaration(path) {
|
|
4075
|
-
const source = path.node.source.value;
|
|
4076
|
-
const line = path.node.loc?.start.line ?? 0;
|
|
4077
|
-
for (const specifier of path.node.specifiers) {
|
|
4078
|
-
if (t2.isImportSpecifier(specifier)) {
|
|
4079
|
-
const importedName = t2.isIdentifier(specifier.imported) ? specifier.imported.name : specifier.imported.value;
|
|
4080
|
-
const localName = specifier.local.name;
|
|
4081
|
-
if (isPascalCase(importedName)) {
|
|
4082
|
-
imports.push({
|
|
4083
|
-
componentName: importedName,
|
|
4084
|
-
localName,
|
|
4085
|
-
source,
|
|
4086
|
-
isDefault: false,
|
|
4087
|
-
filePath,
|
|
4088
|
-
line
|
|
4089
|
-
});
|
|
4090
|
-
}
|
|
4091
|
-
} else if (t2.isImportDefaultSpecifier(specifier)) {
|
|
4092
|
-
const localName = specifier.local.name;
|
|
4093
|
-
if (isPascalCase(localName)) {
|
|
4094
|
-
imports.push({
|
|
4095
|
-
componentName: localName,
|
|
4096
|
-
localName,
|
|
4097
|
-
source,
|
|
4098
|
-
isDefault: true,
|
|
4099
|
-
filePath,
|
|
4100
|
-
line
|
|
4101
|
-
});
|
|
4102
|
-
}
|
|
4103
|
-
}
|
|
4104
|
-
}
|
|
4105
|
-
}
|
|
4106
|
-
});
|
|
4107
|
-
} catch (error) {
|
|
4108
|
-
console.warn(`Failed to parse ${filePath}:`, error.message);
|
|
4109
|
-
return [];
|
|
4110
|
-
}
|
|
4111
|
-
return imports;
|
|
4112
|
-
}
|
|
4113
|
-
async function scanFileForUsages(filePath, componentNames) {
|
|
4114
|
-
const usages = [];
|
|
4115
|
-
try {
|
|
4116
|
-
const sourceCode = await readFile4(filePath, "utf-8");
|
|
4117
|
-
const lines = sourceCode.split("\n");
|
|
4118
|
-
const ast = parse2(sourceCode, PARSER_OPTIONS2);
|
|
4119
|
-
traverse2(ast, {
|
|
4120
|
-
JSXOpeningElement(path) {
|
|
4121
|
-
const elementName = getJSXElementName(path.node.name);
|
|
4122
|
-
if (!elementName) return;
|
|
4123
|
-
const componentName = componentNames.get(elementName);
|
|
4124
|
-
if (!componentName) return;
|
|
4125
|
-
const loc = path.node.loc;
|
|
4126
|
-
if (!loc) return;
|
|
4127
|
-
const props = extractProps(path.node.attributes);
|
|
4128
|
-
const contextLines = getContextLines(lines, loc.start.line - 1, 3);
|
|
4129
|
-
const isConditional = checkIfConditional(path);
|
|
4130
|
-
const parentElement = getParentElementName(path);
|
|
4131
|
-
usages.push({
|
|
4132
|
-
componentName,
|
|
4133
|
-
filePath,
|
|
4134
|
-
line: loc.start.line,
|
|
4135
|
-
column: loc.start.column,
|
|
4136
|
-
props,
|
|
4137
|
-
context: contextLines,
|
|
4138
|
-
parentElement,
|
|
4139
|
-
hasSpreadProps: props.spreads.length > 0,
|
|
4140
|
-
isConditional
|
|
4141
|
-
});
|
|
4142
|
-
}
|
|
4143
|
-
});
|
|
4144
|
-
} catch (error) {
|
|
4145
|
-
console.warn(`Failed to parse ${filePath}:`, error.message);
|
|
4146
|
-
return [];
|
|
4147
|
-
}
|
|
4148
|
-
return usages;
|
|
4149
|
-
}
|
|
4150
|
-
async function scanFile(filePath, trackedComponents) {
|
|
4151
|
-
const imports = [];
|
|
4152
|
-
const usages = [];
|
|
4153
|
-
try {
|
|
4154
|
-
const sourceCode = await readFile4(filePath, "utf-8");
|
|
4155
|
-
const lines = sourceCode.split("\n");
|
|
4156
|
-
const ast = parse2(sourceCode, PARSER_OPTIONS2);
|
|
4157
|
-
const localToComponent = /* @__PURE__ */ new Map();
|
|
4158
|
-
traverse2(ast, {
|
|
4159
|
-
ImportDeclaration(path) {
|
|
4160
|
-
const source = path.node.source.value;
|
|
4161
|
-
const line = path.node.loc?.start.line ?? 0;
|
|
4162
|
-
for (const specifier of path.node.specifiers) {
|
|
4163
|
-
if (t2.isImportSpecifier(specifier)) {
|
|
4164
|
-
const importedName = t2.isIdentifier(specifier.imported) ? specifier.imported.name : specifier.imported.value;
|
|
4165
|
-
const localName = specifier.local.name;
|
|
4166
|
-
if (isPascalCase(importedName)) {
|
|
4167
|
-
if (!trackedComponents || trackedComponents.has(importedName)) {
|
|
4168
|
-
imports.push({
|
|
4169
|
-
componentName: importedName,
|
|
4170
|
-
localName,
|
|
4171
|
-
source,
|
|
4172
|
-
isDefault: false,
|
|
4173
|
-
filePath,
|
|
4174
|
-
line
|
|
4175
|
-
});
|
|
4176
|
-
localToComponent.set(localName, importedName);
|
|
4177
|
-
}
|
|
4178
|
-
}
|
|
4179
|
-
} else if (t2.isImportDefaultSpecifier(specifier)) {
|
|
4180
|
-
const localName = specifier.local.name;
|
|
4181
|
-
if (isPascalCase(localName)) {
|
|
4182
|
-
if (!trackedComponents || trackedComponents.has(localName)) {
|
|
4183
|
-
imports.push({
|
|
4184
|
-
componentName: localName,
|
|
4185
|
-
localName,
|
|
4186
|
-
source,
|
|
4187
|
-
isDefault: true,
|
|
4188
|
-
filePath,
|
|
4189
|
-
line
|
|
4190
|
-
});
|
|
4191
|
-
localToComponent.set(localName, localName);
|
|
4192
|
-
}
|
|
4193
|
-
}
|
|
4194
|
-
}
|
|
4195
|
-
}
|
|
4196
|
-
},
|
|
4197
|
-
JSXOpeningElement(path) {
|
|
4198
|
-
const elementName = getJSXElementName(path.node.name);
|
|
4199
|
-
if (!elementName) return;
|
|
4200
|
-
const componentName = localToComponent.get(elementName);
|
|
4201
|
-
if (!componentName) return;
|
|
4202
|
-
const loc = path.node.loc;
|
|
4203
|
-
if (!loc) return;
|
|
4204
|
-
const props = extractProps(path.node.attributes);
|
|
4205
|
-
const contextLines = getContextLines(lines, loc.start.line - 1, 3);
|
|
4206
|
-
const isConditional = checkIfConditional(path);
|
|
4207
|
-
const parentElement = getParentElementName(path);
|
|
4208
|
-
usages.push({
|
|
4209
|
-
componentName,
|
|
4210
|
-
filePath,
|
|
4211
|
-
line: loc.start.line,
|
|
4212
|
-
column: loc.start.column,
|
|
4213
|
-
props,
|
|
4214
|
-
context: contextLines,
|
|
4215
|
-
parentElement,
|
|
4216
|
-
hasSpreadProps: props.spreads.length > 0,
|
|
4217
|
-
isConditional
|
|
4218
|
-
});
|
|
4219
|
-
}
|
|
4220
|
-
});
|
|
4221
|
-
} catch (error) {
|
|
4222
|
-
console.warn(`Failed to parse ${filePath}:`, error.message);
|
|
4223
|
-
return { imports: [], usages: [] };
|
|
4224
|
-
}
|
|
4225
|
-
return { imports, usages };
|
|
4226
|
-
}
|
|
4227
|
-
function isPascalCase(str) {
|
|
4228
|
-
return /^[A-Z][a-zA-Z0-9]*$/.test(str);
|
|
4229
|
-
}
|
|
4230
|
-
function getJSXElementName(name) {
|
|
4231
|
-
if (t2.isJSXIdentifier(name)) {
|
|
4232
|
-
return name.name;
|
|
4233
|
-
}
|
|
4234
|
-
if (t2.isJSXMemberExpression(name)) {
|
|
4235
|
-
const parts = [];
|
|
4236
|
-
let current = name;
|
|
4237
|
-
while (t2.isJSXMemberExpression(current)) {
|
|
4238
|
-
parts.unshift(current.property.name);
|
|
4239
|
-
current = current.object;
|
|
4240
|
-
}
|
|
4241
|
-
if (t2.isJSXIdentifier(current)) {
|
|
4242
|
-
parts.unshift(current.name);
|
|
4243
|
-
}
|
|
4244
|
-
return parts.join(".");
|
|
4245
|
-
}
|
|
4246
|
-
return null;
|
|
4247
|
-
}
|
|
4248
|
-
function extractProps(attributes) {
|
|
4249
|
-
const result = {
|
|
4250
|
-
static: {},
|
|
4251
|
-
dynamic: [],
|
|
4252
|
-
spreads: []
|
|
4253
|
-
};
|
|
4254
|
-
for (const attr of attributes) {
|
|
4255
|
-
if (t2.isJSXSpreadAttribute(attr)) {
|
|
4256
|
-
if (t2.isIdentifier(attr.argument)) {
|
|
4257
|
-
result.spreads.push(attr.argument.name);
|
|
4258
|
-
} else {
|
|
4259
|
-
result.spreads.push("(expression)");
|
|
4260
|
-
}
|
|
4261
|
-
} else if (t2.isJSXAttribute(attr)) {
|
|
4262
|
-
const propName = t2.isJSXIdentifier(attr.name) ? attr.name.name : `${attr.name.namespace.name}:${attr.name.name.name}`;
|
|
4263
|
-
const value = attr.value;
|
|
4264
|
-
if (value === null) {
|
|
4265
|
-
result.static[propName] = true;
|
|
4266
|
-
} else if (t2.isStringLiteral(value)) {
|
|
4267
|
-
result.static[propName] = value.value;
|
|
4268
|
-
} else if (t2.isJSXExpressionContainer(value)) {
|
|
4269
|
-
const expr = value.expression;
|
|
4270
|
-
if (t2.isStringLiteral(expr)) {
|
|
4271
|
-
result.static[propName] = expr.value;
|
|
4272
|
-
} else if (t2.isNumericLiteral(expr)) {
|
|
4273
|
-
result.static[propName] = expr.value;
|
|
4274
|
-
} else if (t2.isBooleanLiteral(expr)) {
|
|
4275
|
-
result.static[propName] = expr.value;
|
|
4276
|
-
} else if (t2.isTemplateLiteral(expr) && expr.expressions.length === 0) {
|
|
4277
|
-
result.static[propName] = expr.quasis.map((q) => q.value.raw).join("");
|
|
4278
|
-
} else {
|
|
4279
|
-
result.dynamic.push(propName);
|
|
4280
|
-
}
|
|
4281
|
-
}
|
|
4282
|
-
}
|
|
4283
|
-
}
|
|
4284
|
-
return result;
|
|
4285
|
-
}
|
|
4286
|
-
function getContextLines(lines, centerLine, radius) {
|
|
4287
|
-
const start = Math.max(0, centerLine - radius);
|
|
4288
|
-
const end = Math.min(lines.length, centerLine + radius + 1);
|
|
4289
|
-
return lines.slice(start, end).join("\n");
|
|
4290
|
-
}
|
|
4291
|
-
function checkIfConditional(path) {
|
|
4292
|
-
let current = path.parentPath;
|
|
4293
|
-
while (current) {
|
|
4294
|
-
if (current.isLogicalExpression() && current.node.operator === "&&") {
|
|
4295
|
-
return true;
|
|
4296
|
-
}
|
|
4297
|
-
if (current.isConditionalExpression()) {
|
|
4298
|
-
return true;
|
|
4299
|
-
}
|
|
4300
|
-
if (current.isJSXExpressionContainer() && current.parentPath?.isJSXElement()) {
|
|
4301
|
-
const expr = current.node.expression;
|
|
4302
|
-
if (t2.isLogicalExpression(expr) || t2.isConditionalExpression(expr)) {
|
|
4303
|
-
return true;
|
|
4304
|
-
}
|
|
4305
|
-
}
|
|
4306
|
-
current = current.parentPath;
|
|
4307
|
-
}
|
|
4308
|
-
return false;
|
|
4309
|
-
}
|
|
4310
|
-
function getParentElementName(path) {
|
|
4311
|
-
let current = path.parentPath;
|
|
4312
|
-
const currentElementName = getJSXElementName(path.node.name);
|
|
4313
|
-
while (current) {
|
|
4314
|
-
if (current.isJSXElement()) {
|
|
4315
|
-
const opening = current.node.openingElement;
|
|
4316
|
-
const name = getJSXElementName(opening.name);
|
|
4317
|
-
if (name && name !== currentElementName) {
|
|
4318
|
-
return name;
|
|
4319
|
-
}
|
|
4320
|
-
}
|
|
4321
|
-
current = current.parentPath;
|
|
4322
|
-
}
|
|
4323
|
-
return void 0;
|
|
4324
|
-
}
|
|
4325
|
-
|
|
4326
|
-
// src/service/enhance/aggregator.ts
|
|
4327
|
-
function aggregateComponentUsages(componentName, sourceFile, usages, imports) {
|
|
4328
|
-
const uniqueFiles = new Set(usages.map((u) => u.filePath));
|
|
4329
|
-
const patternMap = /* @__PURE__ */ new Map();
|
|
4330
|
-
for (const usage of usages) {
|
|
4331
|
-
const propKey = createPropKey(usage.props.static);
|
|
4332
|
-
const existing = patternMap.get(propKey);
|
|
4333
|
-
if (existing) {
|
|
4334
|
-
existing.count++;
|
|
4335
|
-
if (!existing.files.includes(usage.filePath)) {
|
|
4336
|
-
existing.files.push(usage.filePath);
|
|
4337
|
-
}
|
|
4338
|
-
if (existing.sampleContexts.length < 3) {
|
|
4339
|
-
existing.sampleContexts.push(usage.context);
|
|
4340
|
-
}
|
|
4341
|
-
} else {
|
|
4342
|
-
patternMap.set(propKey, {
|
|
4343
|
-
props: { ...usage.props.static },
|
|
4344
|
-
count: 1,
|
|
4345
|
-
files: [usage.filePath],
|
|
4346
|
-
sampleContexts: [usage.context]
|
|
4347
|
-
});
|
|
4348
|
-
}
|
|
4349
|
-
}
|
|
4350
|
-
const patterns = Array.from(patternMap.values()).sort(
|
|
4351
|
-
(a, b) => b.count - a.count
|
|
4352
|
-
);
|
|
4353
|
-
const contextMap = /* @__PURE__ */ new Map();
|
|
4354
|
-
for (const usage of usages) {
|
|
4355
|
-
const context = classifyFileContext(usage.filePath, usage.context);
|
|
4356
|
-
const existing = contextMap.get(context);
|
|
4357
|
-
if (existing) {
|
|
4358
|
-
existing.count++;
|
|
4359
|
-
if (!existing.files.includes(usage.filePath)) {
|
|
4360
|
-
existing.files.push(usage.filePath);
|
|
4361
|
-
}
|
|
4362
|
-
} else {
|
|
4363
|
-
contextMap.set(context, { count: 1, files: [usage.filePath] });
|
|
4364
|
-
}
|
|
4365
|
-
}
|
|
4366
|
-
const contexts = Array.from(contextMap.entries()).map(([type, data]) => ({ type, ...data })).sort((a, b) => b.count - a.count);
|
|
4367
|
-
return {
|
|
4368
|
-
name: componentName,
|
|
4369
|
-
sourceFile,
|
|
4370
|
-
totalUsages: usages.length,
|
|
4371
|
-
uniqueFiles: uniqueFiles.size,
|
|
4372
|
-
patterns,
|
|
4373
|
-
contexts,
|
|
4374
|
-
usages,
|
|
4375
|
-
imports
|
|
4376
|
-
};
|
|
4377
|
-
}
|
|
4378
|
-
function aggregateAllUsages(usages, imports, componentSources) {
|
|
4379
|
-
const usagesByComponent = /* @__PURE__ */ new Map();
|
|
4380
|
-
for (const usage of usages) {
|
|
4381
|
-
const existing = usagesByComponent.get(usage.componentName) ?? [];
|
|
4382
|
-
existing.push(usage);
|
|
4383
|
-
usagesByComponent.set(usage.componentName, existing);
|
|
4384
|
-
}
|
|
4385
|
-
const importsByComponent = /* @__PURE__ */ new Map();
|
|
4386
|
-
for (const imp of imports) {
|
|
4387
|
-
const existing = importsByComponent.get(imp.componentName) ?? [];
|
|
4388
|
-
existing.push(imp);
|
|
4389
|
-
importsByComponent.set(imp.componentName, existing);
|
|
4390
|
-
}
|
|
4391
|
-
const components = {};
|
|
4392
|
-
const allComponentNames = /* @__PURE__ */ new Set([
|
|
4393
|
-
...usagesByComponent.keys(),
|
|
4394
|
-
...importsByComponent.keys()
|
|
4395
|
-
]);
|
|
4396
|
-
for (const componentName of allComponentNames) {
|
|
4397
|
-
const componentUsages = usagesByComponent.get(componentName) ?? [];
|
|
4398
|
-
const componentImports = importsByComponent.get(componentName) ?? [];
|
|
4399
|
-
const sourceFile = componentSources.get(componentName) ?? "unknown";
|
|
4400
|
-
components[componentName] = aggregateComponentUsages(
|
|
4401
|
-
componentName,
|
|
4402
|
-
sourceFile,
|
|
4403
|
-
componentUsages,
|
|
4404
|
-
componentImports
|
|
4405
|
-
);
|
|
4406
|
-
}
|
|
4407
|
-
const allFiles = /* @__PURE__ */ new Set();
|
|
4408
|
-
for (const usage of usages) {
|
|
4409
|
-
allFiles.add(usage.filePath);
|
|
4410
|
-
}
|
|
4411
|
-
for (const imp of imports) {
|
|
4412
|
-
allFiles.add(imp.filePath);
|
|
4413
|
-
}
|
|
4414
|
-
return {
|
|
4415
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4416
|
-
rootDir: "",
|
|
4417
|
-
// Will be set by caller
|
|
4418
|
-
totalFiles: allFiles.size,
|
|
4419
|
-
totalComponents: Object.keys(components).length,
|
|
4420
|
-
components,
|
|
4421
|
-
errorFiles: []
|
|
4422
|
-
// Will be populated by scanner
|
|
4423
|
-
};
|
|
4424
|
-
}
|
|
4425
|
-
function createPropKey(props) {
|
|
4426
|
-
const entries = Object.entries(props).sort(([a], [b]) => a.localeCompare(b));
|
|
4427
|
-
return entries.map(([k, v]) => `${k}=${JSON.stringify(v)}`).join("|");
|
|
4428
|
-
}
|
|
4429
|
-
function classifyFileContext(filePath, context) {
|
|
4430
|
-
const lowerPath = filePath.toLowerCase();
|
|
4431
|
-
const lowerContext = context.toLowerCase();
|
|
4432
|
-
if (lowerPath.includes("/modal") || lowerPath.includes("modal.") || lowerContext.includes("<modal")) {
|
|
4433
|
-
return "modal";
|
|
4434
|
-
}
|
|
4435
|
-
if (lowerPath.includes("/dialog") || lowerPath.includes("dialog.") || lowerContext.includes("<dialog")) {
|
|
4436
|
-
return "dialog";
|
|
4437
|
-
}
|
|
4438
|
-
if (lowerPath.includes("/form") || lowerPath.includes("form.") || lowerContext.includes("<form") || lowerContext.includes("onsubmit")) {
|
|
4439
|
-
return "form";
|
|
4440
|
-
}
|
|
4441
|
-
if (lowerPath.includes("/page") || lowerPath.includes("pages/") || lowerPath.includes("/routes/")) {
|
|
4442
|
-
return "page";
|
|
4443
|
-
}
|
|
4444
|
-
if (lowerPath.includes("/layout") || lowerPath.includes("layout.") || lowerPath.includes("/layouts/")) {
|
|
4445
|
-
return "layout";
|
|
4446
|
-
}
|
|
4447
|
-
if (lowerPath.includes("/card") || lowerPath.includes("card.") || lowerContext.includes("<card")) {
|
|
4448
|
-
return "card";
|
|
4449
|
-
}
|
|
4450
|
-
if (lowerPath.includes("/table") || lowerPath.includes("table.") || lowerContext.includes("<table") || lowerContext.includes("<tr")) {
|
|
4451
|
-
return "table";
|
|
4452
|
-
}
|
|
4453
|
-
if (lowerPath.includes("/list") || lowerPath.includes("list.") || lowerContext.includes("<ul") || lowerContext.includes("<ol") || lowerContext.includes("<li")) {
|
|
4454
|
-
return "list";
|
|
4455
|
-
}
|
|
4456
|
-
if (lowerPath.includes("/nav") || lowerPath.includes("navigation") || lowerContext.includes("<nav")) {
|
|
4457
|
-
return "navigation";
|
|
4458
|
-
}
|
|
4459
|
-
if (lowerPath.includes("/header") || lowerPath.includes("header.") || lowerContext.includes("<header")) {
|
|
4460
|
-
return "header";
|
|
4461
|
-
}
|
|
4462
|
-
if (lowerPath.includes("/footer") || lowerPath.includes("footer.") || lowerContext.includes("<footer")) {
|
|
4463
|
-
return "footer";
|
|
4464
|
-
}
|
|
4465
|
-
if (lowerPath.includes("/sidebar") || lowerPath.includes("sidebar.") || lowerContext.includes("<aside")) {
|
|
4466
|
-
return "sidebar";
|
|
4467
|
-
}
|
|
4468
|
-
return "unknown";
|
|
4469
|
-
}
|
|
4470
|
-
function findCommonPropCombinations(usages, minOccurrences = 3) {
|
|
4471
|
-
const combinations = /* @__PURE__ */ new Map();
|
|
4472
|
-
for (const usage of usages) {
|
|
4473
|
-
const allProps = [
|
|
4474
|
-
...Object.keys(usage.props.static),
|
|
4475
|
-
...usage.props.dynamic
|
|
4476
|
-
].sort();
|
|
4477
|
-
for (let size = 2; size <= Math.min(allProps.length, 4); size++) {
|
|
4478
|
-
for (const combo of combinations_k(allProps, size)) {
|
|
4479
|
-
const key = combo.join(",");
|
|
4480
|
-
combinations.set(key, (combinations.get(key) ?? 0) + 1);
|
|
4481
|
-
}
|
|
4482
|
-
}
|
|
4483
|
-
}
|
|
4484
|
-
return Array.from(combinations.entries()).filter(([, count]) => count >= minOccurrences).map(([key, count]) => ({ props: key.split(","), count })).sort((a, b) => b.count - a.count);
|
|
4485
|
-
}
|
|
4486
|
-
function* combinations_k(arr, k) {
|
|
4487
|
-
if (k === 0) {
|
|
4488
|
-
yield [];
|
|
4489
|
-
return;
|
|
4490
|
-
}
|
|
4491
|
-
if (arr.length < k) return;
|
|
4492
|
-
for (let i = 0; i <= arr.length - k; i++) {
|
|
4493
|
-
for (const combo of combinations_k(arr.slice(i + 1), k - 1)) {
|
|
4494
|
-
yield [arr[i], ...combo];
|
|
4495
|
-
}
|
|
4496
|
-
}
|
|
4497
|
-
}
|
|
4498
|
-
function inferRelations(componentName, analysis, allAnalyses) {
|
|
4499
|
-
const relations = [];
|
|
4500
|
-
const parentCounts = /* @__PURE__ */ new Map();
|
|
4501
|
-
const siblingCounts = /* @__PURE__ */ new Map();
|
|
4502
|
-
for (const usage of analysis.usages) {
|
|
4503
|
-
if (usage.parentElement && usage.parentElement !== "div" && usage.parentElement !== "span") {
|
|
4504
|
-
const parent = usage.parentElement;
|
|
4505
|
-
const existing = parentCounts.get(parent);
|
|
4506
|
-
if (existing) {
|
|
4507
|
-
existing.count++;
|
|
4508
|
-
if (!existing.files.includes(usage.filePath)) {
|
|
4509
|
-
existing.files.push(usage.filePath);
|
|
4510
|
-
}
|
|
4511
|
-
} else {
|
|
4512
|
-
parentCounts.set(parent, { count: 1, files: [usage.filePath] });
|
|
4513
|
-
}
|
|
4514
|
-
}
|
|
4515
|
-
}
|
|
4516
|
-
const filesWithThisComponent = new Set(analysis.usages.map((u) => u.filePath));
|
|
4517
|
-
for (const [otherName, otherAnalysis] of Object.entries(allAnalyses)) {
|
|
4518
|
-
if (otherName === componentName) continue;
|
|
4519
|
-
let sharedFiles = 0;
|
|
4520
|
-
const sharedFileList = [];
|
|
4521
|
-
for (const usage of otherAnalysis.usages) {
|
|
4522
|
-
if (filesWithThisComponent.has(usage.filePath)) {
|
|
4523
|
-
if (!sharedFileList.includes(usage.filePath)) {
|
|
4524
|
-
sharedFiles++;
|
|
4525
|
-
sharedFileList.push(usage.filePath);
|
|
4526
|
-
}
|
|
4527
|
-
}
|
|
4528
|
-
}
|
|
4529
|
-
if (sharedFiles >= 3) {
|
|
4530
|
-
siblingCounts.set(otherName, {
|
|
4531
|
-
count: sharedFiles,
|
|
4532
|
-
files: sharedFileList.slice(0, 5)
|
|
4533
|
-
});
|
|
4534
|
-
}
|
|
4535
|
-
}
|
|
4536
|
-
for (const [parent, data] of parentCounts) {
|
|
4537
|
-
if (data.count >= 2) {
|
|
4538
|
-
relations.push({
|
|
4539
|
-
component: parent,
|
|
4540
|
-
relationship: "parent",
|
|
4541
|
-
frequency: data.count,
|
|
4542
|
-
sampleFiles: data.files.slice(0, 3)
|
|
4543
|
-
});
|
|
4544
|
-
}
|
|
4545
|
-
}
|
|
4546
|
-
for (const [sibling, data] of siblingCounts) {
|
|
4547
|
-
relations.push({
|
|
4548
|
-
component: sibling,
|
|
4549
|
-
relationship: "sibling",
|
|
4550
|
-
frequency: data.count,
|
|
4551
|
-
sampleFiles: data.files.slice(0, 3)
|
|
4552
|
-
});
|
|
4553
|
-
}
|
|
4554
|
-
relations.sort((a, b) => b.frequency - a.frequency);
|
|
4555
|
-
return relations;
|
|
4556
|
-
}
|
|
4557
|
-
function inferAllRelations(analysis) {
|
|
4558
|
-
const allRelations = /* @__PURE__ */ new Map();
|
|
4559
|
-
for (const [componentName, componentAnalysis] of Object.entries(analysis.components)) {
|
|
4560
|
-
const relations = inferRelations(componentName, componentAnalysis, analysis.components);
|
|
4561
|
-
if (relations.length > 0) {
|
|
4562
|
-
allRelations.set(componentName, relations);
|
|
4563
|
-
}
|
|
4564
|
-
}
|
|
4565
|
-
return allRelations;
|
|
4566
|
-
}
|
|
4567
|
-
function summarizePatternsForPrompt(analysis, maxPatterns = 10, maxContexts = 5) {
|
|
4568
|
-
const lines = [];
|
|
4569
|
-
lines.push(`## ${analysis.name}`);
|
|
4570
|
-
lines.push(`Total usages: ${analysis.totalUsages} across ${analysis.uniqueFiles} files`);
|
|
4571
|
-
lines.push("");
|
|
4572
|
-
lines.push("### Usage Patterns (by frequency)");
|
|
4573
|
-
const topPatterns = analysis.patterns.slice(0, maxPatterns);
|
|
4574
|
-
for (const pattern of topPatterns) {
|
|
4575
|
-
const propsStr = Object.entries(pattern.props).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(", ");
|
|
4576
|
-
lines.push(`- ${propsStr || "(no props)"}: ${pattern.count} usages in ${pattern.files.length} files`);
|
|
4577
|
-
}
|
|
4578
|
-
lines.push("");
|
|
4579
|
-
lines.push("### File Contexts");
|
|
4580
|
-
const topContexts = analysis.contexts.slice(0, maxContexts);
|
|
4581
|
-
for (const ctx of topContexts) {
|
|
4582
|
-
lines.push(`- ${ctx.type}: ${ctx.count} usages`);
|
|
4583
|
-
}
|
|
4584
|
-
lines.push("");
|
|
4585
|
-
lines.push("### Sample Usages");
|
|
4586
|
-
for (const pattern of topPatterns.slice(0, 3)) {
|
|
4587
|
-
if (pattern.sampleContexts[0]) {
|
|
4588
|
-
lines.push("```tsx");
|
|
4589
|
-
lines.push(pattern.sampleContexts[0].trim());
|
|
4590
|
-
lines.push("```");
|
|
4591
|
-
lines.push("");
|
|
4592
|
-
}
|
|
4593
|
-
}
|
|
4594
|
-
return lines.join("\n");
|
|
4595
|
-
}
|
|
4596
|
-
|
|
4597
|
-
// src/service/enhance/cache.ts
|
|
4598
|
-
import { readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
|
|
3757
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
4599
3758
|
import { existsSync as existsSync2 } from "fs";
|
|
4600
|
-
import {
|
|
4601
|
-
|
|
4602
|
-
import { mkdir as mkdir3 } from "fs/promises";
|
|
4603
|
-
var CURRENT_CACHE_VERSION = 1;
|
|
4604
|
-
var CACHE_FILENAME = "analysis-cache.json";
|
|
4605
|
-
function getCachePath(rootDir) {
|
|
4606
|
-
return join3(rootDir, ".fragments", CACHE_FILENAME);
|
|
4607
|
-
}
|
|
4608
|
-
async function loadCache(rootDir) {
|
|
4609
|
-
const cachePath = getCachePath(rootDir);
|
|
4610
|
-
if (!existsSync2(cachePath)) {
|
|
4611
|
-
return null;
|
|
4612
|
-
}
|
|
4613
|
-
try {
|
|
4614
|
-
const content = await readFile5(cachePath, "utf-8");
|
|
4615
|
-
const cache = JSON.parse(content);
|
|
4616
|
-
if (cache.version !== CURRENT_CACHE_VERSION) {
|
|
4617
|
-
console.warn(
|
|
4618
|
-
`Cache version mismatch: expected ${CURRENT_CACHE_VERSION}, got ${cache.version}. Invalidating cache.`
|
|
4619
|
-
);
|
|
4620
|
-
return null;
|
|
4621
|
-
}
|
|
4622
|
-
if (cache.rootDir !== rootDir) {
|
|
4623
|
-
console.warn(`Cache root mismatch. Invalidating cache.`);
|
|
4624
|
-
return null;
|
|
4625
|
-
}
|
|
4626
|
-
return cache;
|
|
4627
|
-
} catch (error) {
|
|
4628
|
-
console.warn(`Failed to load cache: ${error.message}`);
|
|
4629
|
-
return null;
|
|
4630
|
-
}
|
|
4631
|
-
}
|
|
4632
|
-
async function saveCache(rootDir, cache) {
|
|
4633
|
-
const cachePath = getCachePath(rootDir);
|
|
4634
|
-
const cacheDir = dirname3(cachePath);
|
|
4635
|
-
if (!existsSync2(cacheDir)) {
|
|
4636
|
-
await mkdir3(cacheDir, { recursive: true });
|
|
4637
|
-
}
|
|
4638
|
-
cache.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4639
|
-
await writeFile3(cachePath, JSON.stringify(cache, null, 2));
|
|
4640
|
-
}
|
|
4641
|
-
function createEmptyCache(rootDir) {
|
|
4642
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4643
|
-
return {
|
|
4644
|
-
version: CURRENT_CACHE_VERSION,
|
|
4645
|
-
createdAt: now,
|
|
4646
|
-
updatedAt: now,
|
|
4647
|
-
rootDir,
|
|
4648
|
-
files: {}
|
|
4649
|
-
};
|
|
4650
|
-
}
|
|
4651
|
-
function computeFileHash(content) {
|
|
4652
|
-
return createHash2("md5").update(content).digest("hex");
|
|
4653
|
-
}
|
|
4654
|
-
function getCachedFile(cache, filePath) {
|
|
4655
|
-
return cache.files[filePath] ?? null;
|
|
4656
|
-
}
|
|
4657
|
-
function updateCacheFile(cache, filePath, hash, imports, usages) {
|
|
4658
|
-
cache.files[filePath] = {
|
|
4659
|
-
hash,
|
|
4660
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4661
|
-
imports,
|
|
4662
|
-
usages
|
|
4663
|
-
};
|
|
4664
|
-
}
|
|
4665
|
-
function removeCacheFile(cache, filePath) {
|
|
4666
|
-
delete cache.files[filePath];
|
|
4667
|
-
}
|
|
4668
|
-
async function detectFileChanges(cache, currentFiles, getFileHash) {
|
|
4669
|
-
const changes = {
|
|
4670
|
-
added: [],
|
|
4671
|
-
modified: [],
|
|
4672
|
-
deleted: [],
|
|
4673
|
-
unchanged: []
|
|
4674
|
-
};
|
|
4675
|
-
const currentFileSet = new Set(currentFiles);
|
|
4676
|
-
const cachedFileSet = new Set(Object.keys(cache.files));
|
|
4677
|
-
for (const filePath of currentFiles) {
|
|
4678
|
-
const entry = cache.files[filePath];
|
|
4679
|
-
if (!entry) {
|
|
4680
|
-
changes.added.push(filePath);
|
|
4681
|
-
} else {
|
|
4682
|
-
const currentHash = await getFileHash(filePath);
|
|
4683
|
-
if (currentHash !== entry.hash) {
|
|
4684
|
-
changes.modified.push(filePath);
|
|
4685
|
-
} else {
|
|
4686
|
-
changes.unchanged.push(filePath);
|
|
4687
|
-
}
|
|
4688
|
-
}
|
|
4689
|
-
}
|
|
4690
|
-
for (const cachedFile of cachedFileSet) {
|
|
4691
|
-
if (!currentFileSet.has(cachedFile)) {
|
|
4692
|
-
changes.deleted.push(cachedFile);
|
|
4693
|
-
}
|
|
4694
|
-
}
|
|
4695
|
-
return changes;
|
|
4696
|
-
}
|
|
4697
|
-
function getCacheStats(cache) {
|
|
4698
|
-
let totalImports = 0;
|
|
4699
|
-
let totalUsages = 0;
|
|
4700
|
-
for (const entry of Object.values(cache.files)) {
|
|
4701
|
-
totalImports += entry.imports.length;
|
|
4702
|
-
totalUsages += entry.usages.length;
|
|
4703
|
-
}
|
|
4704
|
-
const ageMs = Date.now() - new Date(cache.updatedAt).getTime();
|
|
4705
|
-
const ageMinutes = Math.round(ageMs / 6e4);
|
|
4706
|
-
const cacheAge = ageMinutes < 60 ? `${ageMinutes} minutes ago` : ageMinutes < 1440 ? `${Math.round(ageMinutes / 60)} hours ago` : `${Math.round(ageMinutes / 1440)} days ago`;
|
|
4707
|
-
return {
|
|
4708
|
-
totalFiles: Object.keys(cache.files).length,
|
|
4709
|
-
totalImports,
|
|
4710
|
-
totalUsages,
|
|
4711
|
-
cacheAge
|
|
4712
|
-
};
|
|
4713
|
-
}
|
|
4714
|
-
|
|
4715
|
-
// src/service/enhance/codebase-scanner.ts
|
|
4716
|
-
import fg from "fast-glob";
|
|
4717
|
-
import { readFile as readFile6 } from "fs/promises";
|
|
4718
|
-
import { relative as relative2, resolve as resolve3, dirname as dirname4 } from "path";
|
|
4719
|
-
var DEFAULT_INCLUDE = [
|
|
4720
|
-
"**/*.tsx",
|
|
4721
|
-
"**/*.ts",
|
|
4722
|
-
"**/*.jsx",
|
|
4723
|
-
"**/*.js"
|
|
4724
|
-
];
|
|
4725
|
-
var DEFAULT_EXCLUDE = [
|
|
4726
|
-
"**/node_modules/**",
|
|
4727
|
-
"**/dist/**",
|
|
4728
|
-
"**/build/**",
|
|
4729
|
-
"**/.next/**",
|
|
4730
|
-
"**/coverage/**",
|
|
4731
|
-
"**/__tests__/**",
|
|
4732
|
-
"**/*.test.*",
|
|
4733
|
-
"**/*.spec.*",
|
|
4734
|
-
"**/*.stories.*",
|
|
4735
|
-
"**/*.fragment.*",
|
|
4736
|
-
"**/storybook-static/**"
|
|
4737
|
-
];
|
|
4738
|
-
async function scanCodebase(options) {
|
|
4739
|
-
const {
|
|
4740
|
-
rootDir,
|
|
4741
|
-
include = DEFAULT_INCLUDE,
|
|
4742
|
-
exclude = DEFAULT_EXCLUDE,
|
|
4743
|
-
componentNames,
|
|
4744
|
-
useCache = true,
|
|
4745
|
-
onProgress
|
|
4746
|
-
} = options;
|
|
4747
|
-
const absoluteRoot = resolve3(rootDir);
|
|
4748
|
-
let cache = null;
|
|
4749
|
-
if (useCache) {
|
|
4750
|
-
cache = await loadCache(absoluteRoot);
|
|
4751
|
-
}
|
|
4752
|
-
if (!cache) {
|
|
4753
|
-
cache = createEmptyCache(absoluteRoot);
|
|
4754
|
-
}
|
|
4755
|
-
onProgress?.({
|
|
4756
|
-
current: 0,
|
|
4757
|
-
total: 0,
|
|
4758
|
-
currentFile: "",
|
|
4759
|
-
phase: "discovering"
|
|
4760
|
-
});
|
|
4761
|
-
const files = await fg(include, {
|
|
4762
|
-
cwd: absoluteRoot,
|
|
4763
|
-
ignore: exclude,
|
|
4764
|
-
absolute: true,
|
|
4765
|
-
onlyFiles: true
|
|
4766
|
-
});
|
|
4767
|
-
const totalFiles = files.length;
|
|
4768
|
-
const trackedComponents = componentNames ? new Set(componentNames) : void 0;
|
|
4769
|
-
const allImports = [];
|
|
4770
|
-
const allUsages = [];
|
|
4771
|
-
const errorFiles = [];
|
|
4772
|
-
const componentSources = /* @__PURE__ */ new Map();
|
|
4773
|
-
for (let i = 0; i < files.length; i++) {
|
|
4774
|
-
const filePath = files[i];
|
|
4775
|
-
const relativePath = relative2(absoluteRoot, filePath);
|
|
4776
|
-
onProgress?.({
|
|
4777
|
-
current: i + 1,
|
|
4778
|
-
total: totalFiles,
|
|
4779
|
-
currentFile: relativePath,
|
|
4780
|
-
phase: "scanning"
|
|
4781
|
-
});
|
|
4782
|
-
try {
|
|
4783
|
-
const content = await readFile6(filePath, "utf-8");
|
|
4784
|
-
const fileHash = computeFileHash(content);
|
|
4785
|
-
const cachedEntry = getCachedFile(cache, filePath);
|
|
4786
|
-
if (cachedEntry && cachedEntry.hash === fileHash) {
|
|
4787
|
-
allImports.push(...cachedEntry.imports);
|
|
4788
|
-
allUsages.push(...cachedEntry.usages);
|
|
4789
|
-
for (const imp of cachedEntry.imports) {
|
|
4790
|
-
if (!componentSources.has(imp.componentName)) {
|
|
4791
|
-
const sourceFile = resolveImportSource(filePath, imp.source);
|
|
4792
|
-
if (sourceFile) {
|
|
4793
|
-
componentSources.set(imp.componentName, sourceFile);
|
|
4794
|
-
}
|
|
4795
|
-
}
|
|
4796
|
-
}
|
|
4797
|
-
continue;
|
|
4798
|
-
}
|
|
4799
|
-
const { imports, usages } = await scanFile(filePath, trackedComponents);
|
|
4800
|
-
updateCacheFile(cache, filePath, fileHash, imports, usages);
|
|
4801
|
-
allImports.push(...imports);
|
|
4802
|
-
allUsages.push(...usages);
|
|
4803
|
-
for (const imp of imports) {
|
|
4804
|
-
if (!componentSources.has(imp.componentName)) {
|
|
4805
|
-
const sourceFile = resolveImportSource(filePath, imp.source);
|
|
4806
|
-
if (sourceFile) {
|
|
4807
|
-
componentSources.set(imp.componentName, sourceFile);
|
|
4808
|
-
}
|
|
4809
|
-
}
|
|
4810
|
-
}
|
|
4811
|
-
} catch (error) {
|
|
4812
|
-
errorFiles.push(relativePath);
|
|
4813
|
-
console.warn(`Error scanning ${relativePath}:`, error.message);
|
|
4814
|
-
}
|
|
4815
|
-
}
|
|
4816
|
-
if (useCache) {
|
|
4817
|
-
await saveCache(absoluteRoot, cache);
|
|
4818
|
-
}
|
|
4819
|
-
onProgress?.({
|
|
4820
|
-
current: totalFiles,
|
|
4821
|
-
total: totalFiles,
|
|
4822
|
-
currentFile: "",
|
|
4823
|
-
phase: "aggregating"
|
|
4824
|
-
});
|
|
4825
|
-
const analysis = aggregateAllUsages(allUsages, allImports, componentSources);
|
|
4826
|
-
analysis.rootDir = absoluteRoot;
|
|
4827
|
-
analysis.totalFiles = totalFiles;
|
|
4828
|
-
analysis.errorFiles = errorFiles;
|
|
4829
|
-
return analysis;
|
|
4830
|
-
}
|
|
4831
|
-
async function incrementalScan(rootDir, changes, existingCache, onProgress) {
|
|
4832
|
-
const absoluteRoot = resolve3(rootDir);
|
|
4833
|
-
const cache = { ...existingCache, files: { ...existingCache.files } };
|
|
4834
|
-
for (const filePath of changes.deleted) {
|
|
4835
|
-
removeCacheFile(cache, filePath);
|
|
4836
|
-
}
|
|
4837
|
-
const filesToScan = [...changes.added, ...changes.modified];
|
|
4838
|
-
const totalFiles = filesToScan.length;
|
|
4839
|
-
const allImports = [];
|
|
4840
|
-
const allUsages = [];
|
|
4841
|
-
const errorFiles = [];
|
|
4842
|
-
const componentSources = /* @__PURE__ */ new Map();
|
|
4843
|
-
for (const filePath of changes.unchanged) {
|
|
4844
|
-
const cachedEntry = getCachedFile(cache, filePath);
|
|
4845
|
-
if (cachedEntry) {
|
|
4846
|
-
allImports.push(...cachedEntry.imports);
|
|
4847
|
-
allUsages.push(...cachedEntry.usages);
|
|
4848
|
-
for (const imp of cachedEntry.imports) {
|
|
4849
|
-
if (!componentSources.has(imp.componentName)) {
|
|
4850
|
-
const sourceFile = resolveImportSource(filePath, imp.source);
|
|
4851
|
-
if (sourceFile) {
|
|
4852
|
-
componentSources.set(imp.componentName, sourceFile);
|
|
4853
|
-
}
|
|
4854
|
-
}
|
|
4855
|
-
}
|
|
4856
|
-
}
|
|
4857
|
-
}
|
|
4858
|
-
for (let i = 0; i < filesToScan.length; i++) {
|
|
4859
|
-
const filePath = filesToScan[i];
|
|
4860
|
-
const relativePath = relative2(absoluteRoot, filePath);
|
|
4861
|
-
onProgress?.({
|
|
4862
|
-
current: i + 1,
|
|
4863
|
-
total: totalFiles,
|
|
4864
|
-
currentFile: relativePath,
|
|
4865
|
-
phase: "scanning"
|
|
4866
|
-
});
|
|
4867
|
-
try {
|
|
4868
|
-
const content = await readFile6(filePath, "utf-8");
|
|
4869
|
-
const fileHash = computeFileHash(content);
|
|
4870
|
-
const { imports, usages } = await scanFile(filePath);
|
|
4871
|
-
updateCacheFile(cache, filePath, fileHash, imports, usages);
|
|
4872
|
-
allImports.push(...imports);
|
|
4873
|
-
allUsages.push(...usages);
|
|
4874
|
-
for (const imp of imports) {
|
|
4875
|
-
if (!componentSources.has(imp.componentName)) {
|
|
4876
|
-
const sourceFile = resolveImportSource(filePath, imp.source);
|
|
4877
|
-
if (sourceFile) {
|
|
4878
|
-
componentSources.set(imp.componentName, sourceFile);
|
|
4879
|
-
}
|
|
4880
|
-
}
|
|
4881
|
-
}
|
|
4882
|
-
} catch (error) {
|
|
4883
|
-
errorFiles.push(relativePath);
|
|
4884
|
-
}
|
|
4885
|
-
}
|
|
4886
|
-
await saveCache(absoluteRoot, cache);
|
|
4887
|
-
const analysis = aggregateAllUsages(allUsages, allImports, componentSources);
|
|
4888
|
-
analysis.rootDir = absoluteRoot;
|
|
4889
|
-
analysis.totalFiles = changes.unchanged.length + filesToScan.length;
|
|
4890
|
-
analysis.errorFiles = errorFiles;
|
|
4891
|
-
return { analysis, cache };
|
|
4892
|
-
}
|
|
4893
|
-
function resolveImportSource(importingFile, source) {
|
|
4894
|
-
if (!source.startsWith(".") && !source.startsWith("/")) {
|
|
4895
|
-
return null;
|
|
4896
|
-
}
|
|
4897
|
-
const importDir = dirname4(importingFile);
|
|
4898
|
-
const extensions = ["", ".tsx", ".ts", ".jsx", ".js", "/index.tsx", "/index.ts"];
|
|
4899
|
-
for (const ext of extensions) {
|
|
4900
|
-
const fullPath = resolve3(importDir, source + ext);
|
|
4901
|
-
if (ext === "" && source.endsWith(".tsx")) {
|
|
4902
|
-
return fullPath;
|
|
4903
|
-
}
|
|
4904
|
-
if (ext) {
|
|
4905
|
-
return resolve3(importDir, source) + ext;
|
|
4906
|
-
}
|
|
4907
|
-
}
|
|
4908
|
-
return resolve3(importDir, source);
|
|
4909
|
-
}
|
|
4910
|
-
function getScanStats(analysis) {
|
|
4911
|
-
const totalUsages = Object.values(analysis.components).reduce(
|
|
4912
|
-
(sum, c) => sum + c.totalUsages,
|
|
4913
|
-
0
|
|
4914
|
-
);
|
|
4915
|
-
const topComponents = Object.values(analysis.components).map((c) => ({ name: c.name, usages: c.totalUsages })).sort((a, b) => b.usages - a.usages).slice(0, 10);
|
|
4916
|
-
return {
|
|
4917
|
-
totalFiles: analysis.totalFiles,
|
|
4918
|
-
totalComponents: analysis.totalComponents,
|
|
4919
|
-
totalUsages,
|
|
4920
|
-
topComponents
|
|
4921
|
-
};
|
|
4922
|
-
}
|
|
4923
|
-
async function hasCachedAnalysis(rootDir) {
|
|
4924
|
-
const cache = await loadCache(resolve3(rootDir));
|
|
4925
|
-
if (!cache) return false;
|
|
4926
|
-
const stats = getCacheStats(cache);
|
|
4927
|
-
return stats.totalFiles > 0;
|
|
4928
|
-
}
|
|
4929
|
-
|
|
4930
|
-
// src/service/enhance/doc-extractor.ts
|
|
4931
|
-
import { parse as parse3 } from "@babel/parser";
|
|
4932
|
-
import _traverse2 from "@babel/traverse";
|
|
4933
|
-
import * as t3 from "@babel/types";
|
|
4934
|
-
import { readFile as readFile7 } from "fs/promises";
|
|
4935
|
-
import { existsSync as existsSync3 } from "fs";
|
|
4936
|
-
import { basename as basename2, dirname as dirname5, join as join4 } from "path";
|
|
4937
|
-
var traverse3 = _traverse2.default || _traverse2;
|
|
3759
|
+
import { basename, dirname as dirname3, join as join3 } from "path";
|
|
3760
|
+
var traverse2 = _traverse.default || _traverse;
|
|
4938
3761
|
async function extractComponentDocs(filePath) {
|
|
4939
|
-
const content = await
|
|
3762
|
+
const content = await readFile3(filePath, "utf-8");
|
|
4940
3763
|
return extractDocsFromSource(content, filePath);
|
|
4941
3764
|
}
|
|
4942
3765
|
function extractDocsFromSource(source, filePath) {
|
|
4943
3766
|
const isTypeScript = filePath.endsWith(".ts") || filePath.endsWith(".tsx");
|
|
4944
3767
|
const isJSX = filePath.endsWith(".tsx") || filePath.endsWith(".jsx");
|
|
4945
|
-
const ast =
|
|
3768
|
+
const ast = parse2(source, {
|
|
4946
3769
|
sourceType: "module",
|
|
4947
3770
|
plugins: [
|
|
4948
3771
|
...isTypeScript ? ["typescript"] : [],
|
|
@@ -4959,7 +3782,7 @@ function extractDocsFromSource(source, filePath) {
|
|
|
4959
3782
|
tags: {}
|
|
4960
3783
|
};
|
|
4961
3784
|
let mainExportComment;
|
|
4962
|
-
|
|
3785
|
+
traverse2(ast, {
|
|
4963
3786
|
// Extract JSDoc from function declarations
|
|
4964
3787
|
FunctionDeclaration(path) {
|
|
4965
3788
|
const leadingComments = path.node.leadingComments;
|
|
@@ -5095,7 +3918,7 @@ function processTag(docs, tag, content) {
|
|
|
5095
3918
|
function extractPropsFromInterface(node) {
|
|
5096
3919
|
const props = [];
|
|
5097
3920
|
for (const member of node.body.body) {
|
|
5098
|
-
if (
|
|
3921
|
+
if (t2.isTSPropertySignature(member) && t2.isIdentifier(member.key)) {
|
|
5099
3922
|
const name = member.key.name;
|
|
5100
3923
|
const type = member.typeAnnotation ? typeAnnotationToString(member.typeAnnotation.typeAnnotation) : "unknown";
|
|
5101
3924
|
const required = !member.optional;
|
|
@@ -5115,9 +3938,9 @@ function extractPropsFromInterface(node) {
|
|
|
5115
3938
|
}
|
|
5116
3939
|
function extractPropsFromTypeAlias(node) {
|
|
5117
3940
|
const props = [];
|
|
5118
|
-
if (
|
|
3941
|
+
if (t2.isTSTypeLiteral(node.typeAnnotation)) {
|
|
5119
3942
|
for (const member of node.typeAnnotation.members) {
|
|
5120
|
-
if (
|
|
3943
|
+
if (t2.isTSPropertySignature(member) && t2.isIdentifier(member.key)) {
|
|
5121
3944
|
const name = member.key.name;
|
|
5122
3945
|
const type = member.typeAnnotation ? typeAnnotationToString(member.typeAnnotation.typeAnnotation) : "unknown";
|
|
5123
3946
|
const required = !member.optional;
|
|
@@ -5133,23 +3956,23 @@ function extractPropsFromTypeAlias(node) {
|
|
|
5133
3956
|
return props;
|
|
5134
3957
|
}
|
|
5135
3958
|
function typeAnnotationToString(node) {
|
|
5136
|
-
if (
|
|
5137
|
-
if (
|
|
5138
|
-
if (
|
|
5139
|
-
if (
|
|
5140
|
-
if (
|
|
5141
|
-
if (
|
|
5142
|
-
if (
|
|
5143
|
-
if (
|
|
5144
|
-
if (
|
|
5145
|
-
if (
|
|
5146
|
-
if (
|
|
5147
|
-
if (
|
|
5148
|
-
if (
|
|
3959
|
+
if (t2.isTSStringKeyword(node)) return "string";
|
|
3960
|
+
if (t2.isTSNumberKeyword(node)) return "number";
|
|
3961
|
+
if (t2.isTSBooleanKeyword(node)) return "boolean";
|
|
3962
|
+
if (t2.isTSNullKeyword(node)) return "null";
|
|
3963
|
+
if (t2.isTSUndefinedKeyword(node)) return "undefined";
|
|
3964
|
+
if (t2.isTSVoidKeyword(node)) return "void";
|
|
3965
|
+
if (t2.isTSAnyKeyword(node)) return "any";
|
|
3966
|
+
if (t2.isTSNeverKeyword(node)) return "never";
|
|
3967
|
+
if (t2.isTSUnknownKeyword(node)) return "unknown";
|
|
3968
|
+
if (t2.isTSLiteralType(node)) {
|
|
3969
|
+
if (t2.isStringLiteral(node.literal)) return `"${node.literal.value}"`;
|
|
3970
|
+
if (t2.isNumericLiteral(node.literal)) return String(node.literal.value);
|
|
3971
|
+
if (t2.isBooleanLiteral(node.literal)) return String(node.literal.value);
|
|
5149
3972
|
return "literal";
|
|
5150
3973
|
}
|
|
5151
|
-
if (
|
|
5152
|
-
if (
|
|
3974
|
+
if (t2.isTSTypeReference(node)) {
|
|
3975
|
+
if (t2.isIdentifier(node.typeName)) {
|
|
5153
3976
|
const name = node.typeName.name;
|
|
5154
3977
|
if (node.typeParameters) {
|
|
5155
3978
|
const params = node.typeParameters.params.map(typeAnnotationToString).join(", ");
|
|
@@ -5158,28 +3981,28 @@ function typeAnnotationToString(node) {
|
|
|
5158
3981
|
return name;
|
|
5159
3982
|
}
|
|
5160
3983
|
}
|
|
5161
|
-
if (
|
|
3984
|
+
if (t2.isTSUnionType(node)) {
|
|
5162
3985
|
return node.types.map(typeAnnotationToString).join(" | ");
|
|
5163
3986
|
}
|
|
5164
|
-
if (
|
|
3987
|
+
if (t2.isTSIntersectionType(node)) {
|
|
5165
3988
|
return node.types.map(typeAnnotationToString).join(" & ");
|
|
5166
3989
|
}
|
|
5167
|
-
if (
|
|
3990
|
+
if (t2.isTSArrayType(node)) {
|
|
5168
3991
|
return `${typeAnnotationToString(node.elementType)}[]`;
|
|
5169
3992
|
}
|
|
5170
|
-
if (
|
|
3993
|
+
if (t2.isTSFunctionType(node)) {
|
|
5171
3994
|
return "(...args: any[]) => any";
|
|
5172
3995
|
}
|
|
5173
|
-
if (
|
|
3996
|
+
if (t2.isTSTupleType(node)) {
|
|
5174
3997
|
const elements = node.elementTypes.map((el) => {
|
|
5175
|
-
if (
|
|
3998
|
+
if (t2.isTSNamedTupleMember(el)) {
|
|
5176
3999
|
return typeAnnotationToString(el.elementType);
|
|
5177
4000
|
}
|
|
5178
4001
|
return typeAnnotationToString(el);
|
|
5179
4002
|
}).join(", ");
|
|
5180
4003
|
return `[${elements}]`;
|
|
5181
4004
|
}
|
|
5182
|
-
if (
|
|
4005
|
+
if (t2.isTSTypeLiteral(node)) {
|
|
5183
4006
|
return "object";
|
|
5184
4007
|
}
|
|
5185
4008
|
return "unknown";
|
|
@@ -5189,28 +4012,28 @@ function isPropsInterface(name) {
|
|
|
5189
4012
|
}
|
|
5190
4013
|
function isExportedComponent(path) {
|
|
5191
4014
|
const parent = path.parent;
|
|
5192
|
-
if (
|
|
5193
|
-
if (
|
|
5194
|
-
if (
|
|
4015
|
+
if (t2.isExportDefaultDeclaration(parent)) return true;
|
|
4016
|
+
if (t2.isExportNamedDeclaration(parent)) return true;
|
|
4017
|
+
if (t2.isProgram(parent) && path.node.id && /^[A-Z]/.test(path.node.id.name)) {
|
|
5195
4018
|
return true;
|
|
5196
4019
|
}
|
|
5197
4020
|
return false;
|
|
5198
4021
|
}
|
|
5199
4022
|
function hasExportedArrowFunction(path) {
|
|
5200
4023
|
const parent = path.parent;
|
|
5201
|
-
if (!
|
|
4024
|
+
if (!t2.isExportNamedDeclaration(parent)) return false;
|
|
5202
4025
|
for (const declarator of path.node.declarations) {
|
|
5203
|
-
if (
|
|
4026
|
+
if (t2.isIdentifier(declarator.id) && /^[A-Z]/.test(declarator.id.name) && (t2.isArrowFunctionExpression(declarator.init) || t2.isFunctionExpression(declarator.init))) {
|
|
5204
4027
|
return true;
|
|
5205
4028
|
}
|
|
5206
4029
|
}
|
|
5207
4030
|
return false;
|
|
5208
4031
|
}
|
|
5209
4032
|
function inferComponentName(filePath) {
|
|
5210
|
-
const fileName =
|
|
4033
|
+
const fileName = basename(filePath);
|
|
5211
4034
|
let name = fileName.replace(/\.(tsx?|jsx?)$/, "");
|
|
5212
4035
|
if (name === "index") {
|
|
5213
|
-
name =
|
|
4036
|
+
name = basename(dirname3(filePath));
|
|
5214
4037
|
}
|
|
5215
4038
|
return name;
|
|
5216
4039
|
}
|
|
@@ -5249,8 +4072,8 @@ async function findComponentSource(componentName, searchDirs) {
|
|
|
5249
4072
|
];
|
|
5250
4073
|
for (const dir of searchDirs) {
|
|
5251
4074
|
for (const pattern of patterns) {
|
|
5252
|
-
const fullPath =
|
|
5253
|
-
if (
|
|
4075
|
+
const fullPath = join3(dir, pattern);
|
|
4076
|
+
if (existsSync2(fullPath)) {
|
|
5254
4077
|
return fullPath;
|
|
5255
4078
|
}
|
|
5256
4079
|
}
|
|
@@ -5275,21 +4098,21 @@ async function extractAllComponentDocs(componentFiles) {
|
|
|
5275
4098
|
}
|
|
5276
4099
|
|
|
5277
4100
|
// src/service/enhance/storybook-parser.ts
|
|
5278
|
-
import { parse as
|
|
5279
|
-
import
|
|
5280
|
-
import * as
|
|
5281
|
-
import { readFile as
|
|
5282
|
-
import
|
|
5283
|
-
import { basename as
|
|
5284
|
-
var
|
|
4101
|
+
import { parse as parse3 } from "@babel/parser";
|
|
4102
|
+
import _traverse2 from "@babel/traverse";
|
|
4103
|
+
import * as t3 from "@babel/types";
|
|
4104
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
4105
|
+
import fg from "fast-glob";
|
|
4106
|
+
import { basename as basename2, relative } from "path";
|
|
4107
|
+
var traverse3 = _traverse2.default || _traverse2;
|
|
5285
4108
|
async function parseStoryFile(filePath) {
|
|
5286
|
-
const content = await
|
|
4109
|
+
const content = await readFile4(filePath, "utf-8");
|
|
5287
4110
|
return parseStorySource(content, filePath);
|
|
5288
4111
|
}
|
|
5289
4112
|
function parseStorySource(source, filePath) {
|
|
5290
4113
|
const isTypeScript = filePath.endsWith(".ts") || filePath.endsWith(".tsx");
|
|
5291
4114
|
const isJSX = filePath.endsWith(".tsx") || filePath.endsWith(".jsx");
|
|
5292
|
-
const ast =
|
|
4115
|
+
const ast = parse3(source, {
|
|
5293
4116
|
sourceType: "module",
|
|
5294
4117
|
plugins: [
|
|
5295
4118
|
...isTypeScript ? ["typescript"] : [],
|
|
@@ -5305,7 +4128,7 @@ function parseStorySource(source, filePath) {
|
|
|
5305
4128
|
stories: []
|
|
5306
4129
|
};
|
|
5307
4130
|
let defaultExportNode = null;
|
|
5308
|
-
|
|
4131
|
+
traverse3(ast, {
|
|
5309
4132
|
ExportDefaultDeclaration(path) {
|
|
5310
4133
|
defaultExportNode = path.node.declaration;
|
|
5311
4134
|
}
|
|
@@ -5316,12 +4139,12 @@ function parseStorySource(source, filePath) {
|
|
|
5316
4139
|
result.meta = parseMetaObject(metaObject, result.meta.componentName);
|
|
5317
4140
|
}
|
|
5318
4141
|
}
|
|
5319
|
-
|
|
4142
|
+
traverse3(ast, {
|
|
5320
4143
|
ExportNamedDeclaration(path) {
|
|
5321
4144
|
const declaration = path.node.declaration;
|
|
5322
|
-
if (
|
|
4145
|
+
if (t3.isVariableDeclaration(declaration)) {
|
|
5323
4146
|
for (const declarator of declaration.declarations) {
|
|
5324
|
-
if (!
|
|
4147
|
+
if (!t3.isIdentifier(declarator.id)) continue;
|
|
5325
4148
|
const storyName = declarator.id.name;
|
|
5326
4149
|
if (!/^[A-Z]/.test(storyName)) continue;
|
|
5327
4150
|
const story = parseStoryDeclarator(
|
|
@@ -5346,25 +4169,25 @@ function parseStorySource(source, filePath) {
|
|
|
5346
4169
|
return result;
|
|
5347
4170
|
}
|
|
5348
4171
|
function extractMetaObject(node, ast) {
|
|
5349
|
-
if (
|
|
4172
|
+
if (t3.isObjectExpression(node)) {
|
|
5350
4173
|
return node;
|
|
5351
4174
|
}
|
|
5352
|
-
if (
|
|
4175
|
+
if (t3.isIdentifier(node)) {
|
|
5353
4176
|
const metaName = node.name;
|
|
5354
4177
|
let foundObject = null;
|
|
5355
|
-
|
|
4178
|
+
traverse3(ast, {
|
|
5356
4179
|
VariableDeclarator(path) {
|
|
5357
|
-
if (
|
|
4180
|
+
if (t3.isIdentifier(path.node.id) && path.node.id.name === metaName && t3.isObjectExpression(path.node.init)) {
|
|
5358
4181
|
foundObject = path.node.init;
|
|
5359
4182
|
}
|
|
5360
4183
|
}
|
|
5361
4184
|
});
|
|
5362
4185
|
return foundObject;
|
|
5363
4186
|
}
|
|
5364
|
-
if (
|
|
4187
|
+
if (t3.isTSAsExpression(node) && t3.isObjectExpression(node.expression)) {
|
|
5365
4188
|
return node.expression;
|
|
5366
4189
|
}
|
|
5367
|
-
if (
|
|
4190
|
+
if (t3.isTSSatisfiesExpression && t3.isTSSatisfiesExpression(node) && t3.isObjectExpression(node.expression)) {
|
|
5368
4191
|
return node.expression;
|
|
5369
4192
|
}
|
|
5370
4193
|
return null;
|
|
@@ -5374,23 +4197,23 @@ function parseMetaObject(obj, fallbackName) {
|
|
|
5374
4197
|
componentName: fallbackName
|
|
5375
4198
|
};
|
|
5376
4199
|
for (const prop of obj.properties) {
|
|
5377
|
-
if (!
|
|
4200
|
+
if (!t3.isObjectProperty(prop) || !t3.isIdentifier(prop.key)) continue;
|
|
5378
4201
|
const key = prop.key.name;
|
|
5379
4202
|
switch (key) {
|
|
5380
4203
|
case "title":
|
|
5381
|
-
if (
|
|
4204
|
+
if (t3.isStringLiteral(prop.value)) {
|
|
5382
4205
|
meta.title = prop.value.value;
|
|
5383
4206
|
const parts = meta.title.split("/");
|
|
5384
4207
|
meta.componentName = parts[parts.length - 1];
|
|
5385
4208
|
}
|
|
5386
4209
|
break;
|
|
5387
4210
|
case "component":
|
|
5388
|
-
if (
|
|
4211
|
+
if (t3.isIdentifier(prop.value)) {
|
|
5389
4212
|
meta.componentName = prop.value.name;
|
|
5390
4213
|
}
|
|
5391
4214
|
break;
|
|
5392
4215
|
case "parameters":
|
|
5393
|
-
if (
|
|
4216
|
+
if (t3.isObjectExpression(prop.value)) {
|
|
5394
4217
|
meta.parameters = extractObjectLiteral(prop.value);
|
|
5395
4218
|
const docs = meta.parameters?.docs;
|
|
5396
4219
|
if (docs?.description) {
|
|
@@ -5402,7 +4225,7 @@ function parseMetaObject(obj, fallbackName) {
|
|
|
5402
4225
|
}
|
|
5403
4226
|
break;
|
|
5404
4227
|
case "argTypes":
|
|
5405
|
-
if (
|
|
4228
|
+
if (t3.isObjectExpression(prop.value)) {
|
|
5406
4229
|
meta.argTypes = parseArgTypes(prop.value);
|
|
5407
4230
|
}
|
|
5408
4231
|
break;
|
|
@@ -5413,29 +4236,29 @@ function parseMetaObject(obj, fallbackName) {
|
|
|
5413
4236
|
function parseArgTypes(obj) {
|
|
5414
4237
|
const argTypes = {};
|
|
5415
4238
|
for (const prop of obj.properties) {
|
|
5416
|
-
if (!
|
|
4239
|
+
if (!t3.isObjectProperty(prop) || !t3.isIdentifier(prop.key)) continue;
|
|
5417
4240
|
const propName = prop.key.name;
|
|
5418
4241
|
const argType = {};
|
|
5419
|
-
if (
|
|
4242
|
+
if (t3.isObjectExpression(prop.value)) {
|
|
5420
4243
|
for (const inner of prop.value.properties) {
|
|
5421
|
-
if (!
|
|
4244
|
+
if (!t3.isObjectProperty(inner) || !t3.isIdentifier(inner.key)) continue;
|
|
5422
4245
|
const innerKey = inner.key.name;
|
|
5423
|
-
if (innerKey === "description" &&
|
|
4246
|
+
if (innerKey === "description" && t3.isStringLiteral(inner.value)) {
|
|
5424
4247
|
argType.description = inner.value.value;
|
|
5425
4248
|
}
|
|
5426
4249
|
if (innerKey === "defaultValue") {
|
|
5427
4250
|
argType.defaultValue = extractLiteralValue(inner.value);
|
|
5428
4251
|
}
|
|
5429
4252
|
if (innerKey === "control") {
|
|
5430
|
-
if (
|
|
4253
|
+
if (t3.isStringLiteral(inner.value)) {
|
|
5431
4254
|
argType.control = inner.value.value;
|
|
5432
|
-
} else if (
|
|
4255
|
+
} else if (t3.isObjectExpression(inner.value)) {
|
|
5433
4256
|
const controlObj = extractObjectLiteral(inner.value);
|
|
5434
4257
|
argType.control = controlObj?.type;
|
|
5435
4258
|
}
|
|
5436
4259
|
}
|
|
5437
|
-
if (innerKey === "options" &&
|
|
5438
|
-
argType.options = inner.value.elements.filter((el) =>
|
|
4260
|
+
if (innerKey === "options" && t3.isArrayExpression(inner.value)) {
|
|
4261
|
+
argType.options = inner.value.elements.filter((el) => t3.isStringLiteral(el)).map((el) => el.value);
|
|
5439
4262
|
}
|
|
5440
4263
|
}
|
|
5441
4264
|
}
|
|
@@ -5453,25 +4276,25 @@ function parseStoryDeclarator(name, declarator, source, componentName) {
|
|
|
5453
4276
|
code: "",
|
|
5454
4277
|
isDefault: false
|
|
5455
4278
|
};
|
|
5456
|
-
if (
|
|
4279
|
+
if (t3.isObjectExpression(init)) {
|
|
5457
4280
|
parseStoryObject(init, story);
|
|
5458
4281
|
story.code = generateStoryCode(componentName, story.args);
|
|
5459
4282
|
return story;
|
|
5460
4283
|
}
|
|
5461
|
-
if (
|
|
4284
|
+
if (t3.isTSAsExpression(init) && t3.isObjectExpression(init.expression)) {
|
|
5462
4285
|
parseStoryObject(init.expression, story);
|
|
5463
4286
|
story.code = generateStoryCode(componentName, story.args);
|
|
5464
4287
|
return story;
|
|
5465
4288
|
}
|
|
5466
|
-
if (
|
|
4289
|
+
if (t3.isArrowFunctionExpression(init) || t3.isFunctionExpression(init)) {
|
|
5467
4290
|
if (init.start != null && init.end != null) {
|
|
5468
4291
|
const fnCode = source.slice(init.start, init.end);
|
|
5469
4292
|
story.code = fnCode;
|
|
5470
4293
|
}
|
|
5471
4294
|
return story;
|
|
5472
4295
|
}
|
|
5473
|
-
if (
|
|
5474
|
-
if (
|
|
4296
|
+
if (t3.isTSSatisfiesExpression && t3.isTSSatisfiesExpression(init)) {
|
|
4297
|
+
if (t3.isObjectExpression(init.expression)) {
|
|
5475
4298
|
parseStoryObject(init.expression, story);
|
|
5476
4299
|
story.code = generateStoryCode(componentName, story.args);
|
|
5477
4300
|
return story;
|
|
@@ -5481,21 +4304,21 @@ function parseStoryDeclarator(name, declarator, source, componentName) {
|
|
|
5481
4304
|
}
|
|
5482
4305
|
function parseStoryObject(obj, story) {
|
|
5483
4306
|
for (const prop of obj.properties) {
|
|
5484
|
-
if (!
|
|
4307
|
+
if (!t3.isObjectProperty(prop) || !t3.isIdentifier(prop.key)) continue;
|
|
5485
4308
|
const key = prop.key.name;
|
|
5486
4309
|
switch (key) {
|
|
5487
4310
|
case "name":
|
|
5488
|
-
if (
|
|
4311
|
+
if (t3.isStringLiteral(prop.value)) {
|
|
5489
4312
|
story.displayName = prop.value.value;
|
|
5490
4313
|
}
|
|
5491
4314
|
break;
|
|
5492
4315
|
case "args":
|
|
5493
|
-
if (
|
|
4316
|
+
if (t3.isObjectExpression(prop.value)) {
|
|
5494
4317
|
story.args = extractObjectLiteral(prop.value);
|
|
5495
4318
|
}
|
|
5496
4319
|
break;
|
|
5497
4320
|
case "parameters":
|
|
5498
|
-
if (
|
|
4321
|
+
if (t3.isObjectExpression(prop.value)) {
|
|
5499
4322
|
const params = extractObjectLiteral(prop.value);
|
|
5500
4323
|
const docs = params?.docs;
|
|
5501
4324
|
if (docs?.description) {
|
|
@@ -5510,15 +4333,15 @@ function parseStoryObject(obj, story) {
|
|
|
5510
4333
|
}
|
|
5511
4334
|
}
|
|
5512
4335
|
function extractLiteralValue(node) {
|
|
5513
|
-
if (
|
|
5514
|
-
if (
|
|
5515
|
-
if (
|
|
5516
|
-
if (
|
|
5517
|
-
if (
|
|
5518
|
-
if (
|
|
5519
|
-
return node.elements.filter((el) => el !== null &&
|
|
5520
|
-
}
|
|
5521
|
-
if (
|
|
4336
|
+
if (t3.isStringLiteral(node)) return node.value;
|
|
4337
|
+
if (t3.isNumericLiteral(node)) return node.value;
|
|
4338
|
+
if (t3.isBooleanLiteral(node)) return node.value;
|
|
4339
|
+
if (t3.isNullLiteral(node)) return null;
|
|
4340
|
+
if (t3.isIdentifier(node) && node.name === "undefined") return void 0;
|
|
4341
|
+
if (t3.isArrayExpression(node)) {
|
|
4342
|
+
return node.elements.filter((el) => el !== null && t3.isExpression(el)).map(extractLiteralValue);
|
|
4343
|
+
}
|
|
4344
|
+
if (t3.isObjectExpression(node)) {
|
|
5522
4345
|
return extractObjectLiteral(node);
|
|
5523
4346
|
}
|
|
5524
4347
|
return void 0;
|
|
@@ -5526,12 +4349,12 @@ function extractLiteralValue(node) {
|
|
|
5526
4349
|
function extractObjectLiteral(node) {
|
|
5527
4350
|
const obj = {};
|
|
5528
4351
|
for (const prop of node.properties) {
|
|
5529
|
-
if (
|
|
5530
|
-
if (!
|
|
4352
|
+
if (t3.isSpreadElement(prop)) continue;
|
|
4353
|
+
if (!t3.isObjectProperty(prop)) continue;
|
|
5531
4354
|
let key;
|
|
5532
|
-
if (
|
|
4355
|
+
if (t3.isIdentifier(prop.key)) {
|
|
5533
4356
|
key = prop.key.name;
|
|
5534
|
-
} else if (
|
|
4357
|
+
} else if (t3.isStringLiteral(prop.key)) {
|
|
5535
4358
|
key = prop.key.value;
|
|
5536
4359
|
} else {
|
|
5537
4360
|
continue;
|
|
@@ -5559,12 +4382,12 @@ function camelToTitle(str) {
|
|
|
5559
4382
|
return str.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase()).trim();
|
|
5560
4383
|
}
|
|
5561
4384
|
function inferComponentFromPath(filePath) {
|
|
5562
|
-
const fileName =
|
|
4385
|
+
const fileName = basename2(filePath);
|
|
5563
4386
|
const name = fileName.replace(/\.stories\.(tsx?|jsx?|mdx?)$/, "");
|
|
5564
4387
|
return name;
|
|
5565
4388
|
}
|
|
5566
4389
|
async function findStoryFiles(rootDir, include = ["**/*.stories.{tsx,ts,jsx,js}"], exclude = ["**/node_modules/**", "**/dist/**"]) {
|
|
5567
|
-
return
|
|
4390
|
+
return fg(include, {
|
|
5568
4391
|
cwd: rootDir,
|
|
5569
4392
|
ignore: exclude,
|
|
5570
4393
|
absolute: true,
|
|
@@ -5580,7 +4403,7 @@ async function parseAllStories(rootDir) {
|
|
|
5580
4403
|
results.set(parsed.meta.componentName, parsed);
|
|
5581
4404
|
} catch (error) {
|
|
5582
4405
|
console.warn(
|
|
5583
|
-
`Failed to parse story file ${
|
|
4406
|
+
`Failed to parse story file ${relative(rootDir, filePath)}:`,
|
|
5584
4407
|
error.message
|
|
5585
4408
|
);
|
|
5586
4409
|
}
|
|
@@ -5918,12 +4741,12 @@ If there isn't enough usage data to make confident recommendations, indicate tha
|
|
|
5918
4741
|
|
|
5919
4742
|
// src/service/enhance/props-extractor.ts
|
|
5920
4743
|
import * as ts from "typescript";
|
|
5921
|
-
import { readFile as
|
|
5922
|
-
import { existsSync as
|
|
5923
|
-
import { basename as
|
|
4744
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
4745
|
+
import { existsSync as existsSync3 } from "fs";
|
|
4746
|
+
import { basename as basename3, dirname as dirname5, join as join5, resolve as resolve2 } from "path";
|
|
5924
4747
|
async function extractPropsFromFile(filePath, options = {}) {
|
|
5925
|
-
const absPath =
|
|
5926
|
-
if (!
|
|
4748
|
+
const absPath = resolve2(filePath);
|
|
4749
|
+
if (!existsSync3(absPath)) {
|
|
5927
4750
|
return {
|
|
5928
4751
|
filePath: absPath,
|
|
5929
4752
|
componentName: inferComponentName2(absPath),
|
|
@@ -5932,7 +4755,7 @@ async function extractPropsFromFile(filePath, options = {}) {
|
|
|
5932
4755
|
warnings: [`File not found: ${absPath}`]
|
|
5933
4756
|
};
|
|
5934
4757
|
}
|
|
5935
|
-
const content = await
|
|
4758
|
+
const content = await readFile5(absPath, "utf-8");
|
|
5936
4759
|
return extractPropsFromSource(content, absPath, options);
|
|
5937
4760
|
}
|
|
5938
4761
|
function extractPropsFromSource(source, filePath, options = {}) {
|
|
@@ -6221,8 +5044,19 @@ function extractPropsFromInlineParams(componentName, sourceFile) {
|
|
|
6221
5044
|
}
|
|
6222
5045
|
if (ts.isVariableStatement(node)) {
|
|
6223
5046
|
for (const decl of node.declarationList.declarations) {
|
|
6224
|
-
if (ts.isIdentifier(decl.name) && decl.name.text === componentName && decl.initializer
|
|
6225
|
-
|
|
5047
|
+
if (ts.isIdentifier(decl.name) && decl.name.text === componentName && decl.initializer) {
|
|
5048
|
+
if (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer)) {
|
|
5049
|
+
targetFunc = decl.initializer;
|
|
5050
|
+
} else if (ts.isCallExpression(decl.initializer)) {
|
|
5051
|
+
const callee = decl.initializer.expression;
|
|
5052
|
+
const isForwardRef = ts.isPropertyAccessExpression(callee) && callee.name.text === "forwardRef" || ts.isIdentifier(callee) && callee.text === "forwardRef";
|
|
5053
|
+
if (isForwardRef && decl.initializer.arguments.length > 0) {
|
|
5054
|
+
const firstArg = decl.initializer.arguments[0];
|
|
5055
|
+
if (ts.isArrowFunction(firstArg) || ts.isFunctionExpression(firstArg)) {
|
|
5056
|
+
targetFunc = firstArg;
|
|
5057
|
+
}
|
|
5058
|
+
}
|
|
5059
|
+
}
|
|
6226
5060
|
}
|
|
6227
5061
|
}
|
|
6228
5062
|
}
|
|
@@ -6340,12 +5174,12 @@ function extractCvaVariants(sourceFile, props) {
|
|
|
6340
5174
|
}
|
|
6341
5175
|
}
|
|
6342
5176
|
function inferComponentName2(filePath) {
|
|
6343
|
-
const fileName =
|
|
5177
|
+
const fileName = basename3(filePath);
|
|
6344
5178
|
let name = fileName.replace(/\.(tsx?|jsx?)$/, "");
|
|
6345
5179
|
if (name === "index") {
|
|
6346
|
-
name =
|
|
5180
|
+
name = basename3(dirname5(filePath));
|
|
6347
5181
|
}
|
|
6348
|
-
return name;
|
|
5182
|
+
return name.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join("");
|
|
6349
5183
|
}
|
|
6350
5184
|
function convertToFragmentProps(props) {
|
|
6351
5185
|
const result = {};
|
|
@@ -6391,10 +5225,11 @@ async function extractPropsForComponent(componentName, searchDirs) {
|
|
|
6391
5225
|
];
|
|
6392
5226
|
for (const dir of searchDirs) {
|
|
6393
5227
|
for (const pattern of patterns) {
|
|
6394
|
-
const fullPath =
|
|
6395
|
-
if (
|
|
5228
|
+
const fullPath = join5(dir, pattern);
|
|
5229
|
+
if (existsSync3(fullPath)) {
|
|
6396
5230
|
return extractPropsFromFile(fullPath, {
|
|
6397
|
-
propsTypeName: `${componentName}Props
|
|
5231
|
+
propsTypeName: `${componentName}Props`,
|
|
5232
|
+
componentName
|
|
6398
5233
|
});
|
|
6399
5234
|
}
|
|
6400
5235
|
}
|
|
@@ -6406,7 +5241,8 @@ async function extractAllComponentProps(componentFiles) {
|
|
|
6406
5241
|
for (const [componentName, filePath] of componentFiles) {
|
|
6407
5242
|
try {
|
|
6408
5243
|
const extraction = await extractPropsFromFile(filePath, {
|
|
6409
|
-
propsTypeName: `${componentName}Props
|
|
5244
|
+
propsTypeName: `${componentName}Props`,
|
|
5245
|
+
componentName
|
|
6410
5246
|
});
|
|
6411
5247
|
results.set(componentName, extraction);
|
|
6412
5248
|
} catch (error) {
|
|
@@ -6709,12 +5545,6 @@ export {
|
|
|
6709
5545
|
getGrade,
|
|
6710
5546
|
getScoreColor,
|
|
6711
5547
|
generateHtmlReport,
|
|
6712
|
-
parseTokenFile,
|
|
6713
|
-
parseTokenFiles,
|
|
6714
|
-
hexToRgb,
|
|
6715
|
-
rgbToHex,
|
|
6716
|
-
parseRgb,
|
|
6717
|
-
normalizeColor,
|
|
6718
5548
|
TokenRegistryManager,
|
|
6719
5549
|
getSharedTokenRegistry,
|
|
6720
5550
|
initializeSharedRegistry,
|
|
@@ -6730,25 +5560,6 @@ export {
|
|
|
6730
5560
|
applyPatches,
|
|
6731
5561
|
MetricsStore,
|
|
6732
5562
|
createMetricsStore,
|
|
6733
|
-
scanFileForImports,
|
|
6734
|
-
scanFileForUsages,
|
|
6735
|
-
scanFile,
|
|
6736
|
-
aggregateComponentUsages,
|
|
6737
|
-
aggregateAllUsages,
|
|
6738
|
-
findCommonPropCombinations,
|
|
6739
|
-
inferRelations,
|
|
6740
|
-
inferAllRelations,
|
|
6741
|
-
summarizePatternsForPrompt,
|
|
6742
|
-
loadCache,
|
|
6743
|
-
saveCache,
|
|
6744
|
-
createEmptyCache,
|
|
6745
|
-
computeFileHash,
|
|
6746
|
-
detectFileChanges,
|
|
6747
|
-
getCacheStats,
|
|
6748
|
-
scanCodebase,
|
|
6749
|
-
incrementalScan,
|
|
6750
|
-
getScanStats,
|
|
6751
|
-
hasCachedAnalysis,
|
|
6752
5563
|
extractComponentDocs,
|
|
6753
5564
|
extractDocsFromSource,
|
|
6754
5565
|
findComponentSource,
|
|
@@ -6776,4 +5587,4 @@ export {
|
|
|
6776
5587
|
getStorybookStoryIds,
|
|
6777
5588
|
renderAllComponentVariants
|
|
6778
5589
|
};
|
|
6779
|
-
//# sourceMappingURL=chunk-
|
|
5590
|
+
//# sourceMappingURL=chunk-6SQPP47U.js.map
|