@fragments-sdk/cli 0.2.2
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/LICENSE +21 -0
- package/README.md +106 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +4783 -0
- package/dist/bin.js.map +1 -0
- package/dist/chunk-4FDQSGKX.js +786 -0
- package/dist/chunk-4FDQSGKX.js.map +1 -0
- package/dist/chunk-7H2MMGYG.js +369 -0
- package/dist/chunk-7H2MMGYG.js.map +1 -0
- package/dist/chunk-BSCG3IP7.js +619 -0
- package/dist/chunk-BSCG3IP7.js.map +1 -0
- package/dist/chunk-LY2CFFPY.js +898 -0
- package/dist/chunk-LY2CFFPY.js.map +1 -0
- package/dist/chunk-MUZ6CM66.js +6636 -0
- package/dist/chunk-MUZ6CM66.js.map +1 -0
- package/dist/chunk-OAENNG3G.js +1489 -0
- package/dist/chunk-OAENNG3G.js.map +1 -0
- package/dist/chunk-XHNKNI6J.js +235 -0
- package/dist/chunk-XHNKNI6J.js.map +1 -0
- package/dist/core-DWKLGY4N.js +68 -0
- package/dist/core-DWKLGY4N.js.map +1 -0
- package/dist/generate-4LQNJ7SX.js +249 -0
- package/dist/generate-4LQNJ7SX.js.map +1 -0
- package/dist/index.d.ts +775 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/init-EMVI47QG.js +416 -0
- package/dist/init-EMVI47QG.js.map +1 -0
- package/dist/mcp-bin.d.ts +1 -0
- package/dist/mcp-bin.js +1117 -0
- package/dist/mcp-bin.js.map +1 -0
- package/dist/scan-4YPRF7FV.js +12 -0
- package/dist/scan-4YPRF7FV.js.map +1 -0
- package/dist/service-QSZMZJBJ.js +208 -0
- package/dist/service-QSZMZJBJ.js.map +1 -0
- package/dist/static-viewer-MIPGZ4Z7.js +12 -0
- package/dist/static-viewer-MIPGZ4Z7.js.map +1 -0
- package/dist/test-SQ5ZHXWU.js +1067 -0
- package/dist/test-SQ5ZHXWU.js.map +1 -0
- package/dist/tokens-HSGMYK64.js +173 -0
- package/dist/tokens-HSGMYK64.js.map +1 -0
- package/dist/viewer-YRF4SQE4.js +11101 -0
- package/dist/viewer-YRF4SQE4.js.map +1 -0
- package/package.json +107 -0
- package/src/ai.ts +266 -0
- package/src/analyze.ts +265 -0
- package/src/bin.ts +916 -0
- package/src/build.ts +248 -0
- package/src/commands/a11y.ts +302 -0
- package/src/commands/add.ts +313 -0
- package/src/commands/audit.ts +195 -0
- package/src/commands/baseline.ts +221 -0
- package/src/commands/build.ts +144 -0
- package/src/commands/compare.ts +337 -0
- package/src/commands/context.ts +107 -0
- package/src/commands/dev.ts +107 -0
- package/src/commands/enhance.ts +858 -0
- package/src/commands/generate.ts +391 -0
- package/src/commands/init.ts +531 -0
- package/src/commands/link/figma.ts +645 -0
- package/src/commands/link/index.ts +10 -0
- package/src/commands/link/storybook.ts +267 -0
- package/src/commands/list.ts +49 -0
- package/src/commands/metrics.ts +114 -0
- package/src/commands/reset.ts +242 -0
- package/src/commands/scan.ts +537 -0
- package/src/commands/storygen.ts +207 -0
- package/src/commands/tokens.ts +251 -0
- package/src/commands/validate.ts +93 -0
- package/src/commands/verify.ts +215 -0
- package/src/core/composition.test.ts +262 -0
- package/src/core/composition.ts +255 -0
- package/src/core/config.ts +84 -0
- package/src/core/constants.ts +111 -0
- package/src/core/context.ts +380 -0
- package/src/core/defineSegment.ts +137 -0
- package/src/core/discovery.ts +337 -0
- package/src/core/figma.ts +263 -0
- package/src/core/fragment-types.ts +214 -0
- package/src/core/generators/context.ts +389 -0
- package/src/core/generators/index.ts +23 -0
- package/src/core/generators/registry.ts +364 -0
- package/src/core/generators/typescript-extractor.ts +374 -0
- package/src/core/importAnalyzer.ts +217 -0
- package/src/core/index.ts +149 -0
- package/src/core/loader.ts +155 -0
- package/src/core/node.ts +63 -0
- package/src/core/parser.ts +551 -0
- package/src/core/previewLoader.ts +172 -0
- package/src/core/schema/fragment.schema.json +189 -0
- package/src/core/schema/registry.schema.json +137 -0
- package/src/core/schema.ts +182 -0
- package/src/core/storyAdapter.test.ts +571 -0
- package/src/core/storyAdapter.ts +761 -0
- package/src/core/token-types.ts +287 -0
- package/src/core/types.ts +754 -0
- package/src/diff.ts +323 -0
- package/src/index.ts +43 -0
- package/src/mcp/__tests__/projectFields.test.ts +130 -0
- package/src/mcp/bin.ts +36 -0
- package/src/mcp/index.ts +8 -0
- package/src/mcp/server.ts +1310 -0
- package/src/mcp/utils.ts +54 -0
- package/src/mcp-bin.ts +36 -0
- package/src/migrate/__tests__/argTypes/argTypes.test.ts +189 -0
- package/src/migrate/__tests__/args/args.test.ts +452 -0
- package/src/migrate/__tests__/meta/meta.test.ts +198 -0
- package/src/migrate/__tests__/stories/stories.test.ts +278 -0
- package/src/migrate/__tests__/utils/utils.test.ts +371 -0
- package/src/migrate/__tests__/values/values.test.ts +303 -0
- package/src/migrate/bin.ts +108 -0
- package/src/migrate/converter.ts +658 -0
- package/src/migrate/detect.ts +196 -0
- package/src/migrate/index.ts +45 -0
- package/src/migrate/migrate.ts +163 -0
- package/src/migrate/parser.ts +1136 -0
- package/src/migrate/report.ts +624 -0
- package/src/migrate/types.ts +169 -0
- package/src/screenshot.ts +249 -0
- package/src/service/__tests__/ast-utils.test.ts +426 -0
- package/src/service/__tests__/enhance-scanner.test.ts +200 -0
- package/src/service/__tests__/figma/figma.test.ts +652 -0
- package/src/service/__tests__/metrics-store.test.ts +409 -0
- package/src/service/__tests__/patch-generator.test.ts +186 -0
- package/src/service/__tests__/props-extractor.test.ts +365 -0
- package/src/service/__tests__/token-registry.test.ts +267 -0
- package/src/service/analytics.ts +659 -0
- package/src/service/ast-utils.ts +444 -0
- package/src/service/browser-pool.ts +339 -0
- package/src/service/capture.ts +267 -0
- package/src/service/diff.ts +279 -0
- package/src/service/enhance/aggregator.ts +489 -0
- package/src/service/enhance/cache.ts +275 -0
- package/src/service/enhance/codebase-scanner.ts +357 -0
- package/src/service/enhance/context-generator.ts +529 -0
- package/src/service/enhance/doc-extractor.ts +523 -0
- package/src/service/enhance/index.ts +131 -0
- package/src/service/enhance/props-extractor.ts +665 -0
- package/src/service/enhance/scanner.ts +445 -0
- package/src/service/enhance/storybook-parser.ts +552 -0
- package/src/service/enhance/types.ts +346 -0
- package/src/service/enhance/variant-renderer.ts +479 -0
- package/src/service/figma.ts +1008 -0
- package/src/service/index.ts +249 -0
- package/src/service/metrics-store.ts +333 -0
- package/src/service/patch-generator.ts +349 -0
- package/src/service/report.ts +854 -0
- package/src/service/storage.ts +401 -0
- package/src/service/token-fixes.ts +281 -0
- package/src/service/token-parser.ts +504 -0
- package/src/service/token-registry.ts +721 -0
- package/src/service/utils.ts +172 -0
- package/src/setup.ts +241 -0
- package/src/shared/command-wrapper.ts +81 -0
- package/src/shared/dev-server-client.ts +199 -0
- package/src/shared/index.ts +8 -0
- package/src/shared/segment-loader.ts +59 -0
- package/src/shared/types.ts +147 -0
- package/src/static-viewer.ts +715 -0
- package/src/test/discovery.ts +172 -0
- package/src/test/index.ts +281 -0
- package/src/test/reporters/console.ts +194 -0
- package/src/test/reporters/json.ts +190 -0
- package/src/test/reporters/junit.ts +186 -0
- package/src/test/runner.ts +598 -0
- package/src/test/types.ts +245 -0
- package/src/test/watch.ts +200 -0
- package/src/validators.ts +152 -0
- package/src/viewer/__tests__/jsx-parser.test.ts +502 -0
- package/src/viewer/__tests__/render-utils.test.ts +232 -0
- package/src/viewer/__tests__/style-utils.test.ts +404 -0
- package/src/viewer/bin.ts +86 -0
- package/src/viewer/cli/health.ts +256 -0
- package/src/viewer/cli/index.ts +33 -0
- package/src/viewer/cli/scan.ts +124 -0
- package/src/viewer/cli/utils.ts +174 -0
- package/src/viewer/components/AccessibilityPanel.tsx +1404 -0
- package/src/viewer/components/ActionCapture.tsx +172 -0
- package/src/viewer/components/ActionsPanel.tsx +371 -0
- package/src/viewer/components/App.tsx +638 -0
- package/src/viewer/components/BottomPanel.tsx +224 -0
- package/src/viewer/components/CodePanel.tsx +589 -0
- package/src/viewer/components/CommandPalette.tsx +336 -0
- package/src/viewer/components/ComponentGraph.tsx +394 -0
- package/src/viewer/components/ComponentHeader.tsx +85 -0
- package/src/viewer/components/ContractPanel.tsx +234 -0
- package/src/viewer/components/ErrorBoundary.tsx +85 -0
- package/src/viewer/components/FigmaEmbed.tsx +231 -0
- package/src/viewer/components/FragmentEditor.tsx +485 -0
- package/src/viewer/components/HealthDashboard.tsx +452 -0
- package/src/viewer/components/HmrStatusIndicator.tsx +71 -0
- package/src/viewer/components/Icons.tsx +417 -0
- package/src/viewer/components/InteractionsPanel.tsx +720 -0
- package/src/viewer/components/IsolatedPreviewFrame.tsx +321 -0
- package/src/viewer/components/IsolatedRender.tsx +111 -0
- package/src/viewer/components/KeyboardShortcutsHelp.tsx +89 -0
- package/src/viewer/components/LandingPage.tsx +441 -0
- package/src/viewer/components/Layout.tsx +22 -0
- package/src/viewer/components/LeftSidebar.tsx +391 -0
- package/src/viewer/components/MultiViewportPreview.tsx +429 -0
- package/src/viewer/components/PreviewArea.tsx +404 -0
- package/src/viewer/components/PreviewFrameHost.tsx +310 -0
- package/src/viewer/components/PreviewPane.tsx +150 -0
- package/src/viewer/components/PreviewToolbar.tsx +176 -0
- package/src/viewer/components/PropsEditor.tsx +512 -0
- package/src/viewer/components/PropsTable.tsx +98 -0
- package/src/viewer/components/RelationsSection.tsx +57 -0
- package/src/viewer/components/ResizablePanel.tsx +328 -0
- package/src/viewer/components/RightSidebar.tsx +118 -0
- package/src/viewer/components/ScreenshotButton.tsx +90 -0
- package/src/viewer/components/Sidebar.tsx +169 -0
- package/src/viewer/components/SkeletonLoader.tsx +156 -0
- package/src/viewer/components/StoryRenderer.tsx +128 -0
- package/src/viewer/components/ThemeProvider.tsx +96 -0
- package/src/viewer/components/Toast.tsx +67 -0
- package/src/viewer/components/TokenStylePanel.tsx +708 -0
- package/src/viewer/components/UsageSection.tsx +95 -0
- package/src/viewer/components/VariantMatrix.tsx +350 -0
- package/src/viewer/components/VariantRenderer.tsx +131 -0
- package/src/viewer/components/VariantTabs.tsx +84 -0
- package/src/viewer/components/ViewportSelector.tsx +165 -0
- package/src/viewer/components/_future/CreatePage.tsx +836 -0
- package/src/viewer/composition-renderer.ts +381 -0
- package/src/viewer/constants/index.ts +1 -0
- package/src/viewer/constants/ui.ts +185 -0
- package/src/viewer/entry.tsx +299 -0
- package/src/viewer/hooks/index.ts +2 -0
- package/src/viewer/hooks/useA11yCache.ts +383 -0
- package/src/viewer/hooks/useA11yService.ts +498 -0
- package/src/viewer/hooks/useActions.ts +138 -0
- package/src/viewer/hooks/useAppState.ts +124 -0
- package/src/viewer/hooks/useFigmaIntegration.ts +132 -0
- package/src/viewer/hooks/useHmrStatus.ts +109 -0
- package/src/viewer/hooks/useKeyboardShortcuts.ts +222 -0
- package/src/viewer/hooks/usePreviewBridge.ts +347 -0
- package/src/viewer/hooks/useScrollSpy.ts +78 -0
- package/src/viewer/hooks/useUrlState.ts +330 -0
- package/src/viewer/hooks/useViewSettings.ts +125 -0
- package/src/viewer/index.html +28 -0
- package/src/viewer/index.ts +14 -0
- package/src/viewer/intelligence/healthReport.ts +505 -0
- package/src/viewer/intelligence/styleDrift.ts +340 -0
- package/src/viewer/intelligence/usageScanner.ts +309 -0
- package/src/viewer/jsx-parser.ts +485 -0
- package/src/viewer/postcss.config.js +6 -0
- package/src/viewer/preview-frame-entry.tsx +25 -0
- package/src/viewer/preview-frame.html +109 -0
- package/src/viewer/render-template.html +68 -0
- package/src/viewer/render-utils.ts +170 -0
- package/src/viewer/server.ts +276 -0
- package/src/viewer/style-utils.ts +414 -0
- package/src/viewer/styles/globals.css +355 -0
- package/src/viewer/tailwind.config.js +37 -0
- package/src/viewer/types/a11y.ts +197 -0
- package/src/viewer/utils/a11y-fixes.ts +471 -0
- package/src/viewer/utils/actionExport.ts +372 -0
- package/src/viewer/utils/colorSchemes.ts +201 -0
- package/src/viewer/utils/detectRelationships.ts +256 -0
- package/src/viewer/vite-plugin.ts +2143 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storybook Configuration Detection
|
|
3
|
+
*
|
|
4
|
+
* Auto-detects Storybook configuration files and extracts
|
|
5
|
+
* story patterns for migration.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { readFile } from "node:fs/promises";
|
|
10
|
+
import { join, dirname } from "node:path";
|
|
11
|
+
import fg from "fast-glob";
|
|
12
|
+
import type { StorybookConfig } from "./types.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Common Storybook config file names in order of preference
|
|
16
|
+
*/
|
|
17
|
+
const CONFIG_FILES = [
|
|
18
|
+
".storybook/main.ts",
|
|
19
|
+
".storybook/main.mts",
|
|
20
|
+
".storybook/main.js",
|
|
21
|
+
".storybook/main.mjs",
|
|
22
|
+
".storybook/main.cjs",
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Default story patterns if none found in config
|
|
27
|
+
*/
|
|
28
|
+
const DEFAULT_PATTERNS = [
|
|
29
|
+
"**/*.stories.@(ts|tsx|js|jsx|mdx)",
|
|
30
|
+
"**/*.story.@(ts|tsx|js|jsx|mdx)",
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Detect Storybook configuration in a project directory.
|
|
35
|
+
*/
|
|
36
|
+
export async function detectStorybookConfig(
|
|
37
|
+
projectRoot: string
|
|
38
|
+
): Promise<StorybookConfig | null> {
|
|
39
|
+
// Try each config file
|
|
40
|
+
for (const configFile of CONFIG_FILES) {
|
|
41
|
+
const configPath = join(projectRoot, configFile);
|
|
42
|
+
if (existsSync(configPath)) {
|
|
43
|
+
return parseStorybookConfig(configPath);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Parse a Storybook configuration file.
|
|
52
|
+
*/
|
|
53
|
+
async function parseStorybookConfig(
|
|
54
|
+
configPath: string
|
|
55
|
+
): Promise<StorybookConfig> {
|
|
56
|
+
const errors: string[] = [];
|
|
57
|
+
let storyPatterns: string[] = [];
|
|
58
|
+
let framework: string | undefined;
|
|
59
|
+
let builder: string | undefined;
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const content = await readFile(configPath, "utf-8");
|
|
63
|
+
|
|
64
|
+
// Extract stories array/patterns
|
|
65
|
+
// Pattern: stories: ['../src/**/*.stories.@(ts|tsx)']
|
|
66
|
+
const storiesMatch = content.match(
|
|
67
|
+
/stories:\s*\[([^\]]+)\]/s
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
if (storiesMatch) {
|
|
71
|
+
// Parse the array content
|
|
72
|
+
const storiesContent = storiesMatch[1];
|
|
73
|
+
const patterns = storiesContent
|
|
74
|
+
.split(",")
|
|
75
|
+
.map((p) => p.trim())
|
|
76
|
+
.map((p) => {
|
|
77
|
+
// Remove quotes and template literals
|
|
78
|
+
const cleaned = p.replace(/^['"`]|['"`]$/g, "").trim();
|
|
79
|
+
return cleaned;
|
|
80
|
+
})
|
|
81
|
+
.filter((p) => p && !p.startsWith("//") && !p.startsWith("{"));
|
|
82
|
+
|
|
83
|
+
if (patterns.length > 0) {
|
|
84
|
+
storyPatterns = patterns;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Extract framework
|
|
89
|
+
// Pattern: framework: '@storybook/react-vite' or framework: { name: '...' }
|
|
90
|
+
const frameworkMatch = content.match(
|
|
91
|
+
/framework:\s*['"`]([^'"`]+)['"`]/
|
|
92
|
+
);
|
|
93
|
+
if (frameworkMatch) {
|
|
94
|
+
framework = frameworkMatch[1];
|
|
95
|
+
} else {
|
|
96
|
+
const frameworkNameMatch = content.match(
|
|
97
|
+
/framework:\s*\{[^}]*name:\s*['"`]([^'"`]+)['"`]/
|
|
98
|
+
);
|
|
99
|
+
if (frameworkNameMatch) {
|
|
100
|
+
framework = frameworkNameMatch[1];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Extract builder if specified
|
|
105
|
+
// Pattern: builder: 'vite' or core: { builder: 'vite' }
|
|
106
|
+
const builderMatch = content.match(
|
|
107
|
+
/builder:\s*['"`]([^'"`]+)['"`]/
|
|
108
|
+
);
|
|
109
|
+
if (builderMatch) {
|
|
110
|
+
builder = builderMatch[1];
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
errors.push(
|
|
114
|
+
`Failed to parse config: ${error instanceof Error ? error.message : String(error)}`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Use defaults if no patterns found
|
|
119
|
+
if (storyPatterns.length === 0) {
|
|
120
|
+
storyPatterns = DEFAULT_PATTERNS;
|
|
121
|
+
errors.push("No story patterns found in config, using defaults");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
configPath,
|
|
126
|
+
storyPatterns,
|
|
127
|
+
framework,
|
|
128
|
+
builder,
|
|
129
|
+
valid: errors.length === 0 || storyPatterns.length > 0,
|
|
130
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Discover story files using detected or provided patterns.
|
|
136
|
+
*/
|
|
137
|
+
export async function discoverStoryFiles(
|
|
138
|
+
projectRoot: string,
|
|
139
|
+
patterns?: string[]
|
|
140
|
+
): Promise<string[]> {
|
|
141
|
+
// If no patterns provided, try to detect from config
|
|
142
|
+
if (!patterns || patterns.length === 0) {
|
|
143
|
+
const config = await detectStorybookConfig(projectRoot);
|
|
144
|
+
patterns = config?.storyPatterns ?? DEFAULT_PATTERNS;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Resolve patterns relative to project root
|
|
148
|
+
const configDir = join(projectRoot, ".storybook");
|
|
149
|
+
const resolvedPatterns = patterns.map((p) => {
|
|
150
|
+
// If pattern starts with ../, resolve from .storybook dir
|
|
151
|
+
if (p.startsWith("../")) {
|
|
152
|
+
return join(configDir, p);
|
|
153
|
+
}
|
|
154
|
+
// Otherwise resolve from project root
|
|
155
|
+
return join(projectRoot, p);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Find matching files
|
|
159
|
+
const files = await fg(resolvedPatterns, {
|
|
160
|
+
cwd: projectRoot,
|
|
161
|
+
absolute: true,
|
|
162
|
+
ignore: [
|
|
163
|
+
"**/node_modules/**",
|
|
164
|
+
"**/dist/**",
|
|
165
|
+
"**/build/**",
|
|
166
|
+
"**/.storybook/**",
|
|
167
|
+
],
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return files.sort();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get a summary of detected Storybook setup.
|
|
175
|
+
*/
|
|
176
|
+
export async function getStorybookSummary(
|
|
177
|
+
projectRoot: string
|
|
178
|
+
): Promise<{
|
|
179
|
+
detected: boolean;
|
|
180
|
+
config?: StorybookConfig;
|
|
181
|
+
storyCount: number;
|
|
182
|
+
storyFiles: string[];
|
|
183
|
+
}> {
|
|
184
|
+
const config = await detectStorybookConfig(projectRoot);
|
|
185
|
+
const storyFiles = await discoverStoryFiles(
|
|
186
|
+
projectRoot,
|
|
187
|
+
config?.storyPatterns
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
detected: config !== null,
|
|
192
|
+
config: config ?? undefined,
|
|
193
|
+
storyCount: storyFiles.length,
|
|
194
|
+
storyFiles,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fragments/migrate
|
|
3
|
+
*
|
|
4
|
+
* Storybook to Segments migration tool.
|
|
5
|
+
*
|
|
6
|
+
* Provides automated conversion of Storybook CSF files to Segments format,
|
|
7
|
+
* preserving component documentation while adding AI-first capabilities.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Migration engine
|
|
11
|
+
export { migrate } from "./migrate.js";
|
|
12
|
+
|
|
13
|
+
// Parser
|
|
14
|
+
export {
|
|
15
|
+
parseStoryFile,
|
|
16
|
+
parseStoryContent,
|
|
17
|
+
storyNameToTitle,
|
|
18
|
+
extractCategory,
|
|
19
|
+
__testing,
|
|
20
|
+
} from "./parser.js";
|
|
21
|
+
|
|
22
|
+
// Converter
|
|
23
|
+
export { convertToSegment } from "./converter.js";
|
|
24
|
+
|
|
25
|
+
// Report generator
|
|
26
|
+
export { generateMigrationReport } from "./report.js";
|
|
27
|
+
|
|
28
|
+
// Storybook detection
|
|
29
|
+
export {
|
|
30
|
+
detectStorybookConfig,
|
|
31
|
+
discoverStoryFiles,
|
|
32
|
+
getStorybookSummary,
|
|
33
|
+
} from "./detect.js";
|
|
34
|
+
|
|
35
|
+
// Types
|
|
36
|
+
export type {
|
|
37
|
+
ParsedMeta,
|
|
38
|
+
ParsedArgType,
|
|
39
|
+
ParsedStory,
|
|
40
|
+
ParsedStoryFile,
|
|
41
|
+
ConversionResult,
|
|
42
|
+
MigrationReport,
|
|
43
|
+
MigrateOptions,
|
|
44
|
+
StorybookConfig,
|
|
45
|
+
} from "./types.js";
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration Engine
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates the full migration pipeline:
|
|
5
|
+
* 1. Discover Storybook files
|
|
6
|
+
* 2. Parse CSF format
|
|
7
|
+
* 3. Convert to Segments
|
|
8
|
+
* 4. Write output files
|
|
9
|
+
* 5. Generate report
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { readdir, writeFile, mkdir, access, stat } from "node:fs/promises";
|
|
13
|
+
import { join, dirname, relative } from "node:path";
|
|
14
|
+
import fg from "fast-glob";
|
|
15
|
+
import type {
|
|
16
|
+
MigrateOptions,
|
|
17
|
+
MigrationReport,
|
|
18
|
+
ConversionResult,
|
|
19
|
+
} from "./types.js";
|
|
20
|
+
import { parseStoryFile } from "./parser.js";
|
|
21
|
+
import { convertToSegment } from "./converter.js";
|
|
22
|
+
import { generateMigrationReport } from "./report.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Run the migration process.
|
|
26
|
+
*/
|
|
27
|
+
export async function migrate(options: MigrateOptions): Promise<MigrationReport> {
|
|
28
|
+
const startTime = Date.now();
|
|
29
|
+
|
|
30
|
+
// Discover story files
|
|
31
|
+
const storyFiles = await discoverStoryFiles(options.from);
|
|
32
|
+
|
|
33
|
+
const results: ConversionResult[] = [];
|
|
34
|
+
const categories = new Set<string>();
|
|
35
|
+
let totalTodos = 0;
|
|
36
|
+
let totalVariants = 0;
|
|
37
|
+
|
|
38
|
+
// Process each story file
|
|
39
|
+
for (const storyFile of storyFiles) {
|
|
40
|
+
try {
|
|
41
|
+
// Parse
|
|
42
|
+
const parsed = await parseStoryFile(storyFile);
|
|
43
|
+
|
|
44
|
+
// Convert
|
|
45
|
+
const result = convertToSegment(parsed);
|
|
46
|
+
|
|
47
|
+
// Determine output path
|
|
48
|
+
const outputDir = options.to ?? dirname(storyFile);
|
|
49
|
+
const outputFile = join(outputDir, relative(dirname(storyFile), result.outputFile));
|
|
50
|
+
result.outputFile = outputFile;
|
|
51
|
+
|
|
52
|
+
// Check if file exists
|
|
53
|
+
if (!options.overwrite) {
|
|
54
|
+
try {
|
|
55
|
+
await access(outputFile);
|
|
56
|
+
result.warnings.push(`Output file already exists: ${outputFile}`);
|
|
57
|
+
if (!options.dryRun) {
|
|
58
|
+
result.success = false;
|
|
59
|
+
results.push(result);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
// File doesn't exist, proceed
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Write file (unless dry run)
|
|
68
|
+
if (!options.dryRun) {
|
|
69
|
+
await mkdir(dirname(outputFile), { recursive: true });
|
|
70
|
+
await writeFile(outputFile, result.code);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Track stats
|
|
74
|
+
categories.add(result.category);
|
|
75
|
+
totalTodos += result.todos.length;
|
|
76
|
+
totalVariants += result.variantCount;
|
|
77
|
+
|
|
78
|
+
results.push(result);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
results.push({
|
|
81
|
+
sourceFile: storyFile,
|
|
82
|
+
outputFile: "",
|
|
83
|
+
code: "",
|
|
84
|
+
componentName: "",
|
|
85
|
+
category: "",
|
|
86
|
+
variantCount: 0,
|
|
87
|
+
propCount: 0,
|
|
88
|
+
confidence: 0,
|
|
89
|
+
todos: [],
|
|
90
|
+
warnings: [error instanceof Error ? error.message : String(error)],
|
|
91
|
+
success: false,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Calculate stats
|
|
97
|
+
const successfulConversions = results.filter((r) => r.success).length;
|
|
98
|
+
const failedConversions = results.filter((r) => !r.success).length;
|
|
99
|
+
|
|
100
|
+
// Build report
|
|
101
|
+
const report: MigrationReport = {
|
|
102
|
+
timestamp: new Date(),
|
|
103
|
+
sourceDir: options.from,
|
|
104
|
+
outputDir: options.to ?? options.from,
|
|
105
|
+
totalStoryFiles: storyFiles.length,
|
|
106
|
+
successfulConversions,
|
|
107
|
+
failedConversions,
|
|
108
|
+
totalVariants,
|
|
109
|
+
totalTodos,
|
|
110
|
+
results,
|
|
111
|
+
categories: Array.from(categories).sort(),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Generate HTML report if requested
|
|
115
|
+
if (options.report) {
|
|
116
|
+
const reportHtml = generateMigrationReport(report);
|
|
117
|
+
const reportPath = options.reportPath ?? join(options.from, "migration-report.html");
|
|
118
|
+
await mkdir(dirname(reportPath), { recursive: true });
|
|
119
|
+
await writeFile(reportPath, reportHtml);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return report;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Discover Storybook story files in a directory.
|
|
127
|
+
*/
|
|
128
|
+
async function discoverStoryFiles(fromPath: string): Promise<string[]> {
|
|
129
|
+
// Support both file and directory paths
|
|
130
|
+
const stats = await stat(fromPath);
|
|
131
|
+
|
|
132
|
+
if (stats.isFile()) {
|
|
133
|
+
// Single file
|
|
134
|
+
if (isStoryFile(fromPath)) {
|
|
135
|
+
return [fromPath];
|
|
136
|
+
}
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Directory - find all story files
|
|
141
|
+
const patterns = [
|
|
142
|
+
"**/*.stories.tsx",
|
|
143
|
+
"**/*.stories.ts",
|
|
144
|
+
"**/*.stories.jsx",
|
|
145
|
+
"**/*.stories.js",
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
const files = await fg(patterns, {
|
|
149
|
+
cwd: fromPath,
|
|
150
|
+
ignore: ["**/node_modules/**", "**/.storybook/**"],
|
|
151
|
+
absolute: false,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Return absolute paths, sorted
|
|
155
|
+
return files.map((f) => join(fromPath, f)).sort();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Check if a file is a Storybook story file.
|
|
160
|
+
*/
|
|
161
|
+
function isStoryFile(filePath: string): boolean {
|
|
162
|
+
return /\.stories\.(tsx?|jsx?)$/.test(filePath);
|
|
163
|
+
}
|