@layoutdesign/context 0.4.0 → 0.5.0
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/bin/cli.js +10 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/src/cli/scan.d.ts +8 -0
- package/dist/src/cli/scan.d.ts.map +1 -0
- package/dist/src/cli/scan.js +143 -0
- package/dist/src/cli/scan.js.map +1 -0
- package/dist/src/integrations/codebase-scan.d.ts +46 -0
- package/dist/src/integrations/codebase-scan.d.ts.map +1 -0
- package/dist/src/integrations/codebase-scan.js +231 -0
- package/dist/src/integrations/codebase-scan.js.map +1 -0
- package/dist/src/integrations/storybook.d.ts +36 -0
- package/dist/src/integrations/storybook.d.ts.map +1 -0
- package/dist/src/integrations/storybook.js +124 -0
- package/dist/src/integrations/storybook.js.map +1 -0
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +17 -2
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/list-components.d.ts +2 -1
- package/dist/src/mcp/tools/list-components.d.ts.map +1 -1
- package/dist/src/mcp/tools/list-components.js +50 -24
- package/dist/src/mcp/tools/list-components.js.map +1 -1
- package/dist/src/mcp/tools/scan-project.d.ts +30 -0
- package/dist/src/mcp/tools/scan-project.d.ts.map +1 -0
- package/dist/src/mcp/tools/scan-project.js +97 -0
- package/dist/src/mcp/tools/scan-project.js.map +1 -0
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import { listCommand } from "../src/cli/list.js";
|
|
|
9
9
|
import { installCommand } from "../src/cli/install.js";
|
|
10
10
|
import { doctorCommand } from "../src/cli/doctor.js";
|
|
11
11
|
import { serveLocalCommand } from "../src/cli/serve-local.js";
|
|
12
|
+
import { scanCommand } from "../src/cli/scan.js";
|
|
12
13
|
const require = createRequire(import.meta.url);
|
|
13
14
|
const pkg = require("../../package.json");
|
|
14
15
|
const program = new Command();
|
|
@@ -75,5 +76,14 @@ program
|
|
|
75
76
|
.action(async (options) => {
|
|
76
77
|
await doctorCommand(options);
|
|
77
78
|
});
|
|
79
|
+
program
|
|
80
|
+
.command("scan [path]")
|
|
81
|
+
.description("Scan the codebase for React components and Storybook stories")
|
|
82
|
+
.option("--sync", "Upload results to your Layout project")
|
|
83
|
+
.option("--project <id>", "Layout project ID (auto-detected from .layout/ if not specified)")
|
|
84
|
+
.option("--type <type>", "Scan type: storybook, codebase, or both (default: both)")
|
|
85
|
+
.action(async (targetPath, options) => {
|
|
86
|
+
await scanCommand(targetPath, options);
|
|
87
|
+
});
|
|
78
88
|
program.parse();
|
|
79
89
|
//# sourceMappingURL=cli.js.map
|
package/dist/bin/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,oBAAoB,CAAwB,CAAC;AAEjE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,gBAAgB,CAAC;KACtB,WAAW,CACV,+DAA+D,CAChE;KACA,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,sDAAsD,CAAC;KACnE,MAAM,CAAC,cAAc,EAAE,kCAAkC,CAAC;KAC1D,MAAM,CAAC,KAAK,EAAE,OAAyB,EAAE,EAAE;IAC1C,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,YAAY,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,EAAE;IAChC,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,gBAAgB,CAAC;KACzB,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,EAAE;IAChC,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,gCAAgC,CAAC;KAC7C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,WAAW,EAAE,CAAC;AACtB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,uHAAuH,CAAC;KACpI,MAAM,CAAC,iBAAiB,EAAE,mEAAmE,CAAC;KAC9F,MAAM,CAAC,UAAU,EAAE,gEAAgE,CAAC;KACpF,MAAM,CAAC,cAAc,EAAE,qCAAqC,CAAC;KAC7D,MAAM,CAAC,KAAK,EAAE,OAAmE,EAAE,EAAE;IACpF,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,oBAAoB,CAAC;KAC7B,WAAW,CAAC,+GAA+G,CAAC;KAC5H,MAAM,CAAC,YAAY,EAAE,8CAA8C,CAAC;KACpE,MAAM,CAAC,SAAS,EAAE,2CAA2C,CAAC;KAC9D,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,OAA2C,EAAE,EAAE;IAChF,MAAM,iBAAiB,CAAC,UAAU,EAAE;QAClC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;QAC3D,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,2DAA2D,CAAC;KACxE,MAAM,CAAC,OAAO,EAAE,kCAAkC,CAAC;KACnD,MAAM,CAAC,WAAW,EAAE,+DAA+D,CAAC;KACpF,MAAM,CAAC,KAAK,EAAE,OAA6C,EAAE,EAAE;IAC9D,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,8DAA8D,CAAC;KAC3E,MAAM,CAAC,QAAQ,EAAE,uCAAuC,CAAC;KACzD,MAAM,CAAC,gBAAgB,EAAE,kEAAkE,CAAC;KAC5F,MAAM,CAAC,eAAe,EAAE,yDAAyD,CAAC;KAClF,MAAM,CAAC,KAAK,EAAE,UAAmB,EAAE,OAA6D,EAAE,EAAE;IACnG,MAAM,WAAW,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/cli/scan.ts"],"names":[],"mappings":"AAOA,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA4FD,wBAAsB,WAAW,CAC/B,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,IAAI,CAAC,CA0Cf"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { scanCodebase, scanStorybook } from "../integrations/codebase-scan.js";
|
|
5
|
+
import { LAYOUT_DIR } from "../kit/types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Read org and project IDs from the .layout/kit.json manifest.
|
|
8
|
+
* The layoutUrl field looks like: https://layout.design/<org>/<project>/studio
|
|
9
|
+
* or the manifest may have explicit orgId/projectId fields.
|
|
10
|
+
*/
|
|
11
|
+
function readProjectContext(rootPath) {
|
|
12
|
+
const manifestPath = resolve(rootPath, LAYOUT_DIR, "kit.json");
|
|
13
|
+
if (!existsSync(manifestPath))
|
|
14
|
+
return {};
|
|
15
|
+
try {
|
|
16
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
17
|
+
// Check explicit fields first
|
|
18
|
+
if (manifest.orgId && manifest.projectId) {
|
|
19
|
+
return { orgId: manifest.orgId, projectId: manifest.projectId, apiBase: manifest.apiBase };
|
|
20
|
+
}
|
|
21
|
+
// Try to parse from layoutUrl
|
|
22
|
+
if (manifest.layoutUrl) {
|
|
23
|
+
const url = new URL(manifest.layoutUrl);
|
|
24
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
25
|
+
// Expected: /<org>/<project>/studio or /<org>/<project>
|
|
26
|
+
if (parts.length >= 2) {
|
|
27
|
+
return { orgId: parts[0], projectId: parts[1] };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Ignore parse errors
|
|
33
|
+
}
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
function formatScanResult(result) {
|
|
37
|
+
const withStories = result.components.filter((c) => c.storybook);
|
|
38
|
+
console.log();
|
|
39
|
+
console.log(chalk.bold(`Scan complete`), chalk.dim(`(${result.durationMs}ms)`));
|
|
40
|
+
console.log();
|
|
41
|
+
console.log(` ${chalk.green(String(result.components.length))} components found`, result.storybookStories.length > 0
|
|
42
|
+
? chalk.dim(`(${withStories.length} with Storybook stories)`)
|
|
43
|
+
: "");
|
|
44
|
+
console.log(` ${chalk.green(String(result.storybookStories.length))} Storybook stories`);
|
|
45
|
+
console.log(` ${chalk.dim(String(result.filesScanned))} files scanned`);
|
|
46
|
+
if (result.unmatchedStories.length > 0) {
|
|
47
|
+
console.log(` ${chalk.yellow(String(result.unmatchedStories.length))} stories without matching components`);
|
|
48
|
+
}
|
|
49
|
+
// Show top components
|
|
50
|
+
if (result.components.length > 0) {
|
|
51
|
+
console.log();
|
|
52
|
+
console.log(chalk.bold("Components:"));
|
|
53
|
+
const display = result.components.slice(0, 20);
|
|
54
|
+
for (const comp of display) {
|
|
55
|
+
const propsCount = comp.props.length;
|
|
56
|
+
const storyIcon = comp.storybook ? chalk.blue(" [stories]") : "";
|
|
57
|
+
const refIcon = comp.usesForwardRef ? chalk.dim(" (forwardRef)") : "";
|
|
58
|
+
const propsLabel = propsCount > 0 ? chalk.dim(` ${propsCount} props`) : "";
|
|
59
|
+
console.log(` ${chalk.cyan(comp.name)}${propsLabel}${refIcon}${storyIcon}`, chalk.dim(`— ${comp.filePath}`));
|
|
60
|
+
}
|
|
61
|
+
if (result.components.length > 20) {
|
|
62
|
+
console.log(chalk.dim(` ... and ${result.components.length - 20} more`));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export async function scanCommand(targetPath, options) {
|
|
67
|
+
const rootPath = resolve(targetPath ?? process.cwd());
|
|
68
|
+
const scanType = options?.type ?? "both";
|
|
69
|
+
console.log();
|
|
70
|
+
console.log(chalk.bold("Layout Codebase Scanner"), chalk.dim(`— ${rootPath}`));
|
|
71
|
+
if (scanType === "storybook") {
|
|
72
|
+
console.log(chalk.dim(" Scanning for Storybook stories only..."));
|
|
73
|
+
const stories = await scanStorybook(rootPath);
|
|
74
|
+
console.log();
|
|
75
|
+
console.log(` ${chalk.green(String(stories.length))} Storybook stories found`);
|
|
76
|
+
for (const story of stories.slice(0, 20)) {
|
|
77
|
+
const storyNames = story.stories.map((s) => s.name).join(", ");
|
|
78
|
+
console.log(` ${chalk.cyan(story.componentName)}`, chalk.dim(`— ${storyNames}`), chalk.dim(`— ${story.filePath}`));
|
|
79
|
+
}
|
|
80
|
+
if (stories.length > 20) {
|
|
81
|
+
console.log(chalk.dim(` ... and ${stories.length - 20} more`));
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
console.log(chalk.dim(" Scanning..."));
|
|
86
|
+
const result = await scanCodebase(rootPath);
|
|
87
|
+
formatScanResult(result);
|
|
88
|
+
// Sync to Layout web app
|
|
89
|
+
if (options?.sync) {
|
|
90
|
+
await syncResults(rootPath, result, options.project);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function syncResults(rootPath, result, projectArg) {
|
|
94
|
+
console.log();
|
|
95
|
+
const context = readProjectContext(rootPath);
|
|
96
|
+
const orgId = context.orgId;
|
|
97
|
+
const projectId = projectArg ?? context.projectId;
|
|
98
|
+
const apiBase = (context.apiBase ?? "https://layout.design").replace(/\/$/, "");
|
|
99
|
+
if (!orgId || !projectId) {
|
|
100
|
+
console.log(chalk.red("Error:"), "Could not determine project to sync to.");
|
|
101
|
+
console.log(chalk.dim(" Add orgId and projectId to .layout/kit.json, or use --project <id>"));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const url = `${apiBase}/api/organizations/${orgId}/projects/${projectId}/scan-results`;
|
|
105
|
+
console.log(chalk.dim(` Syncing to ${url}...`));
|
|
106
|
+
try {
|
|
107
|
+
const apiKey = process.env.LAYOUT_API_KEY;
|
|
108
|
+
const headers = { "Content-Type": "application/json" };
|
|
109
|
+
if (apiKey)
|
|
110
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
111
|
+
const response = await fetch(url, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers,
|
|
114
|
+
body: JSON.stringify({
|
|
115
|
+
components: result.components.map((c) => ({
|
|
116
|
+
name: c.name,
|
|
117
|
+
filePath: c.filePath,
|
|
118
|
+
exportType: c.exportType,
|
|
119
|
+
propsType: c.propsInterfaceName,
|
|
120
|
+
props: c.props.map((p) => p.name),
|
|
121
|
+
usesForwardRef: c.usesForwardRef,
|
|
122
|
+
importPath: c.filePath.replace(/\.(tsx?|jsx?)$/, "").replace(/\/index$/, ""),
|
|
123
|
+
source: c.storybook ? "storybook" : "codebase",
|
|
124
|
+
stories: c.storybook?.stories.map((s) => s.name),
|
|
125
|
+
args: c.storybook?.args,
|
|
126
|
+
})),
|
|
127
|
+
source: "cli",
|
|
128
|
+
}),
|
|
129
|
+
});
|
|
130
|
+
if (response.ok) {
|
|
131
|
+
console.log(chalk.green(" Synced successfully."));
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
const text = await response.text();
|
|
135
|
+
console.log(chalk.red(" Sync failed:"), `${response.status} ${text}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
140
|
+
console.log(chalk.red(" Sync failed:"), msg);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/cli/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type StoryComponentMeta } from "./storybook.js";
|
|
2
|
+
export interface ScannedProp {
|
|
3
|
+
name: string;
|
|
4
|
+
type?: string;
|
|
5
|
+
optional?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface ScannedComponent {
|
|
8
|
+
/** PascalCase component name */
|
|
9
|
+
name: string;
|
|
10
|
+
/** File path relative to the scan root */
|
|
11
|
+
filePath: string;
|
|
12
|
+
/** How the component is exported */
|
|
13
|
+
exportType: "named" | "default";
|
|
14
|
+
/** Props interface/type name if detected */
|
|
15
|
+
propsInterfaceName?: string;
|
|
16
|
+
/** Individual prop keys extracted from the interface */
|
|
17
|
+
props: ScannedProp[];
|
|
18
|
+
/** Whether the component uses forwardRef */
|
|
19
|
+
usesForwardRef: boolean;
|
|
20
|
+
/** Storybook metadata if a matching .stories file was found */
|
|
21
|
+
storybook?: StoryComponentMeta;
|
|
22
|
+
}
|
|
23
|
+
export interface ScanResult {
|
|
24
|
+
/** Root directory that was scanned */
|
|
25
|
+
rootPath: string;
|
|
26
|
+
/** All detected React components */
|
|
27
|
+
components: ScannedComponent[];
|
|
28
|
+
/** Storybook stories that matched a component */
|
|
29
|
+
storybookStories: StoryComponentMeta[];
|
|
30
|
+
/** Stories that did not match any scanned component */
|
|
31
|
+
unmatchedStories: StoryComponentMeta[];
|
|
32
|
+
/** Total files scanned */
|
|
33
|
+
filesScanned: number;
|
|
34
|
+
/** Scan duration in milliseconds */
|
|
35
|
+
durationMs: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Scan a directory for React components and Storybook stories.
|
|
39
|
+
* Returns structured results with component metadata and story associations.
|
|
40
|
+
*/
|
|
41
|
+
export declare function scanCodebase(rootPath: string): Promise<ScanResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Scan for Storybook stories only.
|
|
44
|
+
*/
|
|
45
|
+
export declare function scanStorybook(rootPath: string): Promise<StoryComponentMeta[]>;
|
|
46
|
+
//# sourceMappingURL=codebase-scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codebase-scan.d.ts","sourceRoot":"","sources":["../../../src/integrations/codebase-scan.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,UAAU,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,4CAA4C;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wDAAwD;IACxD,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,4CAA4C;IAC5C,cAAc,EAAE,OAAO,CAAC;IACxB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,iDAAiD;IACjD,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;IACvC,uDAAuD;IACvD,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;IACvC,0BAA0B;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAqLD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAuExE;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAkB/B"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { join, relative, extname } from "node:path";
|
|
3
|
+
import { parseStoryFromPath, } from "./storybook.js";
|
|
4
|
+
// ── Constants ──────────────────────────────────────────────────────────────
|
|
5
|
+
const SKIP_DIRS = new Set([
|
|
6
|
+
"node_modules",
|
|
7
|
+
".next",
|
|
8
|
+
".nuxt",
|
|
9
|
+
"dist",
|
|
10
|
+
"build",
|
|
11
|
+
"out",
|
|
12
|
+
".git",
|
|
13
|
+
".layout",
|
|
14
|
+
".superduper",
|
|
15
|
+
"coverage",
|
|
16
|
+
"__tests__",
|
|
17
|
+
"__mocks__",
|
|
18
|
+
".turbo",
|
|
19
|
+
".cache",
|
|
20
|
+
".vercel",
|
|
21
|
+
".output",
|
|
22
|
+
]);
|
|
23
|
+
const COMPONENT_EXTENSIONS = new Set([".tsx", ".jsx"]);
|
|
24
|
+
const STORY_SUFFIXES = [".stories.ts", ".stories.tsx", ".stories.js", ".stories.jsx"];
|
|
25
|
+
// ── Regex patterns ─────────────────────────────────────────────────────────
|
|
26
|
+
// Named export: `export function Button(` or `export const Button =` or `export const Button: FC`
|
|
27
|
+
const NAMED_FUNCTION_RE = /export\s+function\s+([A-Z]\w+)\s*(?:<[^>]*>)?\s*\(/g;
|
|
28
|
+
const NAMED_CONST_RE = /export\s+const\s+([A-Z]\w+)\s*(?::\s*(?:React\.)?(?:FC|FunctionComponent|ComponentType)(?:<[^>]*>)?\s*)?=\s*/g;
|
|
29
|
+
// Default export: `export default function Button(`
|
|
30
|
+
const DEFAULT_FUNCTION_RE = /export\s+default\s+function\s+([A-Z]\w+)\s*(?:<[^>]*>)?\s*\(/g;
|
|
31
|
+
// forwardRef: `export const Button = forwardRef<` or `React.forwardRef<`
|
|
32
|
+
const FORWARD_REF_RE = /export\s+const\s+([A-Z]\w+)\s*=\s*(?:React\.)?forwardRef/g;
|
|
33
|
+
// Grouped export: `export { Button, Card, buttonVariants }` — capture PascalCase names only
|
|
34
|
+
const GROUPED_EXPORT_RE = /export\s*\{([^}]+)\}/g;
|
|
35
|
+
// Props interface: `interface ButtonProps {` or `type ButtonProps = {`
|
|
36
|
+
const PROPS_INTERFACE_RE = /(?:interface|type)\s+(\w+Props)\s*(?:=\s*)?\{([\s\S]*?)\n\}/g;
|
|
37
|
+
// Individual prop from interface body: ` label: string;` or ` disabled?: boolean;`
|
|
38
|
+
const PROP_LINE_RE = /^\s+(\w+)(\?)?\s*:\s*([^;]+)/gm;
|
|
39
|
+
// ── File discovery ─────────────────────────────────────────────────────────
|
|
40
|
+
function isStoryFile(filePath) {
|
|
41
|
+
return STORY_SUFFIXES.some((suffix) => filePath.endsWith(suffix));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Recursively walk a directory, yielding file paths.
|
|
45
|
+
* Skips directories in the SKIP_DIRS set.
|
|
46
|
+
*/
|
|
47
|
+
async function* walkDir(dir) {
|
|
48
|
+
let entries;
|
|
49
|
+
try {
|
|
50
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
const fullPath = join(dir, entry.name);
|
|
57
|
+
if (entry.isDirectory()) {
|
|
58
|
+
if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
|
|
59
|
+
yield* walkDir(fullPath);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else if (entry.isFile()) {
|
|
63
|
+
yield fullPath;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// ── Component extraction ───────────────────────────────────────────────────
|
|
68
|
+
function extractComponents(content, filePath) {
|
|
69
|
+
const components = [];
|
|
70
|
+
const seen = new Set();
|
|
71
|
+
// Extract all props interfaces/types from the file
|
|
72
|
+
const propsMap = new Map();
|
|
73
|
+
let propsMatch;
|
|
74
|
+
PROPS_INTERFACE_RE.lastIndex = 0;
|
|
75
|
+
while ((propsMatch = PROPS_INTERFACE_RE.exec(content)) !== null) {
|
|
76
|
+
const interfaceName = propsMatch[1];
|
|
77
|
+
const body = propsMatch[2] ?? "";
|
|
78
|
+
const props = [];
|
|
79
|
+
let propLineMatch;
|
|
80
|
+
PROP_LINE_RE.lastIndex = 0;
|
|
81
|
+
while ((propLineMatch = PROP_LINE_RE.exec(body)) !== null) {
|
|
82
|
+
props.push({
|
|
83
|
+
name: propLineMatch[1],
|
|
84
|
+
optional: propLineMatch[2] === "?",
|
|
85
|
+
type: propLineMatch[3]?.trim(),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
propsMap.set(interfaceName, props);
|
|
89
|
+
}
|
|
90
|
+
function addComponent(name, exportType, usesForwardRef) {
|
|
91
|
+
if (seen.has(name))
|
|
92
|
+
return;
|
|
93
|
+
seen.add(name);
|
|
94
|
+
// Try to find a matching props interface
|
|
95
|
+
const propsInterfaceName = `${name}Props`;
|
|
96
|
+
const props = propsMap.get(propsInterfaceName) ?? [];
|
|
97
|
+
components.push({
|
|
98
|
+
name,
|
|
99
|
+
filePath,
|
|
100
|
+
exportType,
|
|
101
|
+
propsInterfaceName: propsMap.has(propsInterfaceName)
|
|
102
|
+
? propsInterfaceName
|
|
103
|
+
: undefined,
|
|
104
|
+
props,
|
|
105
|
+
usesForwardRef,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// Named function exports
|
|
109
|
+
let match;
|
|
110
|
+
NAMED_FUNCTION_RE.lastIndex = 0;
|
|
111
|
+
while ((match = NAMED_FUNCTION_RE.exec(content)) !== null) {
|
|
112
|
+
addComponent(match[1], "named", false);
|
|
113
|
+
}
|
|
114
|
+
// Named const exports (FC, arrow functions)
|
|
115
|
+
NAMED_CONST_RE.lastIndex = 0;
|
|
116
|
+
while ((match = NAMED_CONST_RE.exec(content)) !== null) {
|
|
117
|
+
addComponent(match[1], "named", false);
|
|
118
|
+
}
|
|
119
|
+
// Default function exports
|
|
120
|
+
DEFAULT_FUNCTION_RE.lastIndex = 0;
|
|
121
|
+
while ((match = DEFAULT_FUNCTION_RE.exec(content)) !== null) {
|
|
122
|
+
addComponent(match[1], "default", false);
|
|
123
|
+
}
|
|
124
|
+
// forwardRef exports
|
|
125
|
+
FORWARD_REF_RE.lastIndex = 0;
|
|
126
|
+
while ((match = FORWARD_REF_RE.exec(content)) !== null) {
|
|
127
|
+
addComponent(match[1], "named", true);
|
|
128
|
+
}
|
|
129
|
+
// Grouped exports: `export { Button, Card, buttonVariants }`
|
|
130
|
+
// Only pick PascalCase names (components), skip camelCase (utilities)
|
|
131
|
+
GROUPED_EXPORT_RE.lastIndex = 0;
|
|
132
|
+
while ((match = GROUPED_EXPORT_RE.exec(content)) !== null) {
|
|
133
|
+
const names = match[1].split(",").map((n) => n.trim().split(/\s+as\s+/).pop().trim());
|
|
134
|
+
for (const name of names) {
|
|
135
|
+
if (/^[A-Z][a-zA-Z0-9]+$/.test(name)) {
|
|
136
|
+
addComponent(name, "named", false);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return components;
|
|
141
|
+
}
|
|
142
|
+
// ── Main scanner ───────────────────────────────────────────────────────────
|
|
143
|
+
/**
|
|
144
|
+
* Scan a directory for React components and Storybook stories.
|
|
145
|
+
* Returns structured results with component metadata and story associations.
|
|
146
|
+
*/
|
|
147
|
+
export async function scanCodebase(rootPath) {
|
|
148
|
+
const startTime = Date.now();
|
|
149
|
+
const componentFiles = [];
|
|
150
|
+
const storyFiles = [];
|
|
151
|
+
let filesScanned = 0;
|
|
152
|
+
// Collect all relevant files
|
|
153
|
+
for await (const filePath of walkDir(rootPath)) {
|
|
154
|
+
filesScanned++;
|
|
155
|
+
const ext = extname(filePath);
|
|
156
|
+
if (isStoryFile(filePath)) {
|
|
157
|
+
storyFiles.push(filePath);
|
|
158
|
+
}
|
|
159
|
+
else if (COMPONENT_EXTENSIONS.has(ext)) {
|
|
160
|
+
componentFiles.push(filePath);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Parse all component files
|
|
164
|
+
const allComponents = [];
|
|
165
|
+
for (const filePath of componentFiles) {
|
|
166
|
+
try {
|
|
167
|
+
const content = await readFile(filePath, "utf-8");
|
|
168
|
+
const relPath = relative(rootPath, filePath);
|
|
169
|
+
const found = extractComponents(content, relPath);
|
|
170
|
+
allComponents.push(...found);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// Skip unreadable files
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Parse all story files
|
|
177
|
+
const allStories = [];
|
|
178
|
+
for (const filePath of storyFiles) {
|
|
179
|
+
try {
|
|
180
|
+
const relPath = relative(rootPath, filePath);
|
|
181
|
+
const story = await parseStoryFromPath(filePath);
|
|
182
|
+
if (story) {
|
|
183
|
+
// Use relative path in the result
|
|
184
|
+
allStories.push({ ...story, filePath: relPath });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Skip unreadable files
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Match stories to components
|
|
192
|
+
const matchedStoryNames = new Set();
|
|
193
|
+
for (const component of allComponents) {
|
|
194
|
+
const matchingStory = allStories.find((s) => s.componentName === component.name);
|
|
195
|
+
if (matchingStory) {
|
|
196
|
+
component.storybook = matchingStory;
|
|
197
|
+
matchedStoryNames.add(matchingStory.componentName);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const unmatchedStories = allStories.filter((s) => !matchedStoryNames.has(s.componentName));
|
|
201
|
+
return {
|
|
202
|
+
rootPath,
|
|
203
|
+
components: allComponents,
|
|
204
|
+
storybookStories: allStories,
|
|
205
|
+
unmatchedStories,
|
|
206
|
+
filesScanned,
|
|
207
|
+
durationMs: Date.now() - startTime,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Scan for Storybook stories only.
|
|
212
|
+
*/
|
|
213
|
+
export async function scanStorybook(rootPath) {
|
|
214
|
+
const stories = [];
|
|
215
|
+
for await (const filePath of walkDir(rootPath)) {
|
|
216
|
+
if (isStoryFile(filePath)) {
|
|
217
|
+
try {
|
|
218
|
+
const relPath = relative(rootPath, filePath);
|
|
219
|
+
const story = await parseStoryFromPath(filePath);
|
|
220
|
+
if (story) {
|
|
221
|
+
stories.push({ ...story, filePath: relPath });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// Skip unreadable files
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return stories;
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=codebase-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codebase-scan.js","sourceRoot":"","sources":["../../../src/integrations/codebase-scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface StoryArg {
|
|
2
|
+
name: string;
|
|
3
|
+
type?: string;
|
|
4
|
+
defaultValue?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
control?: string;
|
|
7
|
+
options?: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface StoryEntry {
|
|
10
|
+
name: string;
|
|
11
|
+
tags?: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface StoryComponentMeta {
|
|
14
|
+
/** Component name derived from the story title (e.g. "Button" from "Components/Button") */
|
|
15
|
+
componentName: string;
|
|
16
|
+
/** Full title as declared in the story meta */
|
|
17
|
+
title: string;
|
|
18
|
+
/** File path relative to the scan root */
|
|
19
|
+
filePath: string;
|
|
20
|
+
/** Args and argTypes extracted from the default export */
|
|
21
|
+
args: StoryArg[];
|
|
22
|
+
/** Individual stories (named exports) */
|
|
23
|
+
stories: StoryEntry[];
|
|
24
|
+
/** Tags declared on the meta object */
|
|
25
|
+
tags?: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Parse a single Storybook story file and extract component metadata.
|
|
29
|
+
* Uses regex-based extraction (no AST required).
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseStoryFile(content: string, filePath: string): StoryComponentMeta | null;
|
|
32
|
+
/**
|
|
33
|
+
* Parse a story file from disk.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseStoryFromPath(filePath: string): Promise<StoryComponentMeta | null>;
|
|
36
|
+
//# sourceMappingURL=storybook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storybook.d.ts","sourceRoot":"","sources":["../../../src/integrations/storybook.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,2FAA2F;IAC3F,aAAa,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,yCAAyC;IACzC,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAmCD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,kBAAkB,GAAG,IAAI,CAkG3B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAGpC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
// ── Regex patterns ─────────────────────────────────────────────────────────
|
|
3
|
+
// Match `title: "Components/Button"` or `title: 'Components/Button'`
|
|
4
|
+
const TITLE_RE = /title\s*:\s*["'`]([^"'`]+)["'`]/;
|
|
5
|
+
// Match `component: Button` or `component: "Button"`
|
|
6
|
+
const COMPONENT_RE = /component\s*:\s*["'`]?(\w+)["'`]?/;
|
|
7
|
+
// Match individual argTypes entries like: size: { control: "select", options: ["sm", "md", "lg"] }
|
|
8
|
+
const ARG_TYPE_RE = /(\w+)\s*:\s*\{([^}]*)\}/g;
|
|
9
|
+
// Match `control:` value inside an argType block
|
|
10
|
+
const CONTROL_RE = /control\s*:\s*["'`](\w+)["'`]/;
|
|
11
|
+
// Match `options:` array inside an argType block
|
|
12
|
+
const OPTIONS_RE = /options\s*:\s*\[([^\]]*)\]/;
|
|
13
|
+
// Match `type:` value inside an argType block
|
|
14
|
+
const TYPE_RE = /type\s*:\s*["'`](\w+)["'`]/;
|
|
15
|
+
// Match named exports like `export const Primary: Story = ...`
|
|
16
|
+
const STORY_EXPORT_RE = /export\s+const\s+(\w+)\s*(?::\s*\w+(?:<[^>]*>)?\s*)?=/g;
|
|
17
|
+
// Match `tags: ["autodocs", ...]` on the meta object
|
|
18
|
+
const TAGS_RE = /tags\s*:\s*\[([^\]]*)\]/;
|
|
19
|
+
// Match `args: { ... }` on the meta object (top-level default args)
|
|
20
|
+
const DEFAULT_ARGS_RE = /args\s*:\s*\{([^}]*)\}/;
|
|
21
|
+
// ── Parser ─────────────────────────────────────────────────────────────────
|
|
22
|
+
/**
|
|
23
|
+
* Parse a single Storybook story file and extract component metadata.
|
|
24
|
+
* Uses regex-based extraction (no AST required).
|
|
25
|
+
*/
|
|
26
|
+
export function parseStoryFile(content, filePath) {
|
|
27
|
+
// Must have a default export (the meta object)
|
|
28
|
+
if (!content.includes("export default") &&
|
|
29
|
+
!content.includes("satisfies Meta")) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
// Extract title — required
|
|
33
|
+
const titleMatch = TITLE_RE.exec(content);
|
|
34
|
+
const componentMatch = COMPONENT_RE.exec(content);
|
|
35
|
+
// Derive component name from title or component field
|
|
36
|
+
let componentName;
|
|
37
|
+
if (titleMatch?.[1]) {
|
|
38
|
+
const parts = titleMatch[1].split("/");
|
|
39
|
+
componentName = parts[parts.length - 1];
|
|
40
|
+
}
|
|
41
|
+
else if (componentMatch?.[1]) {
|
|
42
|
+
componentName = componentMatch[1];
|
|
43
|
+
}
|
|
44
|
+
if (!componentName)
|
|
45
|
+
return null;
|
|
46
|
+
const title = titleMatch?.[1] ?? componentName;
|
|
47
|
+
// Extract args from argTypes
|
|
48
|
+
const args = [];
|
|
49
|
+
const argTypesSection = content.match(/argTypes\s*:\s*\{([\s\S]*?)\n\s*\}/);
|
|
50
|
+
if (argTypesSection?.[1]) {
|
|
51
|
+
let match;
|
|
52
|
+
ARG_TYPE_RE.lastIndex = 0;
|
|
53
|
+
while ((match = ARG_TYPE_RE.exec(argTypesSection[1])) !== null) {
|
|
54
|
+
const name = match[1];
|
|
55
|
+
const block = match[2] ?? "";
|
|
56
|
+
const controlMatch = CONTROL_RE.exec(block);
|
|
57
|
+
const optionsMatch = OPTIONS_RE.exec(block);
|
|
58
|
+
const typeMatch = TYPE_RE.exec(block);
|
|
59
|
+
const arg = { name };
|
|
60
|
+
if (typeMatch?.[1])
|
|
61
|
+
arg.type = typeMatch[1];
|
|
62
|
+
if (controlMatch?.[1])
|
|
63
|
+
arg.control = controlMatch[1];
|
|
64
|
+
if (optionsMatch?.[1]) {
|
|
65
|
+
arg.options = optionsMatch[1]
|
|
66
|
+
.split(",")
|
|
67
|
+
.map((s) => s.trim().replace(/["'`]/g, ""))
|
|
68
|
+
.filter(Boolean);
|
|
69
|
+
}
|
|
70
|
+
args.push(arg);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Also extract from top-level `args: { ... }` if argTypes is empty
|
|
74
|
+
if (args.length === 0) {
|
|
75
|
+
const defaultArgsMatch = DEFAULT_ARGS_RE.exec(content);
|
|
76
|
+
if (defaultArgsMatch?.[1]) {
|
|
77
|
+
const entries = defaultArgsMatch[1].split(",");
|
|
78
|
+
for (const entry of entries) {
|
|
79
|
+
const [key, value] = entry.split(":").map((s) => s.trim());
|
|
80
|
+
if (key) {
|
|
81
|
+
args.push({
|
|
82
|
+
name: key,
|
|
83
|
+
defaultValue: value?.replace(/["'`]/g, ""),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Extract story names from named exports
|
|
90
|
+
const stories = [];
|
|
91
|
+
let storyMatch;
|
|
92
|
+
STORY_EXPORT_RE.lastIndex = 0;
|
|
93
|
+
while ((storyMatch = STORY_EXPORT_RE.exec(content)) !== null) {
|
|
94
|
+
const name = storyMatch[1];
|
|
95
|
+
// Skip common non-story exports
|
|
96
|
+
if (name === "default" || name === "meta" || name === "Meta")
|
|
97
|
+
continue;
|
|
98
|
+
stories.push({ name });
|
|
99
|
+
}
|
|
100
|
+
// Extract tags
|
|
101
|
+
const tagsMatch = TAGS_RE.exec(content);
|
|
102
|
+
const tags = tagsMatch?.[1]
|
|
103
|
+
? tagsMatch[1]
|
|
104
|
+
.split(",")
|
|
105
|
+
.map((s) => s.trim().replace(/["'`]/g, ""))
|
|
106
|
+
.filter(Boolean)
|
|
107
|
+
: undefined;
|
|
108
|
+
return {
|
|
109
|
+
componentName,
|
|
110
|
+
title,
|
|
111
|
+
filePath,
|
|
112
|
+
args,
|
|
113
|
+
stories,
|
|
114
|
+
tags,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Parse a story file from disk.
|
|
119
|
+
*/
|
|
120
|
+
export async function parseStoryFromPath(filePath) {
|
|
121
|
+
const content = await readFile(filePath, "utf-8");
|
|
122
|
+
return parseStoryFile(content, filePath);
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=storybook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storybook.js","sourceRoot":"","sources":["../../../src/integrations/storybook.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"AA+BA;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAoMjD"}
|
package/dist/src/mcp/server.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { loadKit } from "../kit/loader.js";
|
|
5
|
+
import { scanCodebase } from "../integrations/codebase-scan.js";
|
|
5
6
|
import { startPreviewServer } from "../preview/server.js";
|
|
6
7
|
import { setPreviewServer } from "../preview/ensure.js";
|
|
7
8
|
import { checkMcpRegistration, addFigmaMcpServer, addPlaywrightMcpServer, fixGlobalClaudeJson } from "../cli/setup-utils.js";
|
|
@@ -22,12 +23,25 @@ import * as updateTokens from "./tools/update-tokens.js";
|
|
|
22
23
|
import * as getScreenshots from "./tools/get-screenshots.js";
|
|
23
24
|
import * as checkSetup from "./tools/check-setup.js";
|
|
24
25
|
import * as pushTokensToFigma from "./tools/push-tokens-to-figma.js";
|
|
26
|
+
import * as scanProject from "./tools/scan-project.js";
|
|
25
27
|
/**
|
|
26
28
|
* Start the Layout Context MCP server.
|
|
27
29
|
* Loads the kit from the current working directory and registers all tools.
|
|
28
30
|
*/
|
|
29
31
|
export async function startServer() {
|
|
30
32
|
const kit = loadKit();
|
|
33
|
+
// Auto-scan current directory for React components and Storybook stories
|
|
34
|
+
let scanResult = null;
|
|
35
|
+
try {
|
|
36
|
+
scanResult = await scanCodebase(process.cwd());
|
|
37
|
+
if (scanResult.components.length > 0) {
|
|
38
|
+
console.error(`[layout-context] Codebase: ${scanResult.components.length} components` +
|
|
39
|
+
(scanResult.storybookStories.length > 0 ? ` (${scanResult.storybookStories.length} stories)` : ""));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Non-fatal — continue without codebase scan
|
|
44
|
+
}
|
|
31
45
|
const kitName = kit?.manifest.displayName ?? "none";
|
|
32
46
|
const componentCount = kit?.components.length ?? 0;
|
|
33
47
|
// Log to stderr so it doesn't interfere with stdio transport
|
|
@@ -102,11 +116,11 @@ export async function startServer() {
|
|
|
102
116
|
name: "layout-context",
|
|
103
117
|
version: pkg.version,
|
|
104
118
|
});
|
|
105
|
-
// Register all
|
|
119
|
+
// Register all 14 tools
|
|
106
120
|
server.tool(getDesignSystem.name, getDesignSystem.description, getDesignSystem.inputSchema, getDesignSystem.handler(kit));
|
|
107
121
|
server.tool(getTokens.name, getTokens.description, getTokens.inputSchema, getTokens.handler(kit));
|
|
108
122
|
server.tool(getComponent.name, getComponent.description, getComponent.inputSchema, getComponent.handler(kit));
|
|
109
|
-
server.tool(listComponents.name, listComponents.description, listComponents.inputSchema, listComponents.handler(kit));
|
|
123
|
+
server.tool(listComponents.name, listComponents.description, listComponents.inputSchema, listComponents.handler(kit, scanResult));
|
|
110
124
|
server.tool(checkCompliance.name, checkCompliance.description, checkCompliance.inputSchema, checkCompliance.handler(kit));
|
|
111
125
|
server.tool(preview.name, preview.description, preview.inputSchema, preview.handler(kit));
|
|
112
126
|
server.tool(pushToFigma.name, pushToFigma.description, pushToFigma.inputSchema, pushToFigma.handler(kit));
|
|
@@ -116,6 +130,7 @@ export async function startServer() {
|
|
|
116
130
|
server.tool(getScreenshots.name, getScreenshots.description, getScreenshots.inputSchema, getScreenshots.handler());
|
|
117
131
|
server.tool(checkSetup.name, checkSetup.description, checkSetup.inputSchema, checkSetup.handler());
|
|
118
132
|
server.tool(pushTokensToFigma.name, pushTokensToFigma.description, pushTokensToFigma.inputSchema, pushTokensToFigma.handler(kit));
|
|
133
|
+
server.tool(scanProject.name, scanProject.description, scanProject.inputSchema, scanProject.handler());
|
|
119
134
|
// Connect via stdio
|
|
120
135
|
const transport = new StdioServerTransport();
|
|
121
136
|
await server.connect(transport);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE7H,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,+DAA+D;AAC/D,MAAM,GAAG,GAAG,OAAO,CAAC,uBAAuB,CAAwB,CAAC;AAEpE,eAAe;AACf,OAAO,KAAK,eAAe,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,SAAS,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,cAAc,MAAM,4BAA4B,CAAC;AAC7D,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,WAAW,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,UAAU,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,aAAa,MAAM,4BAA4B,CAAC;AAC5D,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,cAAc,MAAM,4BAA4B,CAAC;AAC7D,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,iBAAiB,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Kit } from "../../kit/types.js";
|
|
2
|
+
import type { ScanResult } from "../../integrations/codebase-scan.js";
|
|
2
3
|
export declare const name = "list-components";
|
|
3
4
|
export declare const description: string;
|
|
4
5
|
export declare const inputSchema: {};
|
|
5
|
-
export declare function handler(kit: Kit | null): () => Promise<{
|
|
6
|
+
export declare function handler(kit: Kit | null, scanResult: ScanResult | null): () => Promise<{
|
|
6
7
|
content: {
|
|
7
8
|
type: "text";
|
|
8
9
|
text: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-components.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/list-components.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"list-components.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/list-components.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AAEtE,eAAO,MAAM,IAAI,oBAAoB,CAAC;AAEtC,eAAO,MAAM,WAAW,QAG4C,CAAC;AAErE,eAAO,MAAM,WAAW,IAAK,CAAC;AAE9B,wBAAgB,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI;;;;;GAmDrE"}
|
|
@@ -1,38 +1,64 @@
|
|
|
1
1
|
export const name = "list-components";
|
|
2
|
-
export const description = "Lists all available components
|
|
3
|
-
"
|
|
2
|
+
export const description = "Lists all available components: design system components from layout.md, " +
|
|
3
|
+
"auto-detected React components from the codebase, and Storybook stories. " +
|
|
4
|
+
"Use this to discover existing components before building new UI.";
|
|
4
5
|
export const inputSchema = {};
|
|
5
|
-
export function handler(kit) {
|
|
6
|
+
export function handler(kit, scanResult) {
|
|
6
7
|
return async () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
text: "No design system kit found. Run `npx @layoutdesign/context init` to set one up.",
|
|
13
|
-
},
|
|
14
|
-
],
|
|
15
|
-
};
|
|
8
|
+
const sections = [];
|
|
9
|
+
// 1. Design system components from layout.md
|
|
10
|
+
if (kit && kit.components.length > 0) {
|
|
11
|
+
const lines = kit.components.map((c) => `- **${c.name}** — ${c.description || "No description"}`);
|
|
12
|
+
sections.push(`## Design System (from layout.md)\n\n${lines.join("\n")}`);
|
|
16
13
|
}
|
|
17
|
-
|
|
14
|
+
// 2. Codebase components (auto-scanned)
|
|
15
|
+
if (scanResult && scanResult.components.length > 0) {
|
|
16
|
+
const lines = scanResult.components
|
|
17
|
+
.slice(0, 100) // cap for context budget
|
|
18
|
+
.map((c) => {
|
|
19
|
+
const propsStr = c.props.length > 0
|
|
20
|
+
? ` props: ${c.props.map(p => p.name).join(", ")}`
|
|
21
|
+
: "";
|
|
22
|
+
const storyStr = c.storybook
|
|
23
|
+
? ` [Storybook: ${c.storybook.stories.map(s => s.name).join(", ")}]`
|
|
24
|
+
: "";
|
|
25
|
+
const refStr = c.usesForwardRef ? " (forwardRef)" : "";
|
|
26
|
+
const importPath = buildImportPath(c.filePath);
|
|
27
|
+
const importStatement = c.exportType === "default"
|
|
28
|
+
? `import ${c.name} from '${importPath}'`
|
|
29
|
+
: `import { ${c.name} } from '${importPath}'`;
|
|
30
|
+
return `- **${c.name}** (${c.filePath})${propsStr}${refStr}${storyStr}\n Import: \`${importStatement}\``;
|
|
31
|
+
});
|
|
32
|
+
sections.push(`## Your Codebase (auto-detected)\n\n${lines.join("\n")}`);
|
|
33
|
+
}
|
|
34
|
+
if (sections.length === 0) {
|
|
18
35
|
return {
|
|
19
|
-
content: [
|
|
20
|
-
{
|
|
36
|
+
content: [{
|
|
21
37
|
type: "text",
|
|
22
|
-
text: "No components
|
|
23
|
-
},
|
|
24
|
-
],
|
|
38
|
+
text: "No components found. Set up a design system with `npx @layoutdesign/context init` or create React components in this project.",
|
|
39
|
+
}],
|
|
25
40
|
};
|
|
26
41
|
}
|
|
27
|
-
const
|
|
42
|
+
const total = (kit?.components.length ?? 0) + (scanResult?.components.length ?? 0);
|
|
28
43
|
return {
|
|
29
|
-
content: [
|
|
30
|
-
{
|
|
44
|
+
content: [{
|
|
31
45
|
type: "text",
|
|
32
|
-
text: `# Components (${
|
|
33
|
-
},
|
|
34
|
-
],
|
|
46
|
+
text: `# Components (${total})\n\n${sections.join("\n\n")}\n\n---\n**IMPORTANT:** When building UI, reuse existing components listed above. Import from the paths shown. Do NOT generate a new Button/Card/Input if one already exists.`,
|
|
47
|
+
}],
|
|
35
48
|
};
|
|
36
49
|
};
|
|
37
50
|
}
|
|
51
|
+
function buildImportPath(filePath) {
|
|
52
|
+
// Convert file path to import path: src/components/ui/button.tsx -> @/components/ui/button
|
|
53
|
+
let importPath = filePath
|
|
54
|
+
.replace(/\.(tsx?|jsx?)$/, "")
|
|
55
|
+
.replace(/\/index$/, "");
|
|
56
|
+
if (importPath.startsWith("src/")) {
|
|
57
|
+
importPath = "@/" + importPath.slice(4);
|
|
58
|
+
}
|
|
59
|
+
else if (!importPath.startsWith(".") && !importPath.startsWith("@")) {
|
|
60
|
+
importPath = "./" + importPath;
|
|
61
|
+
}
|
|
62
|
+
return importPath;
|
|
63
|
+
}
|
|
38
64
|
//# sourceMappingURL=list-components.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-components.js","sourceRoot":"","sources":["../../../../src/mcp/tools/list-components.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"list-components.js","sourceRoot":"","sources":["../../../../src/mcp/tools/list-components.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const name = "scan-project";
|
|
3
|
+
export declare const description: string;
|
|
4
|
+
export declare const inputSchema: {
|
|
5
|
+
path: z.ZodOptional<z.ZodString>;
|
|
6
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
7
|
+
both: "both";
|
|
8
|
+
storybook: "storybook";
|
|
9
|
+
codebase: "codebase";
|
|
10
|
+
}>>;
|
|
11
|
+
};
|
|
12
|
+
type Input = {
|
|
13
|
+
path?: string;
|
|
14
|
+
type?: "both" | "storybook" | "codebase";
|
|
15
|
+
};
|
|
16
|
+
export declare function handler(): (input: Input) => Promise<{
|
|
17
|
+
content: {
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
}[];
|
|
21
|
+
isError?: undefined;
|
|
22
|
+
} | {
|
|
23
|
+
content: {
|
|
24
|
+
type: "text";
|
|
25
|
+
text: string;
|
|
26
|
+
}[];
|
|
27
|
+
isError: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=scan-project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-project.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/scan-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,IAAI,iBAAiB,CAAC;AAEnC,eAAO,MAAM,WAAW,QAG8F,CAAC;AAEvH,eAAO,MAAM,WAAW;;;;;;;CAavB,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;CAC1C,CAAC;AAEF,wBAAgB,OAAO,KACP,OAAO,KAAK;;;;;;;;;;;;GA8F3B"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { scanCodebase, scanStorybook } from "../../integrations/codebase-scan.js";
|
|
4
|
+
export const name = "scan-project";
|
|
5
|
+
export const description = "Scan the current project for React components and Storybook stories. " +
|
|
6
|
+
"Returns structured data about component names, props, export types, and story associations. " +
|
|
7
|
+
"Use this to understand the existing component inventory before generating new components or design system context.";
|
|
8
|
+
export const inputSchema = {
|
|
9
|
+
path: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Directory to scan. Defaults to the current working directory."),
|
|
13
|
+
type: z
|
|
14
|
+
.enum(["both", "storybook", "codebase"])
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("What to scan: 'both' (default) scans components and stories, 'storybook' scans only stories, 'codebase' scans only components."),
|
|
17
|
+
};
|
|
18
|
+
export function handler() {
|
|
19
|
+
return async (input) => {
|
|
20
|
+
const rootPath = resolve(input.path ?? process.cwd());
|
|
21
|
+
const scanType = input.type ?? "both";
|
|
22
|
+
try {
|
|
23
|
+
if (scanType === "storybook") {
|
|
24
|
+
const stories = await scanStorybook(rootPath);
|
|
25
|
+
return {
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: "text",
|
|
29
|
+
text: JSON.stringify({
|
|
30
|
+
type: "storybook-scan",
|
|
31
|
+
rootPath,
|
|
32
|
+
storiesFound: stories.length,
|
|
33
|
+
stories,
|
|
34
|
+
}, null, 2),
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const result = await scanCodebase(rootPath);
|
|
40
|
+
// For "codebase" type, strip storybook data
|
|
41
|
+
if (scanType === "codebase") {
|
|
42
|
+
const components = result.components.map(({ storybook: _sb, ...rest }) => rest);
|
|
43
|
+
return {
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: "text",
|
|
47
|
+
text: JSON.stringify({
|
|
48
|
+
type: "codebase-scan",
|
|
49
|
+
rootPath,
|
|
50
|
+
componentsFound: components.length,
|
|
51
|
+
filesScanned: result.filesScanned,
|
|
52
|
+
durationMs: result.durationMs,
|
|
53
|
+
components,
|
|
54
|
+
}, null, 2),
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// Default: both
|
|
60
|
+
const withStories = result.components.filter((c) => c.storybook);
|
|
61
|
+
return {
|
|
62
|
+
content: [
|
|
63
|
+
{
|
|
64
|
+
type: "text",
|
|
65
|
+
text: JSON.stringify({
|
|
66
|
+
type: "full-scan",
|
|
67
|
+
rootPath,
|
|
68
|
+
summary: {
|
|
69
|
+
componentsFound: result.components.length,
|
|
70
|
+
storiesFound: result.storybookStories.length,
|
|
71
|
+
componentsWithStories: withStories.length,
|
|
72
|
+
unmatchedStories: result.unmatchedStories.length,
|
|
73
|
+
filesScanned: result.filesScanned,
|
|
74
|
+
durationMs: result.durationMs,
|
|
75
|
+
},
|
|
76
|
+
components: result.components,
|
|
77
|
+
unmatchedStories: result.unmatchedStories,
|
|
78
|
+
}, null, 2),
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: "text",
|
|
89
|
+
text: `Error scanning project: ${msg}`,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
isError: true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=scan-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-project.js","sourceRoot":"","sources":["../../../../src/mcp/tools/scan-project.ts"],"names":[],"mappings":"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"}
|