@fragments-sdk/cli 0.7.2 → 0.7.4
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 +2 -0
- package/dist/bin.js +25 -17
- package/dist/bin.js.map +1 -1
- package/dist/chunk-AWYCDRPG.js +272 -0
- package/dist/chunk-AWYCDRPG.js.map +1 -0
- package/dist/chunk-EKLMXTWU.js +80 -0
- package/dist/chunk-EKLMXTWU.js.map +1 -0
- package/dist/{chunk-DH4ETVSM.js → chunk-NEJ2FBTN.js} +9 -7
- package/dist/{chunk-DH4ETVSM.js.map → chunk-NEJ2FBTN.js.map} +1 -1
- package/dist/{chunk-GHYYFAQN.js → chunk-P33AKQJW.js} +1 -76
- package/dist/chunk-P33AKQJW.js.map +1 -0
- package/dist/{chunk-3T6QL7IY.js → chunk-R6IZZSE7.js} +23 -275
- package/dist/chunk-R6IZZSE7.js.map +1 -0
- package/dist/{chunk-7KUSBMI4.js → chunk-S56I5FST.js} +174 -45
- package/dist/chunk-S56I5FST.js.map +1 -0
- package/dist/{chunk-DQHWLAUV.js → chunk-TOIE7VXF.js} +2 -2
- package/dist/{chunk-OOGTG5FM.js → chunk-UXLGIGSX.js} +56 -2
- package/dist/chunk-UXLGIGSX.js.map +1 -0
- package/dist/{chunk-GKX2HPZ6.js → chunk-YMPGYEWK.js} +9 -3
- package/dist/chunk-YMPGYEWK.js.map +1 -0
- package/dist/chunk-Z7EY4VHE.js +50 -0
- package/dist/{core-UQXZTBFZ.js → core-3NMNCLFW.js} +8 -5
- package/dist/discovery-Z4RDDFVR.js +28 -0
- package/dist/{generate-GP6ZLAQB.js → generate-23VLX7QN.js} +7 -4
- package/dist/{generate-GP6ZLAQB.js.map → generate-23VLX7QN.js.map} +1 -1
- package/dist/index.js +15 -11
- package/dist/index.js.map +1 -1
- package/dist/{init-W72WBSU2.js → init-VYVYMVHH.js} +10 -6
- package/dist/{init-W72WBSU2.js.map → init-VYVYMVHH.js.map} +1 -1
- package/dist/mcp-bin.js +5 -3
- package/dist/mcp-bin.js.map +1 -1
- package/dist/sass.node-4XJK6YBF.js +130708 -0
- package/dist/sass.node-4XJK6YBF.js.map +1 -0
- package/dist/scan-FZR6YVI5.js +15 -0
- package/dist/{service-PVGTYUKX.js → service-CFFBHW4X.js} +6 -4
- package/dist/service-CFFBHW4X.js.map +1 -0
- package/dist/{static-viewer-KILKIVN7.js → static-viewer-VA2JXSCX.js} +6 -4
- package/dist/static-viewer-VA2JXSCX.js.map +1 -0
- package/dist/{test-3YRYQRGV.js → test-VTD7R6G2.js} +8 -4
- package/dist/{test-3YRYQRGV.js.map → test-VTD7R6G2.js.map} +1 -1
- package/dist/{tokens-IXSQHPQK.js → tokens-7JA5CPDL.js} +10 -7
- package/dist/{tokens-IXSQHPQK.js.map → tokens-7JA5CPDL.js.map} +1 -1
- package/dist/{viewer-K42REJU2.js → viewer-WXTDDQGK.js} +403 -26
- package/dist/viewer-WXTDDQGK.js.map +1 -0
- package/package.json +5 -1
- package/src/build.ts +57 -5
- package/src/commands/init.ts +6 -2
- package/src/core/__tests__/token-resolver.test.ts +82 -0
- package/src/core/discovery.ts +7 -1
- package/src/core/token-parser.ts +102 -0
- package/src/core/token-resolver.ts +155 -0
- package/src/migrate/detect.ts +4 -0
- package/src/service/__tests__/patch-generator.test.ts +2 -2
- package/src/service/patch-generator.ts +8 -1
- package/src/viewer/components/App.tsx +63 -2
- package/src/viewer/components/Layout.tsx +1 -1
- package/src/viewer/components/LeftSidebar.tsx +35 -77
- package/src/viewer/preview-frame.html +1 -1
- package/src/viewer/render-utils.ts +141 -0
- package/src/viewer/styles/globals.css +2 -1
- package/src/viewer/vite-plugin.ts +399 -24
- package/dist/chunk-3T6QL7IY.js.map +0 -1
- package/dist/chunk-7KUSBMI4.js.map +0 -1
- package/dist/chunk-GHYYFAQN.js.map +0 -1
- package/dist/chunk-GKX2HPZ6.js.map +0 -1
- package/dist/chunk-OOGTG5FM.js.map +0 -1
- package/dist/scan-V54HWRDY.js +0 -12
- package/dist/viewer-K42REJU2.js.map +0 -1
- /package/dist/{chunk-DQHWLAUV.js.map → chunk-TOIE7VXF.js.map} +0 -0
- /package/dist/{core-UQXZTBFZ.js.map → chunk-Z7EY4VHE.js.map} +0 -0
- /package/dist/{scan-V54HWRDY.js.map → core-3NMNCLFW.js.map} +0 -0
- /package/dist/{service-PVGTYUKX.js.map → discovery-Z4RDDFVR.js.map} +0 -0
- /package/dist/{static-viewer-KILKIVN7.js.map → scan-FZR6YVI5.js.map} +0 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
BRAND
|
|
4
|
+
} from "./chunk-EKLMXTWU.js";
|
|
5
|
+
|
|
6
|
+
// src/core/discovery.ts
|
|
7
|
+
import { resolve, dirname } from "path";
|
|
8
|
+
import { readFile } from "fs/promises";
|
|
9
|
+
import { existsSync } from "fs";
|
|
10
|
+
import fg from "fast-glob";
|
|
11
|
+
async function discoverBlockFiles(configDir, exclude) {
|
|
12
|
+
const patterns = [
|
|
13
|
+
`**/*${BRAND.blockFileExtension}`,
|
|
14
|
+
`**/*${BRAND.recipeFileExtension}`
|
|
15
|
+
];
|
|
16
|
+
const files = await fg(patterns, {
|
|
17
|
+
cwd: configDir,
|
|
18
|
+
ignore: exclude ?? ["**/node_modules/**", "**/dist/**"],
|
|
19
|
+
absolute: false
|
|
20
|
+
});
|
|
21
|
+
return files.map((relativePath) => ({
|
|
22
|
+
relativePath,
|
|
23
|
+
absolutePath: resolve(configDir, relativePath)
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
var discoverRecipeFiles = discoverBlockFiles;
|
|
27
|
+
async function discoverFragmentFiles(config, configDir) {
|
|
28
|
+
const defaultExcludes = [
|
|
29
|
+
"**/*.test.stories.*",
|
|
30
|
+
"**/*.stories.test.*",
|
|
31
|
+
"**/*.test.story.*",
|
|
32
|
+
"**/*.story.test.*"
|
|
33
|
+
];
|
|
34
|
+
const files = await fg(config.include, {
|
|
35
|
+
cwd: configDir,
|
|
36
|
+
ignore: [...defaultExcludes, ...config.exclude ?? []],
|
|
37
|
+
absolute: false
|
|
38
|
+
});
|
|
39
|
+
return files.map((relativePath) => ({
|
|
40
|
+
relativePath,
|
|
41
|
+
absolutePath: resolve(configDir, relativePath)
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
async function discoverComponentFiles(config, configDir) {
|
|
45
|
+
if (!config.components || config.components.length === 0) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const files = await fg(config.components, {
|
|
49
|
+
cwd: configDir,
|
|
50
|
+
ignore: [
|
|
51
|
+
...config.exclude ?? [],
|
|
52
|
+
// Exclude fragment files themselves
|
|
53
|
+
...config.include,
|
|
54
|
+
// Exclude test files
|
|
55
|
+
"**/*.test.*",
|
|
56
|
+
"**/*.spec.*",
|
|
57
|
+
"**/__tests__/**"
|
|
58
|
+
],
|
|
59
|
+
absolute: false
|
|
60
|
+
});
|
|
61
|
+
return files.map((relativePath) => ({
|
|
62
|
+
relativePath,
|
|
63
|
+
absolutePath: resolve(configDir, relativePath)
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
function extractComponentName(filePath) {
|
|
67
|
+
const parts = filePath.replace(/\\/g, "/").split("/");
|
|
68
|
+
const fileName = parts[parts.length - 1];
|
|
69
|
+
if (fileName === "index.tsx" || fileName === "index.ts") {
|
|
70
|
+
return parts[parts.length - 2] ?? "Unknown";
|
|
71
|
+
}
|
|
72
|
+
return fileName.replace(/\.(tsx?|jsx?)$/, "");
|
|
73
|
+
}
|
|
74
|
+
var DEFAULT_COMPONENT_PATTERNS = [
|
|
75
|
+
"src/components/**/*.tsx",
|
|
76
|
+
"src/components/**/index.tsx",
|
|
77
|
+
"components/**/*.tsx",
|
|
78
|
+
"lib/components/**/*.tsx",
|
|
79
|
+
"packages/*/src/components/**/*.tsx"
|
|
80
|
+
];
|
|
81
|
+
var DEFAULT_EXCLUDE_PATTERNS = [
|
|
82
|
+
"**/*.test.*",
|
|
83
|
+
"**/*.spec.*",
|
|
84
|
+
"**/*.stories.*",
|
|
85
|
+
"**/*.story.*",
|
|
86
|
+
"**/__tests__/**",
|
|
87
|
+
"**/__mocks__/**",
|
|
88
|
+
"**/node_modules/**",
|
|
89
|
+
"**/dist/**"
|
|
90
|
+
];
|
|
91
|
+
async function discoverComponentsFromSource(configDir, patterns, exclude) {
|
|
92
|
+
const searchPatterns = patterns && patterns.length > 0 ? patterns : DEFAULT_COMPONENT_PATTERNS;
|
|
93
|
+
const excludePatterns = [
|
|
94
|
+
...DEFAULT_EXCLUDE_PATTERNS,
|
|
95
|
+
...exclude ?? []
|
|
96
|
+
];
|
|
97
|
+
const files = await fg(searchPatterns, {
|
|
98
|
+
cwd: configDir,
|
|
99
|
+
ignore: excludePatterns,
|
|
100
|
+
absolute: false
|
|
101
|
+
});
|
|
102
|
+
const componentFiles = files.filter((file) => {
|
|
103
|
+
const name = extractComponentName(file);
|
|
104
|
+
return /^[A-Z]/.test(name);
|
|
105
|
+
});
|
|
106
|
+
const storyPatterns = [
|
|
107
|
+
"**/*.stories.tsx",
|
|
108
|
+
"**/*.stories.ts",
|
|
109
|
+
"**/*.story.tsx",
|
|
110
|
+
"**/*.story.ts"
|
|
111
|
+
];
|
|
112
|
+
const storyFiles = await fg(storyPatterns, {
|
|
113
|
+
cwd: configDir,
|
|
114
|
+
ignore: ["**/node_modules/**", "**/dist/**"],
|
|
115
|
+
absolute: false
|
|
116
|
+
});
|
|
117
|
+
const storyMap = /* @__PURE__ */ new Map();
|
|
118
|
+
for (const storyFile of storyFiles) {
|
|
119
|
+
const name = extractComponentName(storyFile.replace(/\.stories?\.(tsx?|jsx?)$/, ".tsx"));
|
|
120
|
+
storyMap.set(name, storyFile);
|
|
121
|
+
}
|
|
122
|
+
const components = [];
|
|
123
|
+
for (const file of componentFiles) {
|
|
124
|
+
const name = extractComponentName(file);
|
|
125
|
+
const absolutePath = resolve(configDir, file);
|
|
126
|
+
const storyFile = storyMap.get(name);
|
|
127
|
+
components.push({
|
|
128
|
+
name,
|
|
129
|
+
sourcePath: absolutePath,
|
|
130
|
+
relativePath: file,
|
|
131
|
+
storyPath: storyFile ? resolve(configDir, storyFile) : void 0
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
components.sort((a, b) => a.name.localeCompare(b.name));
|
|
135
|
+
return components;
|
|
136
|
+
}
|
|
137
|
+
async function discoverComponentsFromBarrel(barrelPath, configDir) {
|
|
138
|
+
const absoluteBarrelPath = resolve(configDir, barrelPath);
|
|
139
|
+
if (!existsSync(absoluteBarrelPath)) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
const content = await readFile(absoluteBarrelPath, "utf-8");
|
|
143
|
+
const components = [];
|
|
144
|
+
const exportRegex = /export\s+(?:\*|{([^}]+)})\s+from\s+['"]([^'"]+)['"]/g;
|
|
145
|
+
let match;
|
|
146
|
+
while ((match = exportRegex.exec(content)) !== null) {
|
|
147
|
+
const exportedNames = match[1];
|
|
148
|
+
const importPath = match[2];
|
|
149
|
+
const barrelDir = dirname(absoluteBarrelPath);
|
|
150
|
+
let resolvedPath = resolve(barrelDir, importPath);
|
|
151
|
+
if (!resolvedPath.endsWith(".tsx") && !resolvedPath.endsWith(".ts")) {
|
|
152
|
+
if (existsSync(`${resolvedPath}.tsx`)) {
|
|
153
|
+
resolvedPath = `${resolvedPath}.tsx`;
|
|
154
|
+
} else if (existsSync(`${resolvedPath}.ts`)) {
|
|
155
|
+
resolvedPath = `${resolvedPath}.ts`;
|
|
156
|
+
} else if (existsSync(`${resolvedPath}/index.tsx`)) {
|
|
157
|
+
resolvedPath = `${resolvedPath}/index.tsx`;
|
|
158
|
+
} else if (existsSync(`${resolvedPath}/index.ts`)) {
|
|
159
|
+
resolvedPath = `${resolvedPath}/index.ts`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (!existsSync(resolvedPath)) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (exportedNames) {
|
|
166
|
+
const names = exportedNames.split(",").map((n) => n.trim().split(/\s+as\s+/)[0].trim());
|
|
167
|
+
for (const name of names) {
|
|
168
|
+
if (/^[A-Z]/.test(name)) {
|
|
169
|
+
const relativePath = resolvedPath.replace(configDir + "/", "");
|
|
170
|
+
components.push({
|
|
171
|
+
name,
|
|
172
|
+
sourcePath: resolvedPath,
|
|
173
|
+
relativePath
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} else {
|
|
178
|
+
const name = extractComponentName(importPath);
|
|
179
|
+
if (/^[A-Z]/.test(name)) {
|
|
180
|
+
const relativePath = resolvedPath.replace(configDir + "/", "");
|
|
181
|
+
components.push({
|
|
182
|
+
name,
|
|
183
|
+
sourcePath: resolvedPath,
|
|
184
|
+
relativePath
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return components;
|
|
190
|
+
}
|
|
191
|
+
var DEFAULT_TOKEN_PATTERNS = [
|
|
192
|
+
"src/**/tokens/**/_variables.scss",
|
|
193
|
+
"src/**/tokens/**/variables.scss",
|
|
194
|
+
"src/**/styles/**/variables.scss",
|
|
195
|
+
"src/**/styles/**/tokens.scss",
|
|
196
|
+
"src/**/styles/**/variables.css",
|
|
197
|
+
"src/**/theme/**/_variables.scss",
|
|
198
|
+
"src/**/theme/**/tokens.css"
|
|
199
|
+
];
|
|
200
|
+
async function discoverTokenFiles(configDir, patterns, exclude) {
|
|
201
|
+
const searchPatterns = patterns && patterns.length > 0 ? patterns : DEFAULT_TOKEN_PATTERNS;
|
|
202
|
+
const files = await fg(searchPatterns, {
|
|
203
|
+
cwd: configDir,
|
|
204
|
+
ignore: exclude ?? ["**/node_modules/**", "**/dist/**"],
|
|
205
|
+
absolute: false
|
|
206
|
+
});
|
|
207
|
+
return files.map((relativePath) => ({
|
|
208
|
+
relativePath,
|
|
209
|
+
absolutePath: resolve(configDir, relativePath)
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
async function discoverInstalledFragments(projectRoot) {
|
|
213
|
+
const pkgJsonPath = resolve(projectRoot, "package.json");
|
|
214
|
+
if (!existsSync(pkgJsonPath)) return [];
|
|
215
|
+
const pkgJson = JSON.parse(await readFile(pkgJsonPath, "utf-8"));
|
|
216
|
+
const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
|
|
217
|
+
const results = [];
|
|
218
|
+
for (const depName of Object.keys(allDeps)) {
|
|
219
|
+
const depDir = resolve(projectRoot, "node_modules", depName);
|
|
220
|
+
const depPkgPath = resolve(depDir, "package.json");
|
|
221
|
+
if (!existsSync(depPkgPath)) continue;
|
|
222
|
+
const depPkg = JSON.parse(await readFile(depPkgPath, "utf-8"));
|
|
223
|
+
if (!depPkg.fragments) continue;
|
|
224
|
+
const files = await fg(
|
|
225
|
+
[`src/**/*${BRAND.fileExtension}`, "src/**/*.stories.tsx"],
|
|
226
|
+
{ cwd: depDir, ignore: ["**/node_modules/**"], absolute: false }
|
|
227
|
+
);
|
|
228
|
+
for (const rel of files) {
|
|
229
|
+
results.push({
|
|
230
|
+
relativePath: `${depName}/${rel}`,
|
|
231
|
+
absolutePath: resolve(depDir, rel)
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return results;
|
|
236
|
+
}
|
|
237
|
+
async function discoverAllComponents(configDir, options = {}) {
|
|
238
|
+
const componentsMap = /* @__PURE__ */ new Map();
|
|
239
|
+
const sourceComponents = await discoverComponentsFromSource(
|
|
240
|
+
configDir,
|
|
241
|
+
options.patterns,
|
|
242
|
+
options.exclude
|
|
243
|
+
);
|
|
244
|
+
for (const comp of sourceComponents) {
|
|
245
|
+
componentsMap.set(comp.name, comp);
|
|
246
|
+
}
|
|
247
|
+
if (options.barrelFiles && options.barrelFiles.length > 0) {
|
|
248
|
+
for (const barrelFile of options.barrelFiles) {
|
|
249
|
+
const barrelComponents = await discoverComponentsFromBarrel(barrelFile, configDir);
|
|
250
|
+
for (const comp of barrelComponents) {
|
|
251
|
+
if (!componentsMap.has(comp.name)) {
|
|
252
|
+
componentsMap.set(comp.name, comp);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return Array.from(componentsMap.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export {
|
|
261
|
+
discoverBlockFiles,
|
|
262
|
+
discoverRecipeFiles,
|
|
263
|
+
discoverFragmentFiles,
|
|
264
|
+
discoverComponentFiles,
|
|
265
|
+
extractComponentName,
|
|
266
|
+
discoverComponentsFromSource,
|
|
267
|
+
discoverComponentsFromBarrel,
|
|
268
|
+
discoverTokenFiles,
|
|
269
|
+
discoverInstalledFragments,
|
|
270
|
+
discoverAllComponents
|
|
271
|
+
};
|
|
272
|
+
//# sourceMappingURL=chunk-AWYCDRPG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/discovery.ts"],"sourcesContent":["import { resolve, dirname, basename } from 'node:path';\nimport { readFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport fg from 'fast-glob';\nimport type { FragmentsConfig } from './types.js';\nimport { BRAND } from './constants.js';\n\nexport interface DiscoveredFile {\n /** Absolute path to the file */\n absolutePath: string;\n /** Path relative to config directory */\n relativePath: string;\n}\n\n/**\n * Discovered component with source file information\n */\nexport interface DiscoveredComponent {\n /** Component name (e.g., \"Button\") */\n name: string;\n /** Absolute path to the component source file */\n sourcePath: string;\n /** Path relative to config directory */\n relativePath: string;\n /** Path to storybook file if found */\n storyPath?: string;\n}\n\n/**\n * Discover block files (*.block.ts) under the config directory.\n * Also discovers legacy *.recipe.ts files for backward compatibility.\n */\nexport async function discoverBlockFiles(\n configDir: string,\n exclude?: string[]\n): Promise<DiscoveredFile[]> {\n const patterns = [\n `**/*${BRAND.blockFileExtension}`,\n `**/*${BRAND.recipeFileExtension}`,\n ];\n const files = await fg(patterns, {\n cwd: configDir,\n ignore: exclude ?? ['**/node_modules/**', '**/dist/**'],\n absolute: false,\n });\n\n return files.map((relativePath) => ({\n relativePath,\n absolutePath: resolve(configDir, relativePath),\n }));\n}\n\n/**\n * @deprecated Use discoverBlockFiles instead\n */\nexport const discoverRecipeFiles = discoverBlockFiles;\n\n/**\n * Discover fragment files matching the config patterns\n */\nexport async function discoverFragmentFiles(\n config: FragmentsConfig,\n configDir: string\n): Promise<DiscoveredFile[]> {\n const defaultExcludes = [\n '**/*.test.stories.*',\n '**/*.stories.test.*',\n '**/*.test.story.*',\n '**/*.story.test.*',\n ];\n const files = await fg(config.include, {\n cwd: configDir,\n ignore: [...defaultExcludes, ...(config.exclude ?? [])],\n absolute: false,\n });\n\n return files.map((relativePath) => ({\n relativePath,\n absolutePath: resolve(configDir, relativePath),\n }));\n}\n\n/**\n * Discover component files for coverage validation\n */\nexport async function discoverComponentFiles(\n config: FragmentsConfig,\n configDir: string\n): Promise<DiscoveredFile[]> {\n if (!config.components || config.components.length === 0) {\n return [];\n }\n\n const files = await fg(config.components, {\n cwd: configDir,\n ignore: [\n ...(config.exclude ?? []),\n // Exclude fragment files themselves\n ...config.include,\n // Exclude test files\n '**/*.test.*',\n '**/*.spec.*',\n '**/__tests__/**',\n ],\n absolute: false,\n });\n\n return files.map((relativePath) => ({\n relativePath,\n absolutePath: resolve(configDir, relativePath),\n }));\n}\n\n/**\n * Extract component name from file path\n */\nexport function extractComponentName(filePath: string): string {\n // Handle index.tsx files - use parent directory name\n const parts = filePath.replace(/\\\\/g, '/').split('/');\n const fileName = parts[parts.length - 1];\n\n if (fileName === 'index.tsx' || fileName === 'index.ts') {\n return parts[parts.length - 2] ?? 'Unknown';\n }\n\n // Remove extension\n return fileName.replace(/\\.(tsx?|jsx?)$/, '');\n}\n\n/**\n * Default patterns for component discovery\n */\nconst DEFAULT_COMPONENT_PATTERNS = [\n 'src/components/**/*.tsx',\n 'src/components/**/index.tsx',\n 'components/**/*.tsx',\n 'lib/components/**/*.tsx',\n 'packages/*/src/components/**/*.tsx',\n];\n\n/**\n * Patterns to exclude from component discovery\n */\nconst DEFAULT_EXCLUDE_PATTERNS = [\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*',\n '**/*.story.*',\n '**/__tests__/**',\n '**/__mocks__/**',\n '**/node_modules/**',\n '**/dist/**',\n];\n\n/**\n * Discover components from source files\n *\n * This function finds React components by:\n * 1. Looking for TypeScript/TSX files in common component directories\n * 2. Filtering out test files, stories, and internal files\n * 3. Extracting component names from file names or directories\n */\nexport async function discoverComponentsFromSource(\n configDir: string,\n patterns?: string[],\n exclude?: string[]\n): Promise<DiscoveredComponent[]> {\n const searchPatterns = patterns && patterns.length > 0\n ? patterns\n : DEFAULT_COMPONENT_PATTERNS;\n\n const excludePatterns = [\n ...DEFAULT_EXCLUDE_PATTERNS,\n ...(exclude ?? []),\n ];\n\n const files = await fg(searchPatterns, {\n cwd: configDir,\n ignore: excludePatterns,\n absolute: false,\n });\n\n // Filter to only component-like files (start with uppercase)\n const componentFiles = files.filter((file) => {\n const name = extractComponentName(file);\n return /^[A-Z]/.test(name);\n });\n\n // Find associated story files\n const storyPatterns = [\n '**/*.stories.tsx',\n '**/*.stories.ts',\n '**/*.story.tsx',\n '**/*.story.ts',\n ];\n\n const storyFiles = await fg(storyPatterns, {\n cwd: configDir,\n ignore: ['**/node_modules/**', '**/dist/**'],\n absolute: false,\n });\n\n const storyMap = new Map<string, string>();\n for (const storyFile of storyFiles) {\n const name = extractComponentName(storyFile.replace(/\\.stories?\\.(tsx?|jsx?)$/, '.tsx'));\n storyMap.set(name, storyFile);\n }\n\n // Build discovered components\n const components: DiscoveredComponent[] = [];\n\n for (const file of componentFiles) {\n const name = extractComponentName(file);\n const absolutePath = resolve(configDir, file);\n\n // Look for story file\n const storyFile = storyMap.get(name);\n\n components.push({\n name,\n sourcePath: absolutePath,\n relativePath: file,\n storyPath: storyFile ? resolve(configDir, storyFile) : undefined,\n });\n }\n\n // Sort by name\n components.sort((a, b) => a.name.localeCompare(b.name));\n\n return components;\n}\n\n/**\n * Discover components from a barrel export file (index.ts)\n *\n * Parses the barrel file to find exported components.\n * This is useful for libraries that expose components through a single entry point.\n */\nexport async function discoverComponentsFromBarrel(\n barrelPath: string,\n configDir: string\n): Promise<DiscoveredComponent[]> {\n const absoluteBarrelPath = resolve(configDir, barrelPath);\n\n if (!existsSync(absoluteBarrelPath)) {\n return [];\n }\n\n const content = await readFile(absoluteBarrelPath, 'utf-8');\n const components: DiscoveredComponent[] = [];\n\n // Match export statements like:\n // export { Button } from './Button'\n // export { Card, CardHeader } from './Card'\n // export * from './Modal'\n const exportRegex = /export\\s+(?:\\*|{([^}]+)})\\s+from\\s+['\"]([^'\"]+)['\"]/g;\n\n let match;\n while ((match = exportRegex.exec(content)) !== null) {\n const exportedNames = match[1];\n const importPath = match[2];\n\n // Resolve the import path\n const barrelDir = dirname(absoluteBarrelPath);\n let resolvedPath = resolve(barrelDir, importPath);\n\n // Add extension if needed\n if (!resolvedPath.endsWith('.tsx') && !resolvedPath.endsWith('.ts')) {\n if (existsSync(`${resolvedPath}.tsx`)) {\n resolvedPath = `${resolvedPath}.tsx`;\n } else if (existsSync(`${resolvedPath}.ts`)) {\n resolvedPath = `${resolvedPath}.ts`;\n } else if (existsSync(`${resolvedPath}/index.tsx`)) {\n resolvedPath = `${resolvedPath}/index.tsx`;\n } else if (existsSync(`${resolvedPath}/index.ts`)) {\n resolvedPath = `${resolvedPath}/index.ts`;\n }\n }\n\n if (!existsSync(resolvedPath)) {\n continue;\n }\n\n if (exportedNames) {\n // Named exports: { Button, Card }\n const names = exportedNames.split(',').map((n) => n.trim().split(/\\s+as\\s+/)[0].trim());\n for (const name of names) {\n if (/^[A-Z]/.test(name)) {\n const relativePath = resolvedPath.replace(configDir + '/', '');\n components.push({\n name,\n sourcePath: resolvedPath,\n relativePath,\n });\n }\n }\n } else {\n // Star export: export * from './Component'\n const name = extractComponentName(importPath);\n if (/^[A-Z]/.test(name)) {\n const relativePath = resolvedPath.replace(configDir + '/', '');\n components.push({\n name,\n sourcePath: resolvedPath,\n relativePath,\n });\n }\n }\n }\n\n return components;\n}\n\n/**\n * Default glob patterns for discovering token files (SCSS/CSS with custom properties)\n */\nconst DEFAULT_TOKEN_PATTERNS = [\n 'src/**/tokens/**/_variables.scss',\n 'src/**/tokens/**/variables.scss',\n 'src/**/styles/**/variables.scss',\n 'src/**/styles/**/tokens.scss',\n 'src/**/styles/**/variables.css',\n 'src/**/theme/**/_variables.scss',\n 'src/**/theme/**/tokens.css',\n];\n\n/**\n * Discover token files (SCSS/CSS files containing CSS custom properties).\n * Uses config.tokens.include patterns if provided, otherwise falls back\n * to default patterns that match common project structures.\n */\nexport async function discoverTokenFiles(\n configDir: string,\n patterns?: string[],\n exclude?: string[]\n): Promise<DiscoveredFile[]> {\n const searchPatterns = patterns && patterns.length > 0\n ? patterns\n : DEFAULT_TOKEN_PATTERNS;\n\n const files = await fg(searchPatterns, {\n cwd: configDir,\n ignore: exclude ?? ['**/node_modules/**', '**/dist/**'],\n absolute: false,\n });\n\n return files.map((relativePath) => ({\n relativePath,\n absolutePath: resolve(configDir, relativePath),\n }));\n}\n\n/**\n * Discover fragment files from installed packages that declare a \"fragments\" field\n * in their package.json. This allows consumer projects to see components from\n * installed packages (e.g. @fragments-sdk/ui) in the dev viewer.\n */\nexport async function discoverInstalledFragments(\n projectRoot: string\n): Promise<DiscoveredFile[]> {\n const pkgJsonPath = resolve(projectRoot, 'package.json');\n if (!existsSync(pkgJsonPath)) return [];\n\n const pkgJson = JSON.parse(await readFile(pkgJsonPath, 'utf-8'));\n const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };\n const results: DiscoveredFile[] = [];\n\n for (const depName of Object.keys(allDeps)) {\n const depDir = resolve(projectRoot, 'node_modules', depName);\n const depPkgPath = resolve(depDir, 'package.json');\n if (!existsSync(depPkgPath)) continue;\n\n const depPkg = JSON.parse(await readFile(depPkgPath, 'utf-8'));\n if (!depPkg.fragments) continue;\n\n // Package declares fragments — scan for source fragment files\n const files = await fg(\n [`src/**/*${BRAND.fileExtension}`, 'src/**/*.stories.tsx'],\n { cwd: depDir, ignore: ['**/node_modules/**'], absolute: false }\n );\n\n for (const rel of files) {\n results.push({\n relativePath: `${depName}/${rel}`,\n absolutePath: resolve(depDir, rel),\n });\n }\n }\n\n return results;\n}\n\n/**\n * Discover all components using multiple strategies\n */\nexport async function discoverAllComponents(\n configDir: string,\n options: {\n patterns?: string[];\n exclude?: string[];\n barrelFiles?: string[];\n } = {}\n): Promise<DiscoveredComponent[]> {\n const componentsMap = new Map<string, DiscoveredComponent>();\n\n // Discover from source files\n const sourceComponents = await discoverComponentsFromSource(\n configDir,\n options.patterns,\n options.exclude\n );\n\n for (const comp of sourceComponents) {\n componentsMap.set(comp.name, comp);\n }\n\n // Discover from barrel files if specified\n if (options.barrelFiles && options.barrelFiles.length > 0) {\n for (const barrelFile of options.barrelFiles) {\n const barrelComponents = await discoverComponentsFromBarrel(barrelFile, configDir);\n for (const comp of barrelComponents) {\n // Only add if not already found\n if (!componentsMap.has(comp.name)) {\n componentsMap.set(comp.name, comp);\n }\n }\n }\n }\n\n return Array.from(componentsMap.values()).sort((a, b) => a.name.localeCompare(b.name));\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/core/constants.ts
|
|
4
|
+
var BRAND = {
|
|
5
|
+
/** Display name (e.g., "Fragments") */
|
|
6
|
+
name: "Fragments",
|
|
7
|
+
/** Lowercase name for file paths and CLI (e.g., "fragments") */
|
|
8
|
+
nameLower: "fragments",
|
|
9
|
+
/** File extension for fragment definition files (e.g., ".fragment.tsx") */
|
|
10
|
+
fileExtension: ".fragment.tsx",
|
|
11
|
+
/** Legacy file extension for segments (still supported for migration) */
|
|
12
|
+
legacyFileExtension: ".segment.tsx",
|
|
13
|
+
/** JSON file extension for compiled output */
|
|
14
|
+
jsonExtension: ".fragment.json",
|
|
15
|
+
/** Default output file name (e.g., "fragments.json") */
|
|
16
|
+
outFile: "fragments.json",
|
|
17
|
+
/** Config file name (e.g., "fragments.config.ts") */
|
|
18
|
+
configFile: "fragments.config.ts",
|
|
19
|
+
/** Legacy config file name (still supported for migration) */
|
|
20
|
+
legacyConfigFile: "segments.config.ts",
|
|
21
|
+
/** CLI command name (e.g., "fragments") */
|
|
22
|
+
cliCommand: "fragments",
|
|
23
|
+
/** Package scope (e.g., "@fragments") */
|
|
24
|
+
packageScope: "@fragments",
|
|
25
|
+
/** Directory for storing fragments, registry, and cache */
|
|
26
|
+
dataDir: ".fragments",
|
|
27
|
+
/** Components subdirectory within .fragments/ */
|
|
28
|
+
componentsDir: "components",
|
|
29
|
+
/** Registry file name */
|
|
30
|
+
registryFile: "registry.json",
|
|
31
|
+
/** Context file name (AI-ready markdown) */
|
|
32
|
+
contextFile: "context.md",
|
|
33
|
+
/** Screenshots subdirectory */
|
|
34
|
+
screenshotsDir: "screenshots",
|
|
35
|
+
/** Cache subdirectory (gitignored) */
|
|
36
|
+
cacheDir: "cache",
|
|
37
|
+
/** Diff output subdirectory (gitignored) */
|
|
38
|
+
diffDir: "diff",
|
|
39
|
+
/** Manifest filename */
|
|
40
|
+
manifestFile: "manifest.json",
|
|
41
|
+
/** Prefix for localStorage keys (e.g., "fragments-") */
|
|
42
|
+
storagePrefix: "fragments-",
|
|
43
|
+
/** Static viewer HTML file name */
|
|
44
|
+
viewerHtmlFile: "fragments-viewer.html",
|
|
45
|
+
/** MCP tool name prefix (e.g., "fragments_") */
|
|
46
|
+
mcpToolPrefix: "fragments_",
|
|
47
|
+
/** File extension for block definition files */
|
|
48
|
+
blockFileExtension: ".block.ts",
|
|
49
|
+
/** @deprecated Use blockFileExtension instead */
|
|
50
|
+
recipeFileExtension: ".recipe.ts",
|
|
51
|
+
/** Vite plugin namespace */
|
|
52
|
+
vitePluginNamespace: "fragments-core-shim"
|
|
53
|
+
};
|
|
54
|
+
var DEFAULTS = {
|
|
55
|
+
/** Default viewport dimensions */
|
|
56
|
+
viewport: {
|
|
57
|
+
width: 1280,
|
|
58
|
+
height: 800
|
|
59
|
+
},
|
|
60
|
+
/** Default diff threshold (percentage) */
|
|
61
|
+
diffThreshold: 5,
|
|
62
|
+
/** Browser pool size */
|
|
63
|
+
poolSize: 3,
|
|
64
|
+
/** Idle timeout before browser shutdown (ms) - 5 minutes */
|
|
65
|
+
idleTimeoutMs: 5 * 60 * 1e3,
|
|
66
|
+
/** Delay after render before capture (ms) */
|
|
67
|
+
captureDelayMs: 100,
|
|
68
|
+
/** Font loading timeout (ms) */
|
|
69
|
+
fontTimeoutMs: 3e3,
|
|
70
|
+
/** Default theme */
|
|
71
|
+
theme: "light",
|
|
72
|
+
/** Dev server port */
|
|
73
|
+
port: 6006
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export {
|
|
77
|
+
BRAND,
|
|
78
|
+
DEFAULTS
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=chunk-EKLMXTWU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/constants.ts"],"sourcesContent":["/**\n * Brand constants for easy rebranding if domain availability requires it.\n * All naming throughout the codebase should reference these constants.\n */\nexport const BRAND = {\n /** Display name (e.g., \"Fragments\") */\n name: \"Fragments\",\n\n /** Lowercase name for file paths and CLI (e.g., \"fragments\") */\n nameLower: \"fragments\",\n\n /** File extension for fragment definition files (e.g., \".fragment.tsx\") */\n fileExtension: \".fragment.tsx\",\n\n /** Legacy file extension for segments (still supported for migration) */\n legacyFileExtension: \".segment.tsx\",\n\n /** JSON file extension for compiled output */\n jsonExtension: \".fragment.json\",\n\n /** Default output file name (e.g., \"fragments.json\") */\n outFile: \"fragments.json\",\n\n /** Config file name (e.g., \"fragments.config.ts\") */\n configFile: \"fragments.config.ts\",\n\n /** Legacy config file name (still supported for migration) */\n legacyConfigFile: \"segments.config.ts\",\n\n /** CLI command name (e.g., \"fragments\") */\n cliCommand: \"fragments\",\n\n /** Package scope (e.g., \"@fragments\") */\n packageScope: \"@fragments\",\n\n /** Directory for storing fragments, registry, and cache */\n dataDir: \".fragments\",\n\n /** Components subdirectory within .fragments/ */\n componentsDir: \"components\",\n\n /** Registry file name */\n registryFile: \"registry.json\",\n\n /** Context file name (AI-ready markdown) */\n contextFile: \"context.md\",\n\n /** Screenshots subdirectory */\n screenshotsDir: \"screenshots\",\n\n /** Cache subdirectory (gitignored) */\n cacheDir: \"cache\",\n\n /** Diff output subdirectory (gitignored) */\n diffDir: \"diff\",\n\n /** Manifest filename */\n manifestFile: \"manifest.json\",\n\n /** Prefix for localStorage keys (e.g., \"fragments-\") */\n storagePrefix: \"fragments-\",\n\n /** Static viewer HTML file name */\n viewerHtmlFile: \"fragments-viewer.html\",\n\n /** MCP tool name prefix (e.g., \"fragments_\") */\n mcpToolPrefix: \"fragments_\",\n\n /** File extension for block definition files */\n blockFileExtension: \".block.ts\",\n\n /** @deprecated Use blockFileExtension instead */\n recipeFileExtension: \".recipe.ts\",\n\n /** Vite plugin namespace */\n vitePluginNamespace: \"fragments-core-shim\",\n} as const;\n\nexport type Brand = typeof BRAND;\n\n/**\n * Default configuration values for the service.\n * These can be overridden in fragments.config.ts\n */\nexport const DEFAULTS = {\n /** Default viewport dimensions */\n viewport: {\n width: 1280,\n height: 800,\n },\n\n /** Default diff threshold (percentage) */\n diffThreshold: 5,\n\n /** Browser pool size */\n poolSize: 3,\n\n /** Idle timeout before browser shutdown (ms) - 5 minutes */\n idleTimeoutMs: 5 * 60 * 1000,\n\n /** Delay after render before capture (ms) */\n captureDelayMs: 100,\n\n /** Font loading timeout (ms) */\n fontTimeoutMs: 3000,\n\n /** Default theme */\n theme: \"light\" as const,\n\n /** Dev server port */\n port: 6006,\n} as const;\n\nexport type Defaults = typeof DEFAULTS;\n"],"mappings":";;;AAIO,IAAM,QAAQ;AAAA;AAAA,EAEnB,MAAM;AAAA;AAAA,EAGN,WAAW;AAAA;AAAA,EAGX,eAAe;AAAA;AAAA,EAGf,qBAAqB;AAAA;AAAA,EAGrB,eAAe;AAAA;AAAA,EAGf,SAAS;AAAA;AAAA,EAGT,YAAY;AAAA;AAAA,EAGZ,kBAAkB;AAAA;AAAA,EAGlB,YAAY;AAAA;AAAA,EAGZ,cAAc;AAAA;AAAA,EAGd,SAAS;AAAA;AAAA,EAGT,eAAe;AAAA;AAAA,EAGf,cAAc;AAAA;AAAA,EAGd,aAAa;AAAA;AAAA,EAGb,gBAAgB;AAAA;AAAA,EAGhB,UAAU;AAAA;AAAA,EAGV,SAAS;AAAA;AAAA,EAGT,cAAc;AAAA;AAAA,EAGd,eAAe;AAAA;AAAA,EAGf,gBAAgB;AAAA;AAAA,EAGhB,eAAe;AAAA;AAAA,EAGf,oBAAoB;AAAA;AAAA,EAGpB,qBAAqB;AAAA;AAAA,EAGrB,qBAAqB;AACvB;AAQO,IAAM,WAAW;AAAA;AAAA,EAEtB,UAAU;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AAAA;AAAA,EAGA,eAAe;AAAA;AAAA,EAGf,UAAU;AAAA;AAAA,EAGV,eAAe,IAAI,KAAK;AAAA;AAAA,EAGxB,gBAAgB;AAAA;AAAA,EAGhB,eAAe;AAAA;AAAA,EAGf,OAAO;AAAA;AAAA,EAGP,MAAM;AACR;","names":[]}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
loadConfig
|
|
4
|
+
} from "./chunk-R6IZZSE7.js";
|
|
5
|
+
import {
|
|
6
|
+
discoverAllComponents
|
|
7
|
+
} from "./chunk-AWYCDRPG.js";
|
|
2
8
|
import {
|
|
3
9
|
convertToFragmentProps,
|
|
4
10
|
extractPropsFromFile,
|
|
@@ -8,14 +14,10 @@ import {
|
|
|
8
14
|
inferAllRelations,
|
|
9
15
|
parseAllStories,
|
|
10
16
|
scanCodebase
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import {
|
|
13
|
-
discoverAllComponents,
|
|
14
|
-
loadConfig
|
|
15
|
-
} from "./chunk-3T6QL7IY.js";
|
|
17
|
+
} from "./chunk-YMPGYEWK.js";
|
|
16
18
|
import {
|
|
17
19
|
BRAND
|
|
18
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-EKLMXTWU.js";
|
|
19
21
|
|
|
20
22
|
// src/commands/scan.ts
|
|
21
23
|
import { writeFile, mkdir } from "fs/promises";
|
|
@@ -366,4 +368,4 @@ function calculateConfidence(props, usageAnalysis, storyFile) {
|
|
|
366
368
|
export {
|
|
367
369
|
scan
|
|
368
370
|
};
|
|
369
|
-
//# sourceMappingURL=chunk-
|
|
371
|
+
//# sourceMappingURL=chunk-NEJ2FBTN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/scan.ts"],"sourcesContent":["/**\n * fragments scan - Zero-config fragments.json generation from source code\n *\n * Automatically extracts component documentation by:\n * 1. Discovering components from source files and barrel exports\n * 2. Extracting props from TypeScript interfaces\n * 3. Scanning codebase for usage patterns\n * 4. Parsing Storybook stories for examples\n * 5. Inferring component relationships from usage data\n * 6. Generating complete fragments.json without manual documentation\n */\n\nimport { writeFile, mkdir } from \"node:fs/promises\";\nimport { resolve, join, dirname, relative } from \"node:path\";\nimport pc from \"picocolors\";\nimport {\n BRAND,\n type CompiledFragmentsFile,\n type CompiledFragment,\n type PropDefinition,\n} from \"../core/index.js\";\nimport {\n loadConfig,\n discoverAllComponents,\n type DiscoveredComponent,\n} from \"../core/node.js\";\nimport {\n scanCodebase,\n extractPropsFromFile,\n parseAllStories,\n inferAllRelations,\n generateComponentContext,\n generateEnhancementSuggestions,\n filterBoilerplate,\n convertToFragmentProps,\n type UsageAnalysis,\n type ComponentRelation,\n type PropsExtractionResult,\n type ParsedStoryFile,\n} from \"../service/index.js\";\n\nexport interface ScanOptions {\n /** Path to config file */\n config?: string;\n /** Output file path (default: fragments.json) */\n output?: string;\n /** Component patterns to scan */\n componentPatterns?: string[];\n /** Barrel export files to parse */\n barrelFiles?: string[];\n /** Directory to scan for usage patterns */\n usageDir?: string;\n /** Skip usage analysis */\n skipUsage?: boolean;\n /** Skip Storybook parsing */\n skipStorybook?: boolean;\n /** Verbose output */\n verbose?: boolean;\n}\n\nexport interface ScanResult {\n success: boolean;\n outputPath: string;\n componentCount: number;\n propsExtracted: number;\n usagesFound: number;\n relationsInferred: number;\n storiesParsed: number;\n errors: Array<{ component: string; error: string }>;\n warnings: Array<{ component: string; warning: string }>;\n}\n\n/**\n * Scan codebase and generate fragments.json directly from source\n */\nexport async function scan(options: ScanOptions = {}): Promise<ScanResult> {\n const startTime = Date.now();\n const errors: Array<{ component: string; error: string }> = [];\n const warnings: Array<{ component: string; warning: string }> = [];\n\n // Load config or use defaults\n let configDir: string;\n let outputFile: string;\n let componentPatterns: string[] | undefined;\n\n try {\n const loaded = await loadConfig(options.config);\n configDir = loaded.configDir;\n outputFile = options.output || loaded.config.outFile || \"fragments.json\";\n componentPatterns = options.componentPatterns || loaded.config.components;\n } catch {\n // No config file, use defaults\n configDir = process.cwd();\n outputFile = options.output || \"fragments.json\";\n componentPatterns = options.componentPatterns;\n }\n\n console.log(pc.cyan(`\\n${BRAND.name} Scan\\n`));\n console.log(pc.dim(\"Zero-config fragments.json generation from source code\\n\"));\n\n // Phase 1: Discover components\n console.log(pc.dim(\"Phase 1: Discovering components...\"));\n const components = await discoverAllComponents(configDir, {\n patterns: componentPatterns,\n exclude: [\"**/*.test.*\", \"**/*.spec.*\", \"**/__tests__/**\"],\n barrelFiles: options.barrelFiles,\n });\n\n if (components.length === 0) {\n console.log(pc.yellow(\"No components found. Check your patterns or config.\"));\n return {\n success: false,\n outputPath: resolve(configDir, outputFile),\n componentCount: 0,\n propsExtracted: 0,\n usagesFound: 0,\n relationsInferred: 0,\n storiesParsed: 0,\n errors: [{ component: \"*\", error: \"No components found\" }],\n warnings: [],\n };\n }\n\n console.log(pc.green(` Found ${components.length} components`));\n if (options.verbose) {\n for (const comp of components.slice(0, 10)) {\n console.log(pc.dim(` - ${comp.name}: ${comp.relativePath}`));\n }\n if (components.length > 10) {\n console.log(pc.dim(` ... and ${components.length - 10} more`));\n }\n }\n\n // Phase 2: Extract props from TypeScript\n console.log(pc.dim(\"\\nPhase 2: Extracting props from TypeScript...\"));\n const propsMap = new Map<string, ReturnType<typeof convertToFragmentProps>>();\n const propsResults = new Map<string, PropsExtractionResult>();\n let propsExtracted = 0;\n\n for (const comp of components) {\n try {\n const extraction = await extractPropsFromFile(comp.sourcePath, {\n propsTypeName: `${comp.name}Props`,\n });\n\n propsResults.set(comp.name, extraction);\n\n if (extraction.success && extraction.props.length > 0) {\n propsMap.set(comp.name, convertToFragmentProps(extraction.props));\n propsExtracted++;\n }\n } catch (e) {\n if (options.verbose) {\n warnings.push({\n component: comp.name,\n warning: `Props extraction failed: ${e instanceof Error ? e.message : String(e)}`,\n });\n }\n }\n }\n\n console.log(pc.green(` Extracted props for ${propsExtracted} components`));\n\n // Phase 3: Scan for usage patterns\n let usageAnalysis: UsageAnalysis | undefined;\n let usagesFound = 0;\n let allRelations = new Map<string, ComponentRelation[]>();\n\n if (!options.skipUsage) {\n console.log(pc.dim(\"\\nPhase 3: Scanning for usage patterns...\"));\n const usageDir = options.usageDir || configDir;\n\n try {\n // Get component names for filtering\n const componentNames = components.map((c) => c.name);\n\n usageAnalysis = await scanCodebase({\n rootDir: usageDir,\n include: [\"**/*.tsx\", \"**/*.ts\", \"**/*.jsx\", \"**/*.js\"],\n exclude: [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/*.stories.*\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n ],\n componentNames,\n useCache: true,\n });\n\n // Count total usages across all components\n usagesFound = Object.values(usageAnalysis.components).reduce(\n (sum, comp) => sum + comp.totalUsages,\n 0\n );\n\n // Infer relations\n allRelations = inferAllRelations(usageAnalysis);\n console.log(pc.green(` Found ${usagesFound} usages across ${usageAnalysis.totalFiles} files`));\n console.log(pc.green(` Inferred relations for ${allRelations.size} components`));\n } catch (e) {\n warnings.push({\n component: \"*\",\n warning: `Usage scanning failed: ${e instanceof Error ? e.message : String(e)}`,\n });\n console.log(pc.yellow(` Usage scanning failed: ${e instanceof Error ? e.message : \"unknown error\"}`));\n }\n } else {\n console.log(pc.dim(\"\\nPhase 3: Skipping usage analysis\"));\n }\n\n // Phase 4: Parse Storybook stories\n const storiesMap = new Map<string, ParsedStoryFile>();\n let storiesParsed = 0;\n\n if (!options.skipStorybook) {\n console.log(pc.dim(\"\\nPhase 4: Parsing Storybook stories...\"));\n\n try {\n const allStories = await parseAllStories(configDir);\n\n for (const [name, stories] of Object.entries(allStories)) {\n if (stories && stories.stories.length > 0) {\n storiesMap.set(name, stories);\n storiesParsed++;\n }\n }\n\n console.log(pc.green(` Parsed stories for ${storiesParsed} components`));\n } catch (e) {\n warnings.push({\n component: \"*\",\n warning: `Storybook parsing failed: ${e instanceof Error ? e.message : String(e)}`,\n });\n console.log(pc.yellow(` Storybook parsing failed: ${e instanceof Error ? e.message : \"unknown error\"}`));\n }\n } else {\n console.log(pc.dim(\"\\nPhase 4: Skipping Storybook parsing\"));\n }\n\n // Phase 5: Generate fragments\n console.log(pc.dim(\"\\nPhase 5: Generating fragments...\"));\n const fragments: Record<string, CompiledFragment> = {};\n\n for (const comp of components) {\n try {\n const fragment = generateFragmentFromData(\n comp,\n configDir,\n propsMap.get(comp.name),\n usageAnalysis?.components[comp.name],\n allRelations.get(comp.name),\n storiesMap.get(comp.name)\n );\n\n fragments[comp.name] = fragment;\n } catch (e) {\n errors.push({\n component: comp.name,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n\n // Write output\n const outputPath = resolve(configDir, outputFile);\n await mkdir(dirname(outputPath), { recursive: true });\n\n const output: CompiledFragmentsFile = {\n version: \"1.0.0\",\n generatedAt: new Date().toISOString(),\n fragments,\n };\n\n await writeFile(outputPath, JSON.stringify(output, null, 2));\n\n const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);\n\n // Summary\n console.log(pc.dim(\"\\n────────────────────────────────────────\"));\n console.log(pc.green(`\\n✓ Generated fragments.json in ${elapsed}s`));\n console.log(pc.dim(` Output: ${relative(process.cwd(), outputPath)}`));\n console.log(pc.dim(` Components: ${Object.keys(fragments).length}`));\n console.log(pc.dim(` Props extracted: ${propsExtracted}`));\n console.log(pc.dim(` Usages found: ${usagesFound}`));\n console.log(pc.dim(` Relations inferred: ${allRelations.size}`));\n console.log(pc.dim(` Stories parsed: ${storiesParsed}`));\n\n if (warnings.length > 0) {\n console.log(pc.yellow(`\\n ${warnings.length} warning(s)`));\n if (options.verbose) {\n for (const w of warnings) {\n console.log(pc.dim(` ${w.component}: ${w.warning}`));\n }\n }\n }\n\n if (errors.length > 0) {\n console.log(pc.red(`\\n ${errors.length} error(s)`));\n for (const e of errors) {\n console.log(pc.dim(` ${e.component}: ${e.error}`));\n }\n }\n\n console.log();\n\n return {\n success: errors.length === 0,\n outputPath,\n componentCount: Object.keys(fragments).length,\n propsExtracted,\n usagesFound,\n relationsInferred: allRelations.size,\n storiesParsed,\n errors,\n warnings,\n };\n}\n\n/**\n * Generate a CompiledFragment from extracted data\n */\nfunction generateFragmentFromData(\n comp: DiscoveredComponent,\n configDir: string,\n props: Record<string, PropDefinition> | undefined,\n usageAnalysis: UsageAnalysis[\"components\"][string] | undefined,\n relations: ComponentRelation[] | undefined,\n storyFile: ParsedStoryFile | undefined\n): CompiledFragment {\n // Generate context for AI suggestions\n const context = generateComponentContext(\n comp.name,\n usageAnalysis,\n undefined, // No extracted docs yet\n storyFile,\n undefined, // No props extraction result (we have the converted props already)\n relations\n );\n\n // Generate enhancement suggestions from context\n const suggestions = generateEnhancementSuggestions(context);\n\n // Filter boilerplate from suggestions\n const when = filterBoilerplate(suggestions.suggestions.when);\n const whenNot = filterBoilerplate(suggestions.suggestions.whenNot);\n\n // Infer category from path\n const category = inferCategory(comp.relativePath);\n\n // Infer status from path\n const status = inferStatus(comp.relativePath);\n\n // Build variants from stories\n const variants: CompiledFragment[\"variants\"] = [];\n if (storyFile?.stories) {\n for (const story of storyFile.stories) {\n variants.push({\n name: story.name,\n description: story.description || `${story.displayName} variant`,\n code: story.code,\n });\n }\n }\n\n // Build relations\n const compiledRelations: CompiledFragment[\"relations\"] = [];\n if (relations && relations.length > 0) {\n for (const rel of relations.slice(0, 10)) {\n compiledRelations.push({\n component: rel.component,\n relationship: rel.relationship,\n note: `Appears together ${rel.frequency} times`,\n });\n }\n }\n\n // Generate description\n const description = generateDescription(comp.name, props, usageAnalysis);\n\n return {\n filePath: comp.relativePath,\n meta: {\n name: comp.name,\n description,\n category,\n status,\n },\n usage: {\n when: when.length > 0 ? when : [`Use ${comp.name} for its intended purpose`],\n whenNot: whenNot,\n },\n props: props || {},\n relations: compiledRelations.length > 0 ? compiledRelations : undefined,\n variants,\n _generated: {\n source: \"ai\",\n sourceFile: comp.relativePath,\n confidence: calculateConfidence(props, usageAnalysis, storyFile),\n timestamp: new Date().toISOString(),\n },\n };\n}\n\n/**\n * Infer category from file path\n */\nfunction inferCategory(relativePath: string): string {\n const parts = relativePath.toLowerCase().split(\"/\");\n\n // Common category patterns\n const categoryPatterns: Record<string, string[]> = {\n \"Actions\": [\"button\", \"action\", \"cta\"],\n \"Forms\": [\"form\", \"input\", \"select\", \"checkbox\", \"radio\", \"textarea\", \"field\"],\n \"Layout\": [\"layout\", \"container\", \"grid\", \"flex\", \"stack\", \"box\", \"divider\", \"spacer\"],\n \"Navigation\": [\"nav\", \"menu\", \"breadcrumb\", \"tab\", \"link\", \"pagination\"],\n \"Feedback\": [\"alert\", \"toast\", \"notification\", \"message\", \"badge\", \"indicator\", \"progress\", \"spinner\", \"loading\"],\n \"Data Display\": [\"table\", \"list\", \"card\", \"avatar\", \"stat\", \"timeline\", \"tree\"],\n \"Overlays\": [\"modal\", \"dialog\", \"drawer\", \"popover\", \"tooltip\", \"dropdown\"],\n \"Typography\": [\"text\", \"heading\", \"title\", \"label\", \"paragraph\"],\n \"Media\": [\"image\", \"video\", \"icon\", \"avatar\"],\n };\n\n for (const [category, patterns] of Object.entries(categoryPatterns)) {\n for (const pattern of patterns) {\n if (parts.some((part) => part.includes(pattern))) {\n return category;\n }\n }\n }\n\n // Check path structure for category\n const componentIdx = parts.findIndex((p) => p === \"components\");\n if (componentIdx !== -1 && parts.length > componentIdx + 1) {\n const categoryPart = parts[componentIdx + 1];\n return categoryPart.charAt(0).toUpperCase() + categoryPart.slice(1);\n }\n\n return \"Components\";\n}\n\n/**\n * Infer status from file path\n */\nfunction inferStatus(\n relativePath: string\n): \"stable\" | \"beta\" | \"experimental\" | \"deprecated\" {\n const lowerPath = relativePath.toLowerCase();\n\n if (lowerPath.includes(\"/experimental/\") || lowerPath.includes(\"/labs/\")) {\n return \"experimental\";\n }\n if (lowerPath.includes(\"/beta/\")) {\n return \"beta\";\n }\n if (lowerPath.includes(\"/deprecated/\") || lowerPath.includes(\"/legacy/\")) {\n return \"deprecated\";\n }\n\n return \"stable\";\n}\n\n/**\n * Generate component description\n */\nfunction generateDescription(\n name: string,\n props: Record<string, PropDefinition> | undefined,\n usageAnalysis: UsageAnalysis[\"components\"][string] | undefined\n): string {\n // Convert name to readable form\n const words = name\n .replace(/([A-Z])/g, \" $1\")\n .trim()\n .toLowerCase();\n\n // Check props for hints\n const hasOnClick = props && (\"onClick\" in props || \"onPress\" in props);\n const hasValue = props && (\"value\" in props || \"defaultValue\" in props);\n const hasChildren = props && \"children\" in props;\n const hasHref = props && \"href\" in props;\n\n // Check usage contexts\n const topContext = usageAnalysis?.contexts[0]?.type;\n\n if (hasHref) {\n return `Navigational ${words} for linking to other pages or resources`;\n }\n\n if (hasOnClick && !hasValue) {\n return `Interactive ${words} for triggering actions`;\n }\n\n if (hasValue) {\n return `Form ${words} for user input`;\n }\n\n if (topContext && topContext !== \"unknown\") {\n return `${words.charAt(0).toUpperCase() + words.slice(1)} commonly used in ${topContext} contexts`;\n }\n\n if (hasChildren) {\n return `Container ${words} for composing UI`;\n }\n\n return `${words.charAt(0).toUpperCase() + words.slice(1)} component`;\n}\n\n/**\n * Calculate confidence score based on available data\n */\nfunction calculateConfidence(\n props: Record<string, PropDefinition> | undefined,\n usageAnalysis: UsageAnalysis[\"components\"][string] | undefined,\n storyFile: ParsedStoryFile | undefined\n): number {\n let confidence = 0;\n\n // Props give +30 confidence\n if (props && Object.keys(props).length > 0) {\n confidence += 30;\n }\n\n // Usage data gives up to +40 confidence\n if (usageAnalysis) {\n if (usageAnalysis.totalUsages > 10) confidence += 40;\n else if (usageAnalysis.totalUsages > 5) confidence += 30;\n else if (usageAnalysis.totalUsages > 0) confidence += 20;\n }\n\n // Stories give +30 confidence\n if (storyFile && storyFile.stories.length > 0) {\n confidence += 30;\n }\n\n return Math.min(confidence, 100);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/commands/scan.ts"],"sourcesContent":["/**\n * fragments scan - Zero-config fragments.json generation from source code\n *\n * Automatically extracts component documentation by:\n * 1. Discovering components from source files and barrel exports\n * 2. Extracting props from TypeScript interfaces\n * 3. Scanning codebase for usage patterns\n * 4. Parsing Storybook stories for examples\n * 5. Inferring component relationships from usage data\n * 6. Generating complete fragments.json without manual documentation\n */\n\nimport { writeFile, mkdir } from \"node:fs/promises\";\nimport { resolve, join, dirname, relative } from \"node:path\";\nimport pc from \"picocolors\";\nimport {\n BRAND,\n type CompiledFragmentsFile,\n type CompiledFragment,\n type PropDefinition,\n} from \"../core/index.js\";\nimport {\n loadConfig,\n discoverAllComponents,\n type DiscoveredComponent,\n} from \"../core/node.js\";\nimport {\n scanCodebase,\n extractPropsFromFile,\n parseAllStories,\n inferAllRelations,\n generateComponentContext,\n generateEnhancementSuggestions,\n filterBoilerplate,\n convertToFragmentProps,\n type UsageAnalysis,\n type ComponentRelation,\n type PropsExtractionResult,\n type ParsedStoryFile,\n} from \"../service/index.js\";\n\nexport interface ScanOptions {\n /** Path to config file */\n config?: string;\n /** Output file path (default: fragments.json) */\n output?: string;\n /** Component patterns to scan */\n componentPatterns?: string[];\n /** Barrel export files to parse */\n barrelFiles?: string[];\n /** Directory to scan for usage patterns */\n usageDir?: string;\n /** Skip usage analysis */\n skipUsage?: boolean;\n /** Skip Storybook parsing */\n skipStorybook?: boolean;\n /** Verbose output */\n verbose?: boolean;\n}\n\nexport interface ScanResult {\n success: boolean;\n outputPath: string;\n componentCount: number;\n propsExtracted: number;\n usagesFound: number;\n relationsInferred: number;\n storiesParsed: number;\n errors: Array<{ component: string; error: string }>;\n warnings: Array<{ component: string; warning: string }>;\n}\n\n/**\n * Scan codebase and generate fragments.json directly from source\n */\nexport async function scan(options: ScanOptions = {}): Promise<ScanResult> {\n const startTime = Date.now();\n const errors: Array<{ component: string; error: string }> = [];\n const warnings: Array<{ component: string; warning: string }> = [];\n\n // Load config or use defaults\n let configDir: string;\n let outputFile: string;\n let componentPatterns: string[] | undefined;\n\n try {\n const loaded = await loadConfig(options.config);\n configDir = loaded.configDir;\n outputFile = options.output || loaded.config.outFile || \"fragments.json\";\n componentPatterns = options.componentPatterns || loaded.config.components;\n } catch {\n // No config file, use defaults\n configDir = process.cwd();\n outputFile = options.output || \"fragments.json\";\n componentPatterns = options.componentPatterns;\n }\n\n console.log(pc.cyan(`\\n${BRAND.name} Scan\\n`));\n console.log(pc.dim(\"Zero-config fragments.json generation from source code\\n\"));\n\n // Phase 1: Discover components\n console.log(pc.dim(\"Phase 1: Discovering components...\"));\n const components = await discoverAllComponents(configDir, {\n patterns: componentPatterns,\n exclude: [\"**/*.test.*\", \"**/*.spec.*\", \"**/__tests__/**\"],\n barrelFiles: options.barrelFiles,\n });\n\n if (components.length === 0) {\n console.log(pc.yellow(\"No components found. Check your patterns or config.\"));\n return {\n success: false,\n outputPath: resolve(configDir, outputFile),\n componentCount: 0,\n propsExtracted: 0,\n usagesFound: 0,\n relationsInferred: 0,\n storiesParsed: 0,\n errors: [{ component: \"*\", error: \"No components found\" }],\n warnings: [],\n };\n }\n\n console.log(pc.green(` Found ${components.length} components`));\n if (options.verbose) {\n for (const comp of components.slice(0, 10)) {\n console.log(pc.dim(` - ${comp.name}: ${comp.relativePath}`));\n }\n if (components.length > 10) {\n console.log(pc.dim(` ... and ${components.length - 10} more`));\n }\n }\n\n // Phase 2: Extract props from TypeScript\n console.log(pc.dim(\"\\nPhase 2: Extracting props from TypeScript...\"));\n const propsMap = new Map<string, ReturnType<typeof convertToFragmentProps>>();\n const propsResults = new Map<string, PropsExtractionResult>();\n let propsExtracted = 0;\n\n for (const comp of components) {\n try {\n const extraction = await extractPropsFromFile(comp.sourcePath, {\n propsTypeName: `${comp.name}Props`,\n });\n\n propsResults.set(comp.name, extraction);\n\n if (extraction.success && extraction.props.length > 0) {\n propsMap.set(comp.name, convertToFragmentProps(extraction.props));\n propsExtracted++;\n }\n } catch (e) {\n if (options.verbose) {\n warnings.push({\n component: comp.name,\n warning: `Props extraction failed: ${e instanceof Error ? e.message : String(e)}`,\n });\n }\n }\n }\n\n console.log(pc.green(` Extracted props for ${propsExtracted} components`));\n\n // Phase 3: Scan for usage patterns\n let usageAnalysis: UsageAnalysis | undefined;\n let usagesFound = 0;\n let allRelations = new Map<string, ComponentRelation[]>();\n\n if (!options.skipUsage) {\n console.log(pc.dim(\"\\nPhase 3: Scanning for usage patterns...\"));\n const usageDir = options.usageDir || configDir;\n\n try {\n // Get component names for filtering\n const componentNames = components.map((c) => c.name);\n\n usageAnalysis = await scanCodebase({\n rootDir: usageDir,\n include: [\"**/*.tsx\", \"**/*.ts\", \"**/*.jsx\", \"**/*.js\"],\n exclude: [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/*.stories.*\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n ],\n componentNames,\n useCache: true,\n });\n\n // Count total usages across all components\n usagesFound = Object.values(usageAnalysis.components).reduce(\n (sum, comp) => sum + comp.totalUsages,\n 0\n );\n\n // Infer relations\n allRelations = inferAllRelations(usageAnalysis);\n console.log(pc.green(` Found ${usagesFound} usages across ${usageAnalysis.totalFiles} files`));\n console.log(pc.green(` Inferred relations for ${allRelations.size} components`));\n } catch (e) {\n warnings.push({\n component: \"*\",\n warning: `Usage scanning failed: ${e instanceof Error ? e.message : String(e)}`,\n });\n console.log(pc.yellow(` Usage scanning failed: ${e instanceof Error ? e.message : \"unknown error\"}`));\n }\n } else {\n console.log(pc.dim(\"\\nPhase 3: Skipping usage analysis\"));\n }\n\n // Phase 4: Parse Storybook stories\n const storiesMap = new Map<string, ParsedStoryFile>();\n let storiesParsed = 0;\n\n if (!options.skipStorybook) {\n console.log(pc.dim(\"\\nPhase 4: Parsing Storybook stories...\"));\n\n try {\n const allStories = await parseAllStories(configDir);\n\n for (const [name, stories] of Object.entries(allStories)) {\n if (stories && stories.stories.length > 0) {\n storiesMap.set(name, stories);\n storiesParsed++;\n }\n }\n\n console.log(pc.green(` Parsed stories for ${storiesParsed} components`));\n } catch (e) {\n warnings.push({\n component: \"*\",\n warning: `Storybook parsing failed: ${e instanceof Error ? e.message : String(e)}`,\n });\n console.log(pc.yellow(` Storybook parsing failed: ${e instanceof Error ? e.message : \"unknown error\"}`));\n }\n } else {\n console.log(pc.dim(\"\\nPhase 4: Skipping Storybook parsing\"));\n }\n\n // Phase 5: Generate fragments\n console.log(pc.dim(\"\\nPhase 5: Generating fragments...\"));\n const fragments: Record<string, CompiledFragment> = {};\n\n for (const comp of components) {\n try {\n const fragment = generateFragmentFromData(\n comp,\n configDir,\n propsMap.get(comp.name),\n usageAnalysis?.components[comp.name],\n allRelations.get(comp.name),\n storiesMap.get(comp.name)\n );\n\n fragments[comp.name] = fragment;\n } catch (e) {\n errors.push({\n component: comp.name,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n\n // Write output\n const outputPath = resolve(configDir, outputFile);\n await mkdir(dirname(outputPath), { recursive: true });\n\n const output: CompiledFragmentsFile = {\n version: \"1.0.0\",\n generatedAt: new Date().toISOString(),\n fragments,\n };\n\n await writeFile(outputPath, JSON.stringify(output, null, 2));\n\n const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);\n\n // Summary\n console.log(pc.dim(\"\\n────────────────────────────────────────\"));\n console.log(pc.green(`\\n✓ Generated fragments.json in ${elapsed}s`));\n console.log(pc.dim(` Output: ${relative(process.cwd(), outputPath)}`));\n console.log(pc.dim(` Components: ${Object.keys(fragments).length}`));\n console.log(pc.dim(` Props extracted: ${propsExtracted}`));\n console.log(pc.dim(` Usages found: ${usagesFound}`));\n console.log(pc.dim(` Relations inferred: ${allRelations.size}`));\n console.log(pc.dim(` Stories parsed: ${storiesParsed}`));\n\n if (warnings.length > 0) {\n console.log(pc.yellow(`\\n ${warnings.length} warning(s)`));\n if (options.verbose) {\n for (const w of warnings) {\n console.log(pc.dim(` ${w.component}: ${w.warning}`));\n }\n }\n }\n\n if (errors.length > 0) {\n console.log(pc.red(`\\n ${errors.length} error(s)`));\n for (const e of errors) {\n console.log(pc.dim(` ${e.component}: ${e.error}`));\n }\n }\n\n console.log();\n\n return {\n success: errors.length === 0,\n outputPath,\n componentCount: Object.keys(fragments).length,\n propsExtracted,\n usagesFound,\n relationsInferred: allRelations.size,\n storiesParsed,\n errors,\n warnings,\n };\n}\n\n/**\n * Generate a CompiledFragment from extracted data\n */\nfunction generateFragmentFromData(\n comp: DiscoveredComponent,\n configDir: string,\n props: Record<string, PropDefinition> | undefined,\n usageAnalysis: UsageAnalysis[\"components\"][string] | undefined,\n relations: ComponentRelation[] | undefined,\n storyFile: ParsedStoryFile | undefined\n): CompiledFragment {\n // Generate context for AI suggestions\n const context = generateComponentContext(\n comp.name,\n usageAnalysis,\n undefined, // No extracted docs yet\n storyFile,\n undefined, // No props extraction result (we have the converted props already)\n relations\n );\n\n // Generate enhancement suggestions from context\n const suggestions = generateEnhancementSuggestions(context);\n\n // Filter boilerplate from suggestions\n const when = filterBoilerplate(suggestions.suggestions.when);\n const whenNot = filterBoilerplate(suggestions.suggestions.whenNot);\n\n // Infer category from path\n const category = inferCategory(comp.relativePath);\n\n // Infer status from path\n const status = inferStatus(comp.relativePath);\n\n // Build variants from stories\n const variants: CompiledFragment[\"variants\"] = [];\n if (storyFile?.stories) {\n for (const story of storyFile.stories) {\n variants.push({\n name: story.name,\n description: story.description || `${story.displayName} variant`,\n code: story.code,\n });\n }\n }\n\n // Build relations\n const compiledRelations: CompiledFragment[\"relations\"] = [];\n if (relations && relations.length > 0) {\n for (const rel of relations.slice(0, 10)) {\n compiledRelations.push({\n component: rel.component,\n relationship: rel.relationship,\n note: `Appears together ${rel.frequency} times`,\n });\n }\n }\n\n // Generate description\n const description = generateDescription(comp.name, props, usageAnalysis);\n\n return {\n filePath: comp.relativePath,\n meta: {\n name: comp.name,\n description,\n category,\n status,\n },\n usage: {\n when: when.length > 0 ? when : [`Use ${comp.name} for its intended purpose`],\n whenNot: whenNot,\n },\n props: props || {},\n relations: compiledRelations.length > 0 ? compiledRelations : undefined,\n variants,\n _generated: {\n source: \"ai\",\n sourceFile: comp.relativePath,\n confidence: calculateConfidence(props, usageAnalysis, storyFile),\n timestamp: new Date().toISOString(),\n },\n };\n}\n\n/**\n * Infer category from file path\n */\nfunction inferCategory(relativePath: string): string {\n const parts = relativePath.toLowerCase().split(\"/\");\n\n // Common category patterns\n const categoryPatterns: Record<string, string[]> = {\n \"Actions\": [\"button\", \"action\", \"cta\"],\n \"Forms\": [\"form\", \"input\", \"select\", \"checkbox\", \"radio\", \"textarea\", \"field\"],\n \"Layout\": [\"layout\", \"container\", \"grid\", \"flex\", \"stack\", \"box\", \"divider\", \"spacer\"],\n \"Navigation\": [\"nav\", \"menu\", \"breadcrumb\", \"tab\", \"link\", \"pagination\"],\n \"Feedback\": [\"alert\", \"toast\", \"notification\", \"message\", \"badge\", \"indicator\", \"progress\", \"spinner\", \"loading\"],\n \"Data Display\": [\"table\", \"list\", \"card\", \"avatar\", \"stat\", \"timeline\", \"tree\"],\n \"Overlays\": [\"modal\", \"dialog\", \"drawer\", \"popover\", \"tooltip\", \"dropdown\"],\n \"Typography\": [\"text\", \"heading\", \"title\", \"label\", \"paragraph\"],\n \"Media\": [\"image\", \"video\", \"icon\", \"avatar\"],\n };\n\n for (const [category, patterns] of Object.entries(categoryPatterns)) {\n for (const pattern of patterns) {\n if (parts.some((part) => part.includes(pattern))) {\n return category;\n }\n }\n }\n\n // Check path structure for category\n const componentIdx = parts.findIndex((p) => p === \"components\");\n if (componentIdx !== -1 && parts.length > componentIdx + 1) {\n const categoryPart = parts[componentIdx + 1];\n return categoryPart.charAt(0).toUpperCase() + categoryPart.slice(1);\n }\n\n return \"Components\";\n}\n\n/**\n * Infer status from file path\n */\nfunction inferStatus(\n relativePath: string\n): \"stable\" | \"beta\" | \"experimental\" | \"deprecated\" {\n const lowerPath = relativePath.toLowerCase();\n\n if (lowerPath.includes(\"/experimental/\") || lowerPath.includes(\"/labs/\")) {\n return \"experimental\";\n }\n if (lowerPath.includes(\"/beta/\")) {\n return \"beta\";\n }\n if (lowerPath.includes(\"/deprecated/\") || lowerPath.includes(\"/legacy/\")) {\n return \"deprecated\";\n }\n\n return \"stable\";\n}\n\n/**\n * Generate component description\n */\nfunction generateDescription(\n name: string,\n props: Record<string, PropDefinition> | undefined,\n usageAnalysis: UsageAnalysis[\"components\"][string] | undefined\n): string {\n // Convert name to readable form\n const words = name\n .replace(/([A-Z])/g, \" $1\")\n .trim()\n .toLowerCase();\n\n // Check props for hints\n const hasOnClick = props && (\"onClick\" in props || \"onPress\" in props);\n const hasValue = props && (\"value\" in props || \"defaultValue\" in props);\n const hasChildren = props && \"children\" in props;\n const hasHref = props && \"href\" in props;\n\n // Check usage contexts\n const topContext = usageAnalysis?.contexts[0]?.type;\n\n if (hasHref) {\n return `Navigational ${words} for linking to other pages or resources`;\n }\n\n if (hasOnClick && !hasValue) {\n return `Interactive ${words} for triggering actions`;\n }\n\n if (hasValue) {\n return `Form ${words} for user input`;\n }\n\n if (topContext && topContext !== \"unknown\") {\n return `${words.charAt(0).toUpperCase() + words.slice(1)} commonly used in ${topContext} contexts`;\n }\n\n if (hasChildren) {\n return `Container ${words} for composing UI`;\n }\n\n return `${words.charAt(0).toUpperCase() + words.slice(1)} component`;\n}\n\n/**\n * Calculate confidence score based on available data\n */\nfunction calculateConfidence(\n props: Record<string, PropDefinition> | undefined,\n usageAnalysis: UsageAnalysis[\"components\"][string] | undefined,\n storyFile: ParsedStoryFile | undefined\n): number {\n let confidence = 0;\n\n // Props give +30 confidence\n if (props && Object.keys(props).length > 0) {\n confidence += 30;\n }\n\n // Usage data gives up to +40 confidence\n if (usageAnalysis) {\n if (usageAnalysis.totalUsages > 10) confidence += 40;\n else if (usageAnalysis.totalUsages > 5) confidence += 30;\n else if (usageAnalysis.totalUsages > 0) confidence += 20;\n }\n\n // Stories give +30 confidence\n if (storyFile && storyFile.stories.length > 0) {\n confidence += 30;\n }\n\n return Math.min(confidence, 100);\n}\n"],"mappings":"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","names":[]}
|