@fragments-sdk/cli 0.7.0 → 0.7.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 +77 -14
- package/dist/bin.js +247 -247
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-CVXKXVOY.js → chunk-3T6QL7IY.js} +47 -29
- package/dist/chunk-3T6QL7IY.js.map +1 -0
- package/dist/{chunk-7OPWMLOE.js → chunk-7KUSBMI4.js} +114 -112
- package/dist/chunk-7KUSBMI4.js.map +1 -0
- package/dist/{chunk-XHUDJNN3.js → chunk-DH4ETVSM.js} +18 -18
- package/dist/chunk-DH4ETVSM.js.map +1 -0
- package/dist/{chunk-RVRTRESS.js → chunk-DQHWLAUV.js} +29 -29
- package/dist/chunk-DQHWLAUV.js.map +1 -0
- package/dist/{chunk-6JBGU74P.js → chunk-GHYYFAQN.js} +23 -23
- package/dist/chunk-GHYYFAQN.js.map +1 -0
- package/dist/{chunk-NWQ4CJOQ.js → chunk-GKX2HPZ6.js} +40 -40
- package/dist/chunk-GKX2HPZ6.js.map +1 -0
- package/dist/{chunk-TJ34N7C7.js → chunk-OOGTG5FM.js} +34 -33
- package/dist/chunk-OOGTG5FM.js.map +1 -0
- package/dist/{core-W2HYIQW6.js → core-UQXZTBFZ.js} +24 -26
- package/dist/{generate-LMTISDIJ.js → generate-GP6ZLAQB.js} +5 -5
- package/dist/generate-GP6ZLAQB.js.map +1 -0
- package/dist/index.d.ts +23 -27
- package/dist/index.js +10 -10
- package/dist/{init-7CHRKQ7P.js → init-W72WBSU2.js} +5 -5
- package/dist/{init-7CHRKQ7P.js.map → init-W72WBSU2.js.map} +1 -1
- package/dist/mcp-bin.js +73 -73
- package/dist/mcp-bin.js.map +1 -1
- package/dist/scan-V54HWRDY.js +12 -0
- package/dist/{service-T2L7VLTE.js → service-PVGTYUKX.js} +6 -6
- package/dist/{static-viewer-GBR7YNF3.js → static-viewer-KILKIVN7.js} +4 -4
- package/dist/{test-OJRXNDO2.js → test-3YRYQRGV.js} +19 -19
- package/dist/test-3YRYQRGV.js.map +1 -0
- package/dist/{tokens-3BWDESVM.js → tokens-IXSQHPQK.js} +5 -5
- package/dist/{viewer-SUFOISZM.js → viewer-K42REJU2.js} +199 -199
- package/dist/viewer-K42REJU2.js.map +1 -0
- package/package.json +13 -2
- package/src/ai.ts +5 -5
- package/src/analyze.ts +11 -11
- package/src/bin.ts +1 -1
- package/src/build.ts +37 -35
- package/src/commands/a11y.ts +6 -6
- package/src/commands/add.ts +11 -11
- package/src/commands/audit.ts +4 -4
- package/src/commands/baseline.ts +3 -3
- package/src/commands/build.ts +8 -8
- package/src/commands/compare.ts +20 -20
- package/src/commands/context.ts +16 -16
- package/src/commands/enhance.ts +36 -36
- package/src/commands/generate.ts +1 -1
- package/src/commands/graph.ts +5 -5
- package/src/commands/init.ts +1 -1
- package/src/commands/link/figma.ts +82 -82
- package/src/commands/link/index.ts +3 -3
- package/src/commands/link/storybook.ts +9 -9
- package/src/commands/list.ts +2 -2
- package/src/commands/reset.ts +15 -15
- package/src/commands/scan.ts +27 -27
- package/src/commands/storygen.ts +24 -24
- package/src/commands/validate.ts +2 -2
- package/src/commands/verify.ts +8 -8
- package/src/core/auto-props.ts +4 -4
- package/src/core/composition.test.ts +36 -36
- package/src/core/composition.ts +19 -19
- package/src/core/config.ts +6 -6
- package/src/core/{defineSegment.ts → defineFragment.ts} +16 -22
- package/src/core/discovery.ts +6 -6
- package/src/core/figma.ts +2 -2
- package/src/core/graph-extractor.test.ts +77 -77
- package/src/core/graph-extractor.ts +32 -32
- package/src/core/importAnalyzer.ts +1 -1
- package/src/core/index.ts +22 -23
- package/src/core/loader.ts +21 -24
- package/src/core/node.ts +5 -5
- package/src/core/parser.ts +71 -31
- package/src/core/previewLoader.ts +1 -1
- package/src/core/schema.ts +16 -16
- package/src/core/storyAdapter.test.ts +87 -87
- package/src/core/storyAdapter.ts +16 -16
- package/src/core/token-parser.ts +9 -1
- package/src/core/types.ts +21 -26
- package/src/diff.ts +22 -22
- package/src/index.ts +2 -2
- package/src/mcp/server.ts +80 -80
- package/src/migrate/__tests__/utils/utils.test.ts +3 -3
- package/src/migrate/bin.ts +4 -4
- package/src/migrate/converter.ts +16 -16
- package/src/migrate/index.ts +3 -3
- package/src/migrate/migrate.ts +3 -3
- package/src/migrate/parser.ts +8 -8
- package/src/migrate/report.ts +2 -2
- package/src/migrate/types.ts +4 -4
- package/src/screenshot.ts +22 -22
- package/src/service/__tests__/props-extractor.test.ts +15 -15
- package/src/service/analytics.ts +39 -39
- package/src/service/enhance/codebase-scanner.ts +1 -1
- package/src/service/enhance/index.ts +1 -1
- package/src/service/enhance/props-extractor.ts +2 -2
- package/src/service/enhance/types.ts +2 -2
- package/src/service/index.ts +2 -2
- package/src/service/metrics-store.ts +1 -1
- package/src/service/patch-generator.ts +1 -1
- package/src/setup.ts +52 -52
- package/src/shared/dev-server-client.ts +7 -7
- package/src/shared/fragment-loader.ts +59 -0
- package/src/shared/index.ts +1 -1
- package/src/shared/types.ts +4 -4
- package/src/static-viewer.ts +35 -35
- package/src/test/discovery.ts +6 -6
- package/src/test/index.ts +5 -5
- package/src/test/reporters/console.ts +1 -1
- package/src/test/reporters/junit.ts +1 -1
- package/src/test/runner.ts +7 -7
- package/src/test/types.ts +3 -3
- package/src/test/watch.ts +9 -9
- package/src/validators.ts +26 -26
- package/src/viewer/__tests__/render-utils.test.ts +28 -28
- package/src/viewer/__tests__/viewer-integration.test.ts +4 -4
- package/src/viewer/cli/health.ts +26 -26
- package/src/viewer/components/App.tsx +79 -79
- package/src/viewer/components/BottomPanel.tsx +17 -17
- package/src/viewer/components/CodePanel.tsx +3 -3
- package/src/viewer/components/CommandPalette.tsx +11 -11
- package/src/viewer/components/ComponentGraph.tsx +28 -28
- package/src/viewer/components/ComponentHeader.tsx +2 -2
- package/src/viewer/components/ContractPanel.tsx +6 -6
- package/src/viewer/components/FigmaEmbed.tsx +9 -9
- package/src/viewer/components/HealthDashboard.tsx +17 -17
- package/src/viewer/components/InteractionsPanel.tsx +2 -2
- package/src/viewer/components/IsolatedPreviewFrame.tsx +6 -6
- package/src/viewer/components/IsolatedRender.tsx +10 -10
- package/src/viewer/components/LeftSidebar.tsx +28 -28
- package/src/viewer/components/MultiViewportPreview.tsx +14 -14
- package/src/viewer/components/PreviewArea.tsx +11 -11
- package/src/viewer/components/PreviewFrameHost.tsx +51 -51
- package/src/viewer/components/RightSidebar.tsx +9 -9
- package/src/viewer/components/Sidebar.tsx +17 -17
- package/src/viewer/components/StoryRenderer.tsx +2 -2
- package/src/viewer/components/TokenStylePanel.tsx +1 -1
- package/src/viewer/components/UsageSection.tsx +2 -2
- package/src/viewer/components/VariantMatrix.tsx +11 -11
- package/src/viewer/components/VariantRenderer.tsx +3 -3
- package/src/viewer/components/VariantTabs.tsx +2 -2
- package/src/viewer/components/_future/CreatePage.tsx +6 -6
- package/src/viewer/composition-renderer.ts +11 -11
- package/src/viewer/entry.tsx +40 -40
- package/src/viewer/hooks/useFigmaIntegration.ts +1 -1
- package/src/viewer/hooks/usePreviewBridge.ts +5 -5
- package/src/viewer/hooks/useUrlState.ts +6 -6
- package/src/viewer/index.ts +2 -2
- package/src/viewer/intelligence/healthReport.ts +17 -17
- package/src/viewer/intelligence/styleDrift.ts +1 -1
- package/src/viewer/intelligence/usageScanner.ts +1 -1
- package/src/viewer/render-template.html +1 -1
- package/src/viewer/render-utils.ts +21 -21
- package/src/viewer/server.ts +18 -18
- package/src/viewer/utils/detectRelationships.ts +22 -22
- package/src/viewer/vite-plugin.ts +213 -213
- package/dist/chunk-6JBGU74P.js.map +0 -1
- package/dist/chunk-7OPWMLOE.js.map +0 -1
- package/dist/chunk-CVXKXVOY.js.map +0 -1
- package/dist/chunk-NWQ4CJOQ.js.map +0 -1
- package/dist/chunk-RVRTRESS.js.map +0 -1
- package/dist/chunk-TJ34N7C7.js.map +0 -1
- package/dist/chunk-XHUDJNN3.js.map +0 -1
- package/dist/generate-LMTISDIJ.js.map +0 -1
- package/dist/scan-WY23TJCP.js +0 -12
- package/dist/test-OJRXNDO2.js.map +0 -1
- package/dist/viewer-SUFOISZM.js.map +0 -1
- package/src/shared/segment-loader.ts +0 -59
- /package/dist/{core-W2HYIQW6.js.map → core-UQXZTBFZ.js.map} +0 -0
- /package/dist/{scan-WY23TJCP.js.map → scan-V54HWRDY.js.map} +0 -0
- /package/dist/{service-T2L7VLTE.js.map → service-PVGTYUKX.js.map} +0 -0
- /package/dist/{static-viewer-GBR7YNF3.js.map → static-viewer-KILKIVN7.js.map} +0 -0
- /package/dist/{tokens-3BWDESVM.js.map → tokens-IXSQHPQK.js.map} +0 -0
package/src/commands/scan.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* fragments scan - Zero-config
|
|
2
|
+
* fragments scan - Zero-config fragments.json generation from source code
|
|
3
3
|
*
|
|
4
4
|
* Automatically extracts component documentation by:
|
|
5
5
|
* 1. Discovering components from source files and barrel exports
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 3. Scanning codebase for usage patterns
|
|
8
8
|
* 4. Parsing Storybook stories for examples
|
|
9
9
|
* 5. Inferring component relationships from usage data
|
|
10
|
-
* 6. Generating complete
|
|
10
|
+
* 6. Generating complete fragments.json without manual documentation
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { writeFile, mkdir } from "node:fs/promises";
|
|
@@ -15,8 +15,8 @@ import { resolve, join, dirname, relative } from "node:path";
|
|
|
15
15
|
import pc from "picocolors";
|
|
16
16
|
import {
|
|
17
17
|
BRAND,
|
|
18
|
-
type
|
|
19
|
-
type
|
|
18
|
+
type CompiledFragmentsFile,
|
|
19
|
+
type CompiledFragment,
|
|
20
20
|
type PropDefinition,
|
|
21
21
|
} from "../core/index.js";
|
|
22
22
|
import {
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
generateComponentContext,
|
|
33
33
|
generateEnhancementSuggestions,
|
|
34
34
|
filterBoilerplate,
|
|
35
|
-
|
|
35
|
+
convertToFragmentProps,
|
|
36
36
|
type UsageAnalysis,
|
|
37
37
|
type ComponentRelation,
|
|
38
38
|
type PropsExtractionResult,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
export interface ScanOptions {
|
|
43
43
|
/** Path to config file */
|
|
44
44
|
config?: string;
|
|
45
|
-
/** Output file path (default:
|
|
45
|
+
/** Output file path (default: fragments.json) */
|
|
46
46
|
output?: string;
|
|
47
47
|
/** Component patterns to scan */
|
|
48
48
|
componentPatterns?: string[];
|
|
@@ -71,7 +71,7 @@ export interface ScanResult {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
* Scan codebase and generate
|
|
74
|
+
* Scan codebase and generate fragments.json directly from source
|
|
75
75
|
*/
|
|
76
76
|
export async function scan(options: ScanOptions = {}): Promise<ScanResult> {
|
|
77
77
|
const startTime = Date.now();
|
|
@@ -86,17 +86,17 @@ export async function scan(options: ScanOptions = {}): Promise<ScanResult> {
|
|
|
86
86
|
try {
|
|
87
87
|
const loaded = await loadConfig(options.config);
|
|
88
88
|
configDir = loaded.configDir;
|
|
89
|
-
outputFile = options.output || loaded.config.outFile || "
|
|
89
|
+
outputFile = options.output || loaded.config.outFile || "fragments.json";
|
|
90
90
|
componentPatterns = options.componentPatterns || loaded.config.components;
|
|
91
91
|
} catch {
|
|
92
92
|
// No config file, use defaults
|
|
93
93
|
configDir = process.cwd();
|
|
94
|
-
outputFile = options.output || "
|
|
94
|
+
outputFile = options.output || "fragments.json";
|
|
95
95
|
componentPatterns = options.componentPatterns;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
console.log(pc.cyan(`\n${BRAND.name} Scan\n`));
|
|
99
|
-
console.log(pc.dim("Zero-config
|
|
99
|
+
console.log(pc.dim("Zero-config fragments.json generation from source code\n"));
|
|
100
100
|
|
|
101
101
|
// Phase 1: Discover components
|
|
102
102
|
console.log(pc.dim("Phase 1: Discovering components..."));
|
|
@@ -133,7 +133,7 @@ export async function scan(options: ScanOptions = {}): Promise<ScanResult> {
|
|
|
133
133
|
|
|
134
134
|
// Phase 2: Extract props from TypeScript
|
|
135
135
|
console.log(pc.dim("\nPhase 2: Extracting props from TypeScript..."));
|
|
136
|
-
const propsMap = new Map<string, ReturnType<typeof
|
|
136
|
+
const propsMap = new Map<string, ReturnType<typeof convertToFragmentProps>>();
|
|
137
137
|
const propsResults = new Map<string, PropsExtractionResult>();
|
|
138
138
|
let propsExtracted = 0;
|
|
139
139
|
|
|
@@ -146,7 +146,7 @@ export async function scan(options: ScanOptions = {}): Promise<ScanResult> {
|
|
|
146
146
|
propsResults.set(comp.name, extraction);
|
|
147
147
|
|
|
148
148
|
if (extraction.success && extraction.props.length > 0) {
|
|
149
|
-
propsMap.set(comp.name,
|
|
149
|
+
propsMap.set(comp.name, convertToFragmentProps(extraction.props));
|
|
150
150
|
propsExtracted++;
|
|
151
151
|
}
|
|
152
152
|
} catch (e) {
|
|
@@ -238,13 +238,13 @@ export async function scan(options: ScanOptions = {}): Promise<ScanResult> {
|
|
|
238
238
|
console.log(pc.dim("\nPhase 4: Skipping Storybook parsing"));
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
// Phase 5: Generate
|
|
242
|
-
console.log(pc.dim("\nPhase 5: Generating
|
|
243
|
-
const
|
|
241
|
+
// Phase 5: Generate fragments
|
|
242
|
+
console.log(pc.dim("\nPhase 5: Generating fragments..."));
|
|
243
|
+
const fragments: Record<string, CompiledFragment> = {};
|
|
244
244
|
|
|
245
245
|
for (const comp of components) {
|
|
246
246
|
try {
|
|
247
|
-
const
|
|
247
|
+
const fragment = generateFragmentFromData(
|
|
248
248
|
comp,
|
|
249
249
|
configDir,
|
|
250
250
|
propsMap.get(comp.name),
|
|
@@ -253,7 +253,7 @@ export async function scan(options: ScanOptions = {}): Promise<ScanResult> {
|
|
|
253
253
|
storiesMap.get(comp.name)
|
|
254
254
|
);
|
|
255
255
|
|
|
256
|
-
|
|
256
|
+
fragments[comp.name] = fragment;
|
|
257
257
|
} catch (e) {
|
|
258
258
|
errors.push({
|
|
259
259
|
component: comp.name,
|
|
@@ -266,10 +266,10 @@ export async function scan(options: ScanOptions = {}): Promise<ScanResult> {
|
|
|
266
266
|
const outputPath = resolve(configDir, outputFile);
|
|
267
267
|
await mkdir(dirname(outputPath), { recursive: true });
|
|
268
268
|
|
|
269
|
-
const output:
|
|
269
|
+
const output: CompiledFragmentsFile = {
|
|
270
270
|
version: "1.0.0",
|
|
271
271
|
generatedAt: new Date().toISOString(),
|
|
272
|
-
|
|
272
|
+
fragments,
|
|
273
273
|
};
|
|
274
274
|
|
|
275
275
|
await writeFile(outputPath, JSON.stringify(output, null, 2));
|
|
@@ -278,9 +278,9 @@ export async function scan(options: ScanOptions = {}): Promise<ScanResult> {
|
|
|
278
278
|
|
|
279
279
|
// Summary
|
|
280
280
|
console.log(pc.dim("\n────────────────────────────────────────"));
|
|
281
|
-
console.log(pc.green(`\n✓ Generated
|
|
281
|
+
console.log(pc.green(`\n✓ Generated fragments.json in ${elapsed}s`));
|
|
282
282
|
console.log(pc.dim(` Output: ${relative(process.cwd(), outputPath)}`));
|
|
283
|
-
console.log(pc.dim(` Components: ${Object.keys(
|
|
283
|
+
console.log(pc.dim(` Components: ${Object.keys(fragments).length}`));
|
|
284
284
|
console.log(pc.dim(` Props extracted: ${propsExtracted}`));
|
|
285
285
|
console.log(pc.dim(` Usages found: ${usagesFound}`));
|
|
286
286
|
console.log(pc.dim(` Relations inferred: ${allRelations.size}`));
|
|
@@ -307,7 +307,7 @@ export async function scan(options: ScanOptions = {}): Promise<ScanResult> {
|
|
|
307
307
|
return {
|
|
308
308
|
success: errors.length === 0,
|
|
309
309
|
outputPath,
|
|
310
|
-
componentCount: Object.keys(
|
|
310
|
+
componentCount: Object.keys(fragments).length,
|
|
311
311
|
propsExtracted,
|
|
312
312
|
usagesFound,
|
|
313
313
|
relationsInferred: allRelations.size,
|
|
@@ -318,16 +318,16 @@ export async function scan(options: ScanOptions = {}): Promise<ScanResult> {
|
|
|
318
318
|
}
|
|
319
319
|
|
|
320
320
|
/**
|
|
321
|
-
* Generate a
|
|
321
|
+
* Generate a CompiledFragment from extracted data
|
|
322
322
|
*/
|
|
323
|
-
function
|
|
323
|
+
function generateFragmentFromData(
|
|
324
324
|
comp: DiscoveredComponent,
|
|
325
325
|
configDir: string,
|
|
326
326
|
props: Record<string, PropDefinition> | undefined,
|
|
327
327
|
usageAnalysis: UsageAnalysis["components"][string] | undefined,
|
|
328
328
|
relations: ComponentRelation[] | undefined,
|
|
329
329
|
storyFile: ParsedStoryFile | undefined
|
|
330
|
-
):
|
|
330
|
+
): CompiledFragment {
|
|
331
331
|
// Generate context for AI suggestions
|
|
332
332
|
const context = generateComponentContext(
|
|
333
333
|
comp.name,
|
|
@@ -352,7 +352,7 @@ function generateSegmentFromData(
|
|
|
352
352
|
const status = inferStatus(comp.relativePath);
|
|
353
353
|
|
|
354
354
|
// Build variants from stories
|
|
355
|
-
const variants:
|
|
355
|
+
const variants: CompiledFragment["variants"] = [];
|
|
356
356
|
if (storyFile?.stories) {
|
|
357
357
|
for (const story of storyFile.stories) {
|
|
358
358
|
variants.push({
|
|
@@ -364,7 +364,7 @@ function generateSegmentFromData(
|
|
|
364
364
|
}
|
|
365
365
|
|
|
366
366
|
// Build relations
|
|
367
|
-
const compiledRelations:
|
|
367
|
+
const compiledRelations: CompiledFragment["relations"] = [];
|
|
368
368
|
if (relations && relations.length > 0) {
|
|
369
369
|
for (const rel of relations.slice(0, 10)) {
|
|
370
370
|
compiledRelations.push({
|
package/src/commands/storygen.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* fragments storygen - Generate Storybook stories from
|
|
2
|
+
* fragments storygen - Generate Storybook stories from fragment definitions
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { writeFile, mkdir } from 'node:fs/promises';
|
|
6
6
|
import { resolve, join, relative } from 'node:path';
|
|
7
7
|
import pc from 'picocolors';
|
|
8
8
|
import { BRAND } from '../core/index.js';
|
|
9
|
-
import type {
|
|
10
|
-
import { loadConfig,
|
|
9
|
+
import type { FragmentDefinition } from '../core/index.js';
|
|
10
|
+
import { loadConfig, discoverFragmentFiles, loadFragmentFile } from '../core/node.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Options for storygen command
|
|
@@ -17,7 +17,7 @@ export interface StorygenOptions {
|
|
|
17
17
|
config?: string;
|
|
18
18
|
/** Output directory */
|
|
19
19
|
output?: string;
|
|
20
|
-
/** Watch for
|
|
20
|
+
/** Watch for fragment changes and regenerate */
|
|
21
21
|
watch?: boolean;
|
|
22
22
|
/** Story format (csf3) */
|
|
23
23
|
format?: string;
|
|
@@ -42,11 +42,11 @@ export async function storygen(options: StorygenOptions = {}): Promise<StorygenR
|
|
|
42
42
|
|
|
43
43
|
console.log(pc.cyan(`\n${BRAND.name} Story Generator\n`));
|
|
44
44
|
|
|
45
|
-
// Discover
|
|
46
|
-
const
|
|
45
|
+
// Discover fragment files
|
|
46
|
+
const fragmentFiles = await discoverFragmentFiles(config, configDir);
|
|
47
47
|
|
|
48
|
-
if (
|
|
49
|
-
console.log(pc.yellow('No
|
|
48
|
+
if (fragmentFiles.length === 0) {
|
|
49
|
+
console.log(pc.yellow('No fragment files found.\n'));
|
|
50
50
|
return { success: true, generated: 0, outputDir: output };
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -55,14 +55,14 @@ export async function storygen(options: StorygenOptions = {}): Promise<StorygenR
|
|
|
55
55
|
|
|
56
56
|
let generated = 0;
|
|
57
57
|
|
|
58
|
-
// Generate function for a single
|
|
58
|
+
// Generate function for a single fragment
|
|
59
59
|
const generateStory = async (file: { absolutePath: string; relativePath: string }) => {
|
|
60
60
|
try {
|
|
61
|
-
const
|
|
62
|
-
if (!
|
|
61
|
+
const fragment = await loadFragmentFile(file.absolutePath);
|
|
62
|
+
if (!fragment) return false;
|
|
63
63
|
|
|
64
|
-
const storyContent = generateCSF3Story(
|
|
65
|
-
const storyName = `${
|
|
64
|
+
const storyContent = generateCSF3Story(fragment, file.relativePath);
|
|
65
|
+
const storyName = `${fragment.meta.name}.stories.tsx`;
|
|
66
66
|
const storyPath = join(outputDir, storyName);
|
|
67
67
|
|
|
68
68
|
await writeFile(storyPath, storyContent);
|
|
@@ -77,7 +77,7 @@ export async function storygen(options: StorygenOptions = {}): Promise<StorygenR
|
|
|
77
77
|
// Initial generation
|
|
78
78
|
console.log(pc.dim(`Generating stories to ${relative(process.cwd(), outputDir)}/\n`));
|
|
79
79
|
|
|
80
|
-
for (const file of
|
|
80
|
+
for (const file of fragmentFiles) {
|
|
81
81
|
if (await generateStory(file)) {
|
|
82
82
|
generated++;
|
|
83
83
|
}
|
|
@@ -88,10 +88,10 @@ export async function storygen(options: StorygenOptions = {}): Promise<StorygenR
|
|
|
88
88
|
|
|
89
89
|
// Watch mode
|
|
90
90
|
if (watch) {
|
|
91
|
-
console.log(pc.dim('Watching for
|
|
91
|
+
console.log(pc.dim('Watching for fragment changes... (Ctrl+C to stop)\n'));
|
|
92
92
|
|
|
93
93
|
const chokidar = await import('chokidar');
|
|
94
|
-
const patterns =
|
|
94
|
+
const patterns = fragmentFiles.map(f => f.absolutePath);
|
|
95
95
|
|
|
96
96
|
const watcher = chokidar.watch(patterns, {
|
|
97
97
|
ignoreInitial: true,
|
|
@@ -99,7 +99,7 @@ export async function storygen(options: StorygenOptions = {}): Promise<StorygenR
|
|
|
99
99
|
});
|
|
100
100
|
|
|
101
101
|
watcher.on('change', async (changedPath: string) => {
|
|
102
|
-
const file =
|
|
102
|
+
const file = fragmentFiles.find(f => f.absolutePath === changedPath);
|
|
103
103
|
if (file) {
|
|
104
104
|
console.log(pc.dim(`\nChanged: ${relative(process.cwd(), changedPath)}`));
|
|
105
105
|
await generateStory(file);
|
|
@@ -109,10 +109,10 @@ export async function storygen(options: StorygenOptions = {}): Promise<StorygenR
|
|
|
109
109
|
watcher.on('add', async (addedPath: string) => {
|
|
110
110
|
console.log(pc.dim(`\nAdded: ${relative(process.cwd(), addedPath)}`));
|
|
111
111
|
// Re-discover to get the new file's relative path
|
|
112
|
-
const newFiles = await
|
|
112
|
+
const newFiles = await discoverFragmentFiles(config, configDir);
|
|
113
113
|
const file = newFiles.find(f => f.absolutePath === addedPath);
|
|
114
114
|
if (file) {
|
|
115
|
-
|
|
115
|
+
fragmentFiles.push(file);
|
|
116
116
|
await generateStory(file);
|
|
117
117
|
}
|
|
118
118
|
});
|
|
@@ -125,10 +125,10 @@ export async function storygen(options: StorygenOptions = {}): Promise<StorygenR
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/**
|
|
128
|
-
* Generate a CSF3 story file from a
|
|
128
|
+
* Generate a CSF3 story file from a fragment definition
|
|
129
129
|
*/
|
|
130
|
-
function generateCSF3Story(
|
|
131
|
-
const { meta, variants, props, usage } =
|
|
130
|
+
function generateCSF3Story(fragment: FragmentDefinition, relativePath: string): string {
|
|
131
|
+
const { meta, variants, props, usage } = fragment;
|
|
132
132
|
const componentName = meta.name;
|
|
133
133
|
|
|
134
134
|
// Build argTypes from props
|
|
@@ -178,11 +178,11 @@ ${usage.whenNot?.map(w => `- ${w}`).join('\n') || ''}`
|
|
|
178
178
|
return `/**
|
|
179
179
|
* Auto-generated Storybook stories from ${relativePath}
|
|
180
180
|
*
|
|
181
|
-
* DO NOT EDIT - regenerate with:
|
|
181
|
+
* DO NOT EDIT - regenerate with: fragments storygen
|
|
182
182
|
*/
|
|
183
183
|
|
|
184
184
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
185
|
-
import { ${componentName} } from '${relativePath.replace(/\.
|
|
185
|
+
import { ${componentName} } from '${relativePath.replace(/\.fragment\.tsx$/, '/index.js')}';
|
|
186
186
|
|
|
187
187
|
const meta: Meta<typeof ${componentName}> = {
|
|
188
188
|
title: '${meta.category ? `${meta.category.charAt(0).toUpperCase() + meta.category.slice(1)}/` : ''}${componentName}',
|
package/src/commands/validate.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* fragments validate - Validate
|
|
2
|
+
* fragments validate - Validate fragment files
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import pc from 'picocolors';
|
|
@@ -13,7 +13,7 @@ import { validateSchema, validateCoverage, validateAll } from '../validators.js'
|
|
|
13
13
|
export interface ValidateOptions {
|
|
14
14
|
/** Path to config file */
|
|
15
15
|
config?: string;
|
|
16
|
-
/** Validate
|
|
16
|
+
/** Validate fragment schema only */
|
|
17
17
|
schema?: boolean;
|
|
18
18
|
/** Validate coverage only */
|
|
19
19
|
coverage?: boolean;
|
package/src/commands/verify.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* fragments verify - Verify component compliance for CI pipelines
|
|
3
3
|
*
|
|
4
|
-
* Uses the /
|
|
4
|
+
* Uses the /fragments/compliance endpoint to get real token compliance data
|
|
5
5
|
* based on computed styles compared against the design token registry.
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
DevServerConnectionError,
|
|
14
14
|
type ComplianceResult,
|
|
15
15
|
type ViolationItem,
|
|
16
|
-
type
|
|
16
|
+
type FragmentInfo,
|
|
17
17
|
} from '../shared/index.js';
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -95,16 +95,16 @@ export async function verify(
|
|
|
95
95
|
);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
// Fetch all
|
|
99
|
-
let
|
|
98
|
+
// Fetch all fragments
|
|
99
|
+
let fragments = await client.getFragments();
|
|
100
100
|
|
|
101
101
|
// Filter by component if specified
|
|
102
102
|
if (component) {
|
|
103
|
-
|
|
103
|
+
fragments = fragments.filter(
|
|
104
104
|
s => s.name.toLowerCase() === component.toLowerCase()
|
|
105
105
|
);
|
|
106
106
|
|
|
107
|
-
if (
|
|
107
|
+
if (fragments.length === 0) {
|
|
108
108
|
const error = { error: `Component "${component}" not found` };
|
|
109
109
|
if (ci) {
|
|
110
110
|
console.log(JSON.stringify(error));
|
|
@@ -115,8 +115,8 @@ export async function verify(
|
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
// Check compliance for each
|
|
119
|
-
for (const seg of
|
|
118
|
+
// Check compliance for each fragment
|
|
119
|
+
for (const seg of fragments) {
|
|
120
120
|
try {
|
|
121
121
|
// Get real compliance from the server
|
|
122
122
|
const complianceResult = await client.getCompliance({
|
package/src/core/auto-props.ts
CHANGED
|
@@ -64,18 +64,18 @@ function resolveModulePath(basePath: string): string | null {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* Resolve a component source file from the
|
|
67
|
+
* Resolve a component source file from the fragment file path + component import path.
|
|
68
68
|
* Supports relative imports like ".", "./Button", "../components/Button".
|
|
69
69
|
*/
|
|
70
70
|
export function resolveComponentSourcePath(
|
|
71
|
-
|
|
71
|
+
fragmentFileAbsolutePath: string,
|
|
72
72
|
componentImportPath: string | null
|
|
73
73
|
): string | null {
|
|
74
74
|
if (!componentImportPath) return null;
|
|
75
75
|
if (!componentImportPath.startsWith(".")) return null;
|
|
76
76
|
|
|
77
|
-
const
|
|
78
|
-
const basePath = resolve(
|
|
77
|
+
const fragmentDir = dirname(fragmentFileAbsolutePath);
|
|
78
|
+
const basePath = resolve(fragmentDir, componentImportPath);
|
|
79
79
|
return resolveModulePath(basePath);
|
|
80
80
|
}
|
|
81
81
|
|