@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,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the Storybook migration tool.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parsed Storybook story metadata
|
|
7
|
+
*/
|
|
8
|
+
export interface ParsedMeta {
|
|
9
|
+
/** Full title path (e.g., "Components/Forms/Input") */
|
|
10
|
+
title: string;
|
|
11
|
+
/** Component name (inferred from title or component ref) */
|
|
12
|
+
componentName: string;
|
|
13
|
+
/** Component import path */
|
|
14
|
+
componentImport?: string;
|
|
15
|
+
/** Tags from the story */
|
|
16
|
+
tags?: string[];
|
|
17
|
+
/** Description from parameters.docs */
|
|
18
|
+
description?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Parsed argType definition
|
|
23
|
+
*/
|
|
24
|
+
export interface ParsedArgType {
|
|
25
|
+
/** Storybook control type */
|
|
26
|
+
control?: string;
|
|
27
|
+
/** Options for select/radio controls */
|
|
28
|
+
options?: string[];
|
|
29
|
+
/** Prop description */
|
|
30
|
+
description?: string;
|
|
31
|
+
/** Default value */
|
|
32
|
+
defaultValue?: unknown;
|
|
33
|
+
/** TypeScript type (if available) */
|
|
34
|
+
type?: string;
|
|
35
|
+
/** Whether the prop is required */
|
|
36
|
+
required?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Parsed individual story
|
|
41
|
+
*/
|
|
42
|
+
export interface ParsedStory {
|
|
43
|
+
/** Story name (export name) */
|
|
44
|
+
name: string;
|
|
45
|
+
/** Args passed to the component */
|
|
46
|
+
args: Record<string, unknown>;
|
|
47
|
+
/** Story description */
|
|
48
|
+
description?: string;
|
|
49
|
+
/** Whether story has a custom render function */
|
|
50
|
+
hasCustomRender?: boolean;
|
|
51
|
+
/** Raw render code if extractable */
|
|
52
|
+
renderCode?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Complete parsed story file
|
|
57
|
+
*/
|
|
58
|
+
export interface ParsedStoryFile {
|
|
59
|
+
/** Original file path */
|
|
60
|
+
filePath: string;
|
|
61
|
+
/** Parsed metadata */
|
|
62
|
+
meta: ParsedMeta;
|
|
63
|
+
/** Parsed argTypes */
|
|
64
|
+
argTypes: Record<string, ParsedArgType>;
|
|
65
|
+
/** Parsed stories */
|
|
66
|
+
stories: ParsedStory[];
|
|
67
|
+
/** Parse warnings */
|
|
68
|
+
warnings: string[];
|
|
69
|
+
/** Confidence score (0-1) - how reliable the extraction was */
|
|
70
|
+
confidence: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Detected Storybook configuration
|
|
75
|
+
*/
|
|
76
|
+
export interface StorybookConfig {
|
|
77
|
+
/** Path to .storybook/main.* */
|
|
78
|
+
configPath: string;
|
|
79
|
+
/** Story glob patterns from config */
|
|
80
|
+
storyPatterns: string[];
|
|
81
|
+
/** Detected framework (react, vue, etc.) */
|
|
82
|
+
framework?: string;
|
|
83
|
+
/** Detected builder (vite, webpack) */
|
|
84
|
+
builder?: string;
|
|
85
|
+
/** Whether config was successfully parsed */
|
|
86
|
+
valid: boolean;
|
|
87
|
+
/** Parse errors if any */
|
|
88
|
+
errors?: string[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Conversion result for a single story file
|
|
93
|
+
*/
|
|
94
|
+
export interface ConversionResult {
|
|
95
|
+
/** Original story file path */
|
|
96
|
+
sourceFile: string;
|
|
97
|
+
/** Output segment file path */
|
|
98
|
+
outputFile: string;
|
|
99
|
+
/** Generated segment code */
|
|
100
|
+
code: string;
|
|
101
|
+
/** Component name */
|
|
102
|
+
componentName: string;
|
|
103
|
+
/** Category extracted from title */
|
|
104
|
+
category: string;
|
|
105
|
+
/** Number of variants generated */
|
|
106
|
+
variantCount: number;
|
|
107
|
+
/** Number of props extracted */
|
|
108
|
+
propCount: number;
|
|
109
|
+
/** Confidence score (0-1) - how reliable the extraction was */
|
|
110
|
+
confidence: number;
|
|
111
|
+
/** TODOs that need human attention */
|
|
112
|
+
todos: string[];
|
|
113
|
+
/** Warnings during conversion */
|
|
114
|
+
warnings: string[];
|
|
115
|
+
/** Whether conversion was successful */
|
|
116
|
+
success: boolean;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Migration report summary
|
|
121
|
+
*/
|
|
122
|
+
export interface MigrationReport {
|
|
123
|
+
/** When the migration was run */
|
|
124
|
+
timestamp: Date;
|
|
125
|
+
/** Source directory */
|
|
126
|
+
sourceDir: string;
|
|
127
|
+
/** Output directory */
|
|
128
|
+
outputDir: string;
|
|
129
|
+
/** Total story files found */
|
|
130
|
+
totalStoryFiles: number;
|
|
131
|
+
/** Successfully converted files */
|
|
132
|
+
successfulConversions: number;
|
|
133
|
+
/** Failed conversions */
|
|
134
|
+
failedConversions: number;
|
|
135
|
+
/** Total variants generated */
|
|
136
|
+
totalVariants: number;
|
|
137
|
+
/** Total TODOs that need attention */
|
|
138
|
+
totalTodos: number;
|
|
139
|
+
/** Individual conversion results */
|
|
140
|
+
results: ConversionResult[];
|
|
141
|
+
/** Categories discovered */
|
|
142
|
+
categories: string[];
|
|
143
|
+
/** Analytics from the converted segments */
|
|
144
|
+
analytics?: {
|
|
145
|
+
overallScore: number;
|
|
146
|
+
coveragePercentage: number;
|
|
147
|
+
recommendations: string[];
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Migration options
|
|
153
|
+
*/
|
|
154
|
+
export interface MigrateOptions {
|
|
155
|
+
/** Source directory or file pattern */
|
|
156
|
+
from: string;
|
|
157
|
+
/** Output directory (default: same as source) */
|
|
158
|
+
to?: string;
|
|
159
|
+
/** Dry run - don't write files */
|
|
160
|
+
dryRun?: boolean;
|
|
161
|
+
/** Overwrite existing segment files */
|
|
162
|
+
overwrite?: boolean;
|
|
163
|
+
/** Generate HTML report */
|
|
164
|
+
report?: boolean;
|
|
165
|
+
/** Report output path */
|
|
166
|
+
reportPath?: string;
|
|
167
|
+
/** Verbose output */
|
|
168
|
+
verbose?: boolean;
|
|
169
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
import {
|
|
3
|
+
BRAND,
|
|
4
|
+
DEFAULTS,
|
|
5
|
+
type SegmentsConfig,
|
|
6
|
+
type SegmentDefinition,
|
|
7
|
+
type Theme,
|
|
8
|
+
} from './core/index.js';
|
|
9
|
+
import { discoverSegmentFiles, loadSegmentFile } from './core/node.js';
|
|
10
|
+
import {
|
|
11
|
+
BrowserPool,
|
|
12
|
+
CaptureEngine,
|
|
13
|
+
StorageManager,
|
|
14
|
+
formatMs,
|
|
15
|
+
type CaptureOptions,
|
|
16
|
+
} from './service/index.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Options for the screenshot command
|
|
20
|
+
*/
|
|
21
|
+
export interface ScreenshotCommandOptions {
|
|
22
|
+
/** Specific component to capture */
|
|
23
|
+
component?: string;
|
|
24
|
+
|
|
25
|
+
/** Specific variant to capture */
|
|
26
|
+
variant?: string;
|
|
27
|
+
|
|
28
|
+
/** Theme to capture */
|
|
29
|
+
theme?: Theme;
|
|
30
|
+
|
|
31
|
+
/** Update existing baselines */
|
|
32
|
+
update?: boolean;
|
|
33
|
+
|
|
34
|
+
/** CI mode - no interactive prompts */
|
|
35
|
+
ci?: boolean;
|
|
36
|
+
|
|
37
|
+
/** Viewport width */
|
|
38
|
+
width?: number;
|
|
39
|
+
|
|
40
|
+
/** Viewport height */
|
|
41
|
+
height?: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Result of the screenshot command
|
|
46
|
+
*/
|
|
47
|
+
export interface ScreenshotResult {
|
|
48
|
+
success: boolean;
|
|
49
|
+
captured: number;
|
|
50
|
+
skipped: number;
|
|
51
|
+
errors: Array<{ component: string; variant: string; error: string }>;
|
|
52
|
+
totalTimeMs: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Execute the screenshot command
|
|
57
|
+
*/
|
|
58
|
+
export async function runScreenshotCommand(
|
|
59
|
+
config: SegmentsConfig,
|
|
60
|
+
configDir: string,
|
|
61
|
+
options: ScreenshotCommandOptions = {}
|
|
62
|
+
): Promise<ScreenshotResult> {
|
|
63
|
+
const startTime = Date.now();
|
|
64
|
+
const errors: ScreenshotResult['errors'] = [];
|
|
65
|
+
|
|
66
|
+
// Initialize storage
|
|
67
|
+
const storage = new StorageManager({
|
|
68
|
+
projectRoot: configDir,
|
|
69
|
+
viewport: options.width && options.height
|
|
70
|
+
? { width: options.width, height: options.height }
|
|
71
|
+
: config.screenshots?.viewport,
|
|
72
|
+
});
|
|
73
|
+
await storage.initialize();
|
|
74
|
+
|
|
75
|
+
// Discover segments
|
|
76
|
+
const segmentFiles = await discoverSegmentFiles(config, configDir);
|
|
77
|
+
|
|
78
|
+
if (segmentFiles.length === 0) {
|
|
79
|
+
console.log(pc.yellow('No segment files found.'));
|
|
80
|
+
return {
|
|
81
|
+
success: true,
|
|
82
|
+
captured: 0,
|
|
83
|
+
skipped: 0,
|
|
84
|
+
errors: [],
|
|
85
|
+
totalTimeMs: Date.now() - startTime,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Load all segments
|
|
90
|
+
const segments: Array<{ path: string; segment: SegmentDefinition }> = [];
|
|
91
|
+
|
|
92
|
+
for (const file of segmentFiles) {
|
|
93
|
+
try {
|
|
94
|
+
const segment = await loadSegmentFile(file.absolutePath);
|
|
95
|
+
if (segment) {
|
|
96
|
+
segments.push({ path: file.relativePath, segment });
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
errors.push({
|
|
100
|
+
component: file.relativePath,
|
|
101
|
+
variant: '',
|
|
102
|
+
error: error instanceof Error ? error.message : String(error),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Filter by component if specified
|
|
108
|
+
const filteredSegments = options.component
|
|
109
|
+
? segments.filter((s) => s.segment.meta.name === options.component)
|
|
110
|
+
: segments;
|
|
111
|
+
|
|
112
|
+
if (options.component && filteredSegments.length === 0) {
|
|
113
|
+
console.log(pc.yellow(`Component "${options.component}" not found.`));
|
|
114
|
+
return {
|
|
115
|
+
success: false,
|
|
116
|
+
captured: 0,
|
|
117
|
+
skipped: 0,
|
|
118
|
+
errors: [],
|
|
119
|
+
totalTimeMs: Date.now() - startTime,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Build list of variants to capture
|
|
124
|
+
const variantsToCapture: Array<{
|
|
125
|
+
component: string;
|
|
126
|
+
variant: string;
|
|
127
|
+
render: () => unknown;
|
|
128
|
+
}> = [];
|
|
129
|
+
|
|
130
|
+
for (const { segment } of filteredSegments) {
|
|
131
|
+
const variants = options.variant
|
|
132
|
+
? segment.variants.filter((v) => v.name === options.variant)
|
|
133
|
+
: segment.variants;
|
|
134
|
+
|
|
135
|
+
for (const variant of variants) {
|
|
136
|
+
variantsToCapture.push({
|
|
137
|
+
component: segment.meta.name,
|
|
138
|
+
variant: variant.name,
|
|
139
|
+
render: variant.render,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (variantsToCapture.length === 0) {
|
|
145
|
+
console.log(pc.yellow('No variants to capture.'));
|
|
146
|
+
return {
|
|
147
|
+
success: true,
|
|
148
|
+
captured: 0,
|
|
149
|
+
skipped: 0,
|
|
150
|
+
errors: [],
|
|
151
|
+
totalTimeMs: Date.now() - startTime,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Determine theme
|
|
156
|
+
const theme: Theme = options.theme ?? DEFAULTS.theme;
|
|
157
|
+
const viewport = {
|
|
158
|
+
width: options.width ?? config.screenshots?.viewport?.width ?? DEFAULTS.viewport.width,
|
|
159
|
+
height: options.height ?? config.screenshots?.viewport?.height ?? DEFAULTS.viewport.height,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
console.log(pc.cyan(`\n${BRAND.name} Screenshot\n`));
|
|
163
|
+
console.log(pc.dim(`Capturing variants (theme: ${theme}, viewport: ${viewport.width}x${viewport.height}):\n`));
|
|
164
|
+
|
|
165
|
+
// Initialize browser pool
|
|
166
|
+
const pool = new BrowserPool({
|
|
167
|
+
viewport,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Create capture engine - use the viewer URL
|
|
171
|
+
const viewerPort = DEFAULTS.port;
|
|
172
|
+
const baseUrl = `http://localhost:${viewerPort}`;
|
|
173
|
+
const captureEngine = new CaptureEngine(pool, baseUrl);
|
|
174
|
+
|
|
175
|
+
let captured = 0;
|
|
176
|
+
let skipped = 0;
|
|
177
|
+
|
|
178
|
+
const captureOptions: CaptureOptions = {
|
|
179
|
+
theme,
|
|
180
|
+
viewport,
|
|
181
|
+
delay: config.screenshots?.delay ?? DEFAULTS.captureDelayMs,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
// Warm up the pool
|
|
186
|
+
console.log(pc.dim('Starting browser...'));
|
|
187
|
+
await pool.warmup();
|
|
188
|
+
console.log(pc.dim('Browser ready.\n'));
|
|
189
|
+
|
|
190
|
+
// Capture each variant
|
|
191
|
+
for (const { component, variant } of variantsToCapture) {
|
|
192
|
+
const hasExisting = storage.hasBaseline(component, variant, theme);
|
|
193
|
+
|
|
194
|
+
// Skip if exists and not updating
|
|
195
|
+
if (hasExisting && !options.update) {
|
|
196
|
+
console.log(` ${pc.dim('○')} ${component}/${variant} ${pc.dim('(skipped)')}`);
|
|
197
|
+
skipped++;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
const screenshot = await captureEngine.captureVariant(
|
|
203
|
+
component,
|
|
204
|
+
variant,
|
|
205
|
+
captureOptions
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
await storage.saveBaseline(screenshot);
|
|
209
|
+
|
|
210
|
+
const totalTime = screenshot.metadata.renderTimeMs + screenshot.metadata.captureTimeMs;
|
|
211
|
+
console.log(
|
|
212
|
+
` ${pc.green('✓')} ${component}/${variant} ${pc.dim(formatMs(totalTime))}`
|
|
213
|
+
);
|
|
214
|
+
captured++;
|
|
215
|
+
} catch (error) {
|
|
216
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
217
|
+
console.log(` ${pc.red('✗')} ${component}/${variant} ${pc.dim(errorMsg)}`);
|
|
218
|
+
errors.push({ component, variant, error: errorMsg });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} finally {
|
|
222
|
+
// Shutdown browser pool
|
|
223
|
+
await pool.shutdown();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const totalTimeMs = Date.now() - startTime;
|
|
227
|
+
|
|
228
|
+
// Print summary
|
|
229
|
+
console.log();
|
|
230
|
+
if (errors.length === 0) {
|
|
231
|
+
console.log(pc.green(`✓ Captured ${captured} screenshot(s) in ${formatMs(totalTimeMs)}`));
|
|
232
|
+
} else {
|
|
233
|
+
console.log(pc.yellow(`⚠ Captured ${captured} screenshot(s) with ${errors.length} error(s)`));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (skipped > 0) {
|
|
237
|
+
console.log(pc.dim(` ${skipped} skipped (use --update to recapture)`));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
console.log(pc.dim(` Stored in ${storage.screenshotsDirPath}\n`));
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
success: errors.length === 0,
|
|
244
|
+
captured,
|
|
245
|
+
skipped,
|
|
246
|
+
errors,
|
|
247
|
+
totalTimeMs,
|
|
248
|
+
};
|
|
249
|
+
}
|