@layoutdesign/context 0.3.1 → 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/cli/setup-utils.d.ts +7 -0
- package/dist/src/cli/setup-utils.d.ts.map +1 -1
- package/dist/src/cli/setup-utils.js +52 -1
- package/dist/src/cli/setup-utils.js.map +1 -1
- 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 +75 -2
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/check-setup.js +6 -1
- package/dist/src/mcp/tools/check-setup.js.map +1 -1
- package/dist/src/mcp/tools/design-in-figma.d.ts.map +1 -1
- package/dist/src/mcp/tools/design-in-figma.js +73 -80
- package/dist/src/mcp/tools/design-in-figma.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/push-to-figma.d.ts +8 -3
- package/dist/src/mcp/tools/push-to-figma.d.ts.map +1 -1
- package/dist/src/mcp/tools/push-to-figma.js +109 -2
- package/dist/src/mcp/tools/push-to-figma.js.map +1 -1
- package/dist/src/mcp/tools/push-tokens-to-figma.d.ts +16 -0
- package/dist/src/mcp/tools/push-tokens-to-figma.d.ts.map +1 -0
- package/dist/src/mcp/tools/push-tokens-to-figma.js +141 -0
- package/dist/src/mcp/tools/push-tokens-to-figma.js.map +1 -0
- 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":"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"}
|
|
@@ -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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"}
|
|
@@ -19,6 +19,8 @@ export interface McpRegistrationState {
|
|
|
19
19
|
correctTransport: boolean;
|
|
20
20
|
/** True if registered at user scope */
|
|
21
21
|
correctScope: boolean;
|
|
22
|
+
/** True if using the old figma-developer-mcp npm package (stdio, only 2 tools) */
|
|
23
|
+
isOldNpmPackage?: boolean;
|
|
22
24
|
};
|
|
23
25
|
/** Playwright state */
|
|
24
26
|
playwright: {
|
|
@@ -54,6 +56,11 @@ export declare function addFigmaMcpServer(): FixResult;
|
|
|
54
56
|
* Register Playwright MCP server via `claude mcp add --scope user`.
|
|
55
57
|
*/
|
|
56
58
|
export declare function addPlaywrightMcpServer(): FixResult;
|
|
59
|
+
/**
|
|
60
|
+
* Check ~/.claude.json for an outdated figma-developer-mcp entry that
|
|
61
|
+
* shadows the correct HTTP registration. Returns true if fixed.
|
|
62
|
+
*/
|
|
63
|
+
export declare function fixGlobalClaudeJson(): boolean;
|
|
57
64
|
/**
|
|
58
65
|
* Test whether an HTTP endpoint is reachable (HEAD request with timeout).
|
|
59
66
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-utils.d.ts","sourceRoot":"","sources":["../../../src/cli/setup-utils.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IACtC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IACxC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,2BAA2B;IAC3B,KAAK,EAAE;QACL,UAAU,EAAE,OAAO,CAAC;QACpB,KAAK,CAAC,EAAE,cAAc,CAAC;QACvB,sEAAsE;QACtE,YAAY,EAAE,OAAO,CAAC;QACtB,qDAAqD;QACrD,gBAAgB,EAAE,OAAO,CAAC;QAC1B,uCAAuC;QACvC,YAAY,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"setup-utils.d.ts","sourceRoot":"","sources":["../../../src/cli/setup-utils.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IACtC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IACxC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,2BAA2B;IAC3B,KAAK,EAAE;QACL,UAAU,EAAE,OAAO,CAAC;QACpB,KAAK,CAAC,EAAE,cAAc,CAAC;QACvB,sEAAsE;QACtE,YAAY,EAAE,OAAO,CAAC;QACtB,qDAAqD;QACrD,gBAAgB,EAAE,OAAO,CAAC;QAC1B,uCAAuC;QACvC,YAAY,EAAE,OAAO,CAAC;QACtB,kFAAkF;QAClF,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,uBAAuB;IACvB,UAAU,EAAE;QACV,UAAU,EAAE,OAAO,CAAC;QACpB,KAAK,CAAC,EAAE,cAAc,CAAC;KACxB,CAAC;IACF,mBAAmB;IACnB,MAAM,EAAE;QACN,UAAU,EAAE,OAAO,CAAC;QACpB,KAAK,CAAC,EAAE,cAAc,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,oBAAoB,GAAG,IAAI,CAoDlE;AA6ED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,IAAI,SAAS,CA0C7C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,SAAS,CA4ClD;AAMD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAiC7C;AAMD;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,MAAM,EACX,SAAS,SAAQ,GAChB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAclE"}
|
|
@@ -28,6 +28,8 @@ export function checkMcpRegistration() {
|
|
|
28
28
|
const playwrightEntry = servers.find((s) => s.name === "playwright");
|
|
29
29
|
// Layout analysis
|
|
30
30
|
const layoutEntry = servers.find((s) => s.name === "layout" || s.name === "layoutdesign");
|
|
31
|
+
// Detect old figma-developer-mcp npm package (only has 2 tools, uses stdio)
|
|
32
|
+
const isOldNpmPackage = figmaEntry?.transport === "stdio" && !hasPluginShadow;
|
|
31
33
|
return {
|
|
32
34
|
rawOutput,
|
|
33
35
|
servers,
|
|
@@ -37,6 +39,7 @@ export function checkMcpRegistration() {
|
|
|
37
39
|
pluginShadow: hasPluginShadow,
|
|
38
40
|
correctTransport: figmaEntry?.transport === "http",
|
|
39
41
|
correctScope: figmaEntry?.scope === "user",
|
|
42
|
+
isOldNpmPackage,
|
|
40
43
|
},
|
|
41
44
|
playwright: {
|
|
42
45
|
registered: !!playwrightEntry,
|
|
@@ -129,6 +132,17 @@ function parseMcpList(raw) {
|
|
|
129
132
|
* sessions, so we must ensure a proper user-scoped entry exists.
|
|
130
133
|
*/
|
|
131
134
|
export function addFigmaMcpServer() {
|
|
135
|
+
// Remove any existing figma entries at all scopes (may be old npm package or wrong scope)
|
|
136
|
+
for (const scope of ["user", "project", "local"]) {
|
|
137
|
+
try {
|
|
138
|
+
execFileSync("claude", ["mcp", "remove", "--scope", scope, "figma"], {
|
|
139
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Ignore — may not exist at this scope
|
|
144
|
+
}
|
|
145
|
+
}
|
|
132
146
|
try {
|
|
133
147
|
execFileSync("claude", [
|
|
134
148
|
"mcp", "add", "--scope", "user", "--transport", "http",
|
|
@@ -137,7 +151,7 @@ export function addFigmaMcpServer() {
|
|
|
137
151
|
return {
|
|
138
152
|
server: "figma",
|
|
139
153
|
success: true,
|
|
140
|
-
message: "Registered
|
|
154
|
+
message: "Registered official Figma MCP (OAuth — authenticate once in Claude Code)",
|
|
141
155
|
};
|
|
142
156
|
}
|
|
143
157
|
catch (err) {
|
|
@@ -201,6 +215,43 @@ export function addPlaywrightMcpServer() {
|
|
|
201
215
|
}
|
|
202
216
|
}
|
|
203
217
|
/* ------------------------------------------------------------------ */
|
|
218
|
+
/* Check .claude.json for old Figma entries */
|
|
219
|
+
/* ------------------------------------------------------------------ */
|
|
220
|
+
/**
|
|
221
|
+
* Check ~/.claude.json for an outdated figma-developer-mcp entry that
|
|
222
|
+
* shadows the correct HTTP registration. Returns true if fixed.
|
|
223
|
+
*/
|
|
224
|
+
export function fixGlobalClaudeJson() {
|
|
225
|
+
const { readFileSync, writeFileSync } = require("node:fs");
|
|
226
|
+
const { homedir } = require("node:os");
|
|
227
|
+
const { join } = require("node:path");
|
|
228
|
+
const configPath = join(homedir(), ".claude.json");
|
|
229
|
+
try {
|
|
230
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
231
|
+
const config = JSON.parse(raw);
|
|
232
|
+
const servers = config.mcpServers;
|
|
233
|
+
if (!servers?.figma)
|
|
234
|
+
return false;
|
|
235
|
+
const figma = servers.figma;
|
|
236
|
+
const isOldNpm = figma.type === "stdio" ||
|
|
237
|
+
(figma.command === "npx" &&
|
|
238
|
+
Array.isArray(figma.args) &&
|
|
239
|
+
figma.args.some((a) => a.includes("figma-developer-mcp")));
|
|
240
|
+
if (!isOldNpm)
|
|
241
|
+
return false;
|
|
242
|
+
// Replace with official HTTP server
|
|
243
|
+
servers.figma = {
|
|
244
|
+
type: "http",
|
|
245
|
+
url: "https://mcp.figma.com/mcp",
|
|
246
|
+
};
|
|
247
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/* ------------------------------------------------------------------ */
|
|
204
255
|
/* Endpoint reachability */
|
|
205
256
|
/* ------------------------------------------------------------------ */
|
|
206
257
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-utils.js","sourceRoot":"","sources":["../../../src/cli/setup-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"setup-utils.js","sourceRoot":"","sources":["../../../src/cli/setup-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiDlD,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AAExE;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;YAClD,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,MAAM;YACf,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAEtC,iBAAiB;IACjB,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IAC3D,MAAM,eAAe,GACnB,KAAK,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACtC,KAAK,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC;IAE5C,sBAAsB;IACtB,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;IAErE,kBAAkB;IAClB,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAC9B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc,CACxD,CAAC;IAEF,4EAA4E;IAC5E,MAAM,eAAe,GAAG,UAAU,EAAE,SAAS,KAAK,OAAO,IAAI,CAAC,eAAe,CAAC;IAE9E,OAAO;QACL,SAAS;QACT,OAAO;QACP,KAAK,EAAE;YACL,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,KAAK,EAAE,UAAU;YACjB,YAAY,EAAE,eAAe;YAC7B,gBAAgB,EAAE,UAAU,EAAE,SAAS,KAAK,MAAM;YAClD,YAAY,EAAE,UAAU,EAAE,KAAK,KAAK,MAAM;YAC1C,eAAe;SAChB;QACD,UAAU,EAAE;YACV,UAAU,EAAE,CAAC,CAAC,eAAe;YAC7B,KAAK,EAAE,eAAe;SACvB;QACD,MAAM,EAAE;YACN,UAAU,EAAE,CAAC,CAAC,WAAW;YACzB,KAAK,EAAE,WAAW;SACnB;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,YAAY,CAAC,GAAW;IAC/B,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAEtD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAExC,wCAAwC;QACxC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAEvE,wDAAwD;QACxD,sFAAsF;QACtF,IAAI,IAAwB,CAAC;QAC7B,IAAI,KAAK,GAA4B,SAAS,CAAC;QAC/C,IAAI,SAAS,GAAgC,SAAS,CAAC;QAEvD,wDAAwD;QACxD,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAC5B,+DAA+D,CAChE,CAAC;QACF,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YACrB,SAAS,GAAG,UAAU,CAAC,CAAC,CAAgC,CAAC;YACzD,KAAK,GAAG,UAAU,CAAC,CAAC,CAA4B,CAAC;QACnD,CAAC;QAED,iEAAiE;QACjE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC1D,IAAI,UAAU,EAAE,CAAC;gBACf,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;gBACrB,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;gBAC7B,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,SAAS,GAAG,MAAM,CAAC;qBAC1C,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;oBAAE,SAAS,GAAG,OAAO,CAAC;gBACtD,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,KAAK,GAAG,MAAM,CAAC;qBACtC,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;oBAAE,KAAK,GAAG,SAAS,CAAC;YACxD,CAAC;QACH,CAAC;QAED,6EAA6E;QAC7E,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjC,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;YACrE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YACxD,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,GAAG,KAAK,CAAC;gBACb,qDAAqD;gBACrD,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,SAAS,GAAG,MAAM,CAAC;qBAC1C,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;oBAAE,SAAS,GAAG,OAAO,CAAC;gBACtD,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,KAAK,GAAG,MAAM,CAAC;qBACtC,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;oBAAE,KAAK,GAAG,SAAS,CAAC;YACxD,CAAC;QACH,CAAC;QAED,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AAExE;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB;IAC/B,0FAA0F;IAC1F,KAAK,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC;YACH,YAAY,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE;gBACnE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;aAChC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,uCAAuC;QACzC,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,YAAY,CACV,QAAQ,EACR;YACE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM;YACtD,OAAO,EAAE,2BAA2B;SACrC,EACD,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACpC,CAAC;QACF,OAAO;YACL,MAAM,EAAE,OAAO;YACf,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,0EAA0E;SACpF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAI,GAA2B,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACrE,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5D,OAAO;gBACL,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,kCAAkC;aAC5C,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,OAAO;YACf,OAAO,EAAE,KAAK;YACd,OAAO,EACL,8HAA8H;SACjI,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,8BAA8B;IAC9B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;YACnD,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9C,OAAO;gBACL,MAAM,EAAE,YAAY;gBACpB,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,oBAAoB;aAC9B,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,0BAA0B;SACpC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,YAAY,CACV,QAAQ,EACR;YACE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM;YAC/B,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,8BAA8B;SAChE,EACD,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACpC,CAAC;QACF,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,qBAAqB;SAC/B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,OAAO,EAAE,KAAK;YACd,OAAO,EACL,+HAA+H;SAClI,CAAC;IACJ,CAAC;AACH,CAAC;AAED,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AAExE;;;GAGG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,SAAS,CAA6B,CAAC;IACvF,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,SAAS,CAA6B,CAAC;IACnE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,WAAW,CAA+B,CAAC;IAEpE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;QAC1D,MAAM,OAAO,GAAG,MAAM,CAAC,UAAiE,CAAC;QACzF,IAAI,CAAC,OAAO,EAAE,KAAK;YAAE,OAAO,KAAK,CAAC;QAElC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,MAAM,QAAQ,GACZ,KAAK,CAAC,IAAI,KAAK,OAAO;YACtB,CAAC,KAAK,CAAC,OAAO,KAAK,KAAK;gBACtB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;gBACxB,KAAK,CAAC,IAAiB,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAErF,IAAI,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QAE5B,oCAAoC;QACpC,OAAO,CAAC,KAAK,GAAG;YACd,IAAI,EAAE,MAAM;YACZ,GAAG,EAAE,2BAA2B;SACjC,CAAC;QAEF,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AAExE;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAW,EACX,SAAS,GAAG,KAAK;IAEjB,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;QAC9D,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAC1C,CAAC;AACH,CAAC"}
|
|
@@ -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
|