@fragments-sdk/cli 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +529 -285
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-F7ITZPDJ.js → chunk-32VIEOQY.js} +18 -18
- package/dist/chunk-32VIEOQY.js.map +1 -0
- package/dist/{chunk-SSLQXHNX.js → chunk-5ITIP3ES.js} +27 -27
- package/dist/chunk-5ITIP3ES.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-Q7GOHVOK.js → chunk-GCZMFLDI.js} +67 -32
- package/dist/chunk-GCZMFLDI.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-D35RGPAG.js → chunk-U6VTHBNI.js} +499 -83
- package/dist/chunk-U6VTHBNI.js.map +1 -0
- package/dist/{core-SKRPJQZG.js → core-SFHPYR5H.js} +24 -26
- package/dist/{generate-7AF7WRVK.js → generate-54GJAWUY.js} +5 -5
- package/dist/generate-54GJAWUY.js.map +1 -0
- package/dist/index.d.ts +23 -27
- package/dist/index.js +10 -10
- package/dist/{init-WKGDPYI4.js → init-EIM5WNMP.js} +5 -5
- package/dist/{init-WKGDPYI4.js.map → init-EIM5WNMP.js.map} +1 -1
- package/dist/mcp-bin.js +73 -73
- package/dist/mcp-bin.js.map +1 -1
- package/dist/scan-KQBKUS64.js +12 -0
- package/dist/{service-F3E4JJM7.js → service-ED2LNCTU.js} +6 -6
- package/dist/{static-viewer-4LQZ5AGA.js → static-viewer-Q4F4QP5M.js} +4 -4
- package/dist/{test-CJDNJTPZ.js → test-6VN2DA3S.js} +19 -19
- package/dist/test-6VN2DA3S.js.map +1 -0
- package/dist/{tokens-JAJABYXP.js → tokens-P2B7ZAM3.js} +5 -5
- package/dist/{viewer-R3Q6WAMJ.js → viewer-GM7IQPPB.js} +199 -199
- package/dist/viewer-GM7IQPPB.js.map +1 -0
- package/package.json +2 -2
- package/src/ai.ts +5 -5
- package/src/analyze.ts +11 -11
- package/src/bin.ts +24 -1
- package/src/build.ts +64 -21
- 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 +274 -0
- 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 +83 -20
- 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 +542 -0
- package/src/core/graph-extractor.ts +601 -0
- package/src/core/importAnalyzer.ts +6 -1
- package/src/core/index.ts +22 -23
- package/src/core/loader.ts +22 -22
- package/src/core/node.ts +5 -5
- package/src/core/parser.ts +31 -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/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 +201 -103
- 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/Icons.tsx +53 -1
- 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/Layout.tsx +7 -3
- package/src/viewer/components/LeftSidebar.tsx +92 -114
- package/src/viewer/components/MultiViewportPreview.tsx +14 -14
- package/src/viewer/components/PreviewArea.tsx +11 -11
- package/src/viewer/components/PreviewFrameHost.tsx +77 -48
- package/src/viewer/components/PreviewToolbar.tsx +57 -10
- 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/ViewportSelector.tsx +56 -45
- package/src/viewer/components/_future/CreatePage.tsx +6 -6
- package/src/viewer/composition-renderer.ts +11 -11
- package/src/viewer/constants/ui.ts +4 -4
- 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/preview-frame.html +22 -13
- 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/styles/globals.css +42 -81
- 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-D35RGPAG.js.map +0 -1
- package/dist/chunk-F7ITZPDJ.js.map +0 -1
- package/dist/chunk-NWQ4CJOQ.js.map +0 -1
- package/dist/chunk-Q7GOHVOK.js.map +0 -1
- package/dist/chunk-RVRTRESS.js.map +0 -1
- package/dist/chunk-SSLQXHNX.js.map +0 -1
- package/dist/generate-7AF7WRVK.js.map +0 -1
- package/dist/scan-K6JNMCGM.js +0 -12
- package/dist/test-CJDNJTPZ.js.map +0 -1
- package/dist/viewer-R3Q6WAMJ.js.map +0 -1
- package/src/shared/segment-loader.ts +0 -59
- /package/dist/{core-SKRPJQZG.js.map → core-SFHPYR5H.js.map} +0 -0
- /package/dist/{scan-K6JNMCGM.js.map → scan-KQBKUS64.js.map} +0 -0
- /package/dist/{service-F3E4JJM7.js.map → service-ED2LNCTU.js.map} +0 -0
- /package/dist/{static-viewer-4LQZ5AGA.js.map → static-viewer-Q4F4QP5M.js.map} +0 -0
- /package/dist/{tokens-JAJABYXP.js.map → tokens-P2B7ZAM3.js.map} +0 -0
package/src/core/index.ts
CHANGED
|
@@ -9,9 +9,9 @@ export type { Brand, Defaults } from "./constants.js";
|
|
|
9
9
|
|
|
10
10
|
// Types
|
|
11
11
|
export type {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
FragmentComponent,
|
|
13
|
+
FragmentMeta,
|
|
14
|
+
FragmentUsage,
|
|
15
15
|
PropType,
|
|
16
16
|
PropDefinition,
|
|
17
17
|
ControlType,
|
|
@@ -20,20 +20,19 @@ export type {
|
|
|
20
20
|
VariantLoader,
|
|
21
21
|
PlayFunction,
|
|
22
22
|
PlayFunctionContext,
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
FragmentVariant,
|
|
24
|
+
FragmentDefinition,
|
|
25
25
|
FragmentsConfig,
|
|
26
|
-
SegmentsConfig, // @deprecated - use FragmentsConfig
|
|
27
26
|
RegistryOptions,
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
CompiledFragment,
|
|
28
|
+
CompiledFragmentsFile,
|
|
30
29
|
BlockDefinition,
|
|
31
30
|
CompiledBlock,
|
|
32
31
|
RecipeDefinition, // @deprecated - use BlockDefinition
|
|
33
32
|
CompiledRecipe, // @deprecated - use CompiledBlock
|
|
34
33
|
// Contract and provenance types
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
FragmentContract,
|
|
35
|
+
FragmentGenerated,
|
|
37
36
|
// AI metadata type
|
|
38
37
|
AIMetadata,
|
|
39
38
|
// Screenshot types
|
|
@@ -81,18 +80,18 @@ export type {
|
|
|
81
80
|
|
|
82
81
|
// Schema validation (Zod is browser-safe)
|
|
83
82
|
export {
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
fragmentMetaSchema,
|
|
84
|
+
fragmentUsageSchema,
|
|
86
85
|
propDefinitionSchema,
|
|
87
86
|
componentRelationSchema,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
fragmentVariantSchema,
|
|
88
|
+
fragmentDefinitionSchema,
|
|
89
|
+
fragmentsConfigSchema,
|
|
91
90
|
figmaPropMappingSchema,
|
|
92
91
|
// Contract and provenance schemas
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
fragmentContractSchema,
|
|
93
|
+
fragmentGeneratedSchema,
|
|
94
|
+
fragmentBanSchema,
|
|
96
95
|
blockDefinitionSchema,
|
|
97
96
|
recipeDefinitionSchema, // @deprecated - use blockDefinitionSchema
|
|
98
97
|
// AI metadata schema
|
|
@@ -100,12 +99,12 @@ export {
|
|
|
100
99
|
} from "./schema.js";
|
|
101
100
|
|
|
102
101
|
// Main API
|
|
103
|
-
export {
|
|
104
|
-
export type { InferProps } from "./
|
|
102
|
+
export { defineFragment, compileFragment, defineBlock, compileBlock, defineRecipe, compileRecipe } from "./defineFragment.js";
|
|
103
|
+
export type { InferProps } from "./defineFragment.js";
|
|
105
104
|
|
|
106
105
|
// Story adapter (runtime conversion of Storybook modules)
|
|
107
106
|
export {
|
|
108
|
-
|
|
107
|
+
storyModuleToFragment,
|
|
109
108
|
setPreviewConfig,
|
|
110
109
|
getPreviewConfig,
|
|
111
110
|
// Re-export @storybook/csf utilities
|
|
@@ -136,12 +135,12 @@ export { figma, isFigmaPropMapping, resolveFigmaMapping } from "./figma.js";
|
|
|
136
135
|
export type {
|
|
137
136
|
Fragment,
|
|
138
137
|
FragmentFigma,
|
|
139
|
-
FragmentUsage,
|
|
138
|
+
FragmentUsage as FragmentJsonUsage,
|
|
140
139
|
FragmentDoNotItem,
|
|
141
140
|
FragmentPattern,
|
|
142
141
|
FragmentAccessibility,
|
|
143
142
|
FragmentRelated,
|
|
144
|
-
FragmentMeta,
|
|
143
|
+
FragmentMeta as FragmentJsonMeta,
|
|
145
144
|
FragmentIndex,
|
|
146
145
|
FragmentRegistry,
|
|
147
146
|
RegistryComponentEntry,
|
package/src/core/loader.ts
CHANGED
|
@@ -2,13 +2,13 @@ import { writeFile, unlink } from 'node:fs/promises';
|
|
|
2
2
|
import { dirname, basename, join } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import { build, type Plugin } from 'esbuild';
|
|
5
|
-
import type {
|
|
5
|
+
import type { FragmentDefinition } from './types.js';
|
|
6
6
|
import { BRAND } from './constants.js';
|
|
7
7
|
|
|
8
|
-
// Inline implementation of
|
|
9
|
-
// This allows
|
|
10
|
-
const
|
|
11
|
-
export function
|
|
8
|
+
// Inline implementation of defineFragment that will be injected into bundled files
|
|
9
|
+
// This allows fragment files to work without @fragments/core being installed
|
|
10
|
+
const DEFINE_FRAGMENT_SHIM = `
|
|
11
|
+
export function defineFragment(def) {
|
|
12
12
|
return def;
|
|
13
13
|
}
|
|
14
14
|
export function defineFragment(def) {
|
|
@@ -24,9 +24,9 @@ export function defineRecipe(def) {
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Creates an esbuild plugin that replaces @fragments/core imports with an inline shim.
|
|
27
|
-
* This allows
|
|
27
|
+
* This allows fragment files to be loaded without @fragments/core being installed in the target project.
|
|
28
28
|
*/
|
|
29
|
-
function
|
|
29
|
+
function createFragmentsCoreShimPlugin(): Plugin {
|
|
30
30
|
return {
|
|
31
31
|
name: BRAND.vitePluginNamespace,
|
|
32
32
|
setup(build) {
|
|
@@ -41,7 +41,7 @@ function createSegmentsCoreShimPlugin(): Plugin {
|
|
|
41
41
|
// Return the shim content
|
|
42
42
|
build.onLoad({ filter: /.*/, namespace: BRAND.vitePluginNamespace }, () => {
|
|
43
43
|
return {
|
|
44
|
-
contents:
|
|
44
|
+
contents: DEFINE_FRAGMENT_SHIM,
|
|
45
45
|
loader: 'js',
|
|
46
46
|
};
|
|
47
47
|
});
|
|
@@ -50,12 +50,12 @@ function createSegmentsCoreShimPlugin(): Plugin {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
* Load a
|
|
53
|
+
* Load a fragment file, handling TSX/TS transformation automatically.
|
|
54
54
|
* Uses esbuild to bundle and transform TypeScript/JSX before importing.
|
|
55
55
|
*/
|
|
56
|
-
export async function
|
|
56
|
+
export async function loadFragmentFile(
|
|
57
57
|
absolutePath: string
|
|
58
|
-
): Promise<
|
|
58
|
+
): Promise<FragmentDefinition | null> {
|
|
59
59
|
const ext = absolutePath.split('.').pop()?.toLowerCase();
|
|
60
60
|
const needsTransform = ext === 'tsx' || ext === 'ts' || ext === 'jsx';
|
|
61
61
|
|
|
@@ -70,10 +70,10 @@ export async function loadSegmentFile(
|
|
|
70
70
|
const sourceDir = dirname(absolutePath);
|
|
71
71
|
const baseName = basename(absolutePath, `.${ext}`);
|
|
72
72
|
// Use .cjs extension to ensure CommonJS evaluation
|
|
73
|
-
const tempFile = join(sourceDir, `.${baseName}.
|
|
73
|
+
const tempFile = join(sourceDir, `.${baseName}.fragments-temp-${Date.now()}.cjs`);
|
|
74
74
|
|
|
75
75
|
try {
|
|
76
|
-
// Use esbuild to bundle the
|
|
76
|
+
// Use esbuild to bundle the fragment file
|
|
77
77
|
// We inject a shim for @fragments/core so it doesn't need to be installed
|
|
78
78
|
// Using CommonJS format to avoid ESM/CJS interop issues with node_modules
|
|
79
79
|
await build({
|
|
@@ -84,8 +84,8 @@ export async function loadSegmentFile(
|
|
|
84
84
|
target: 'es2022',
|
|
85
85
|
jsx: 'automatic',
|
|
86
86
|
platform: 'node',
|
|
87
|
-
plugins: [
|
|
88
|
-
// Externalize all node_modules - we only need
|
|
87
|
+
plugins: [createFragmentsCoreShimPlugin()],
|
|
88
|
+
// Externalize all node_modules - we only need fragment metadata, not component code
|
|
89
89
|
packages: 'external',
|
|
90
90
|
// Also explicitly list patterns for nested imports
|
|
91
91
|
external: [
|
|
@@ -129,19 +129,19 @@ export async function loadSegmentFile(
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
|
-
* Load multiple
|
|
132
|
+
* Load multiple fragment files in parallel with error handling.
|
|
133
133
|
*/
|
|
134
|
-
export async function
|
|
134
|
+
export async function loadFragmentFiles(
|
|
135
135
|
absolutePaths: string[]
|
|
136
|
-
): Promise<Map<string,
|
|
137
|
-
const results = new Map<string,
|
|
136
|
+
): Promise<Map<string, FragmentDefinition | Error>> {
|
|
137
|
+
const results = new Map<string, FragmentDefinition | Error>();
|
|
138
138
|
|
|
139
139
|
await Promise.all(
|
|
140
140
|
absolutePaths.map(async (path) => {
|
|
141
141
|
try {
|
|
142
|
-
const
|
|
143
|
-
if (
|
|
144
|
-
results.set(path,
|
|
142
|
+
const fragment = await loadFragmentFile(path);
|
|
143
|
+
if (fragment) {
|
|
144
|
+
results.set(path, fragment);
|
|
145
145
|
} else {
|
|
146
146
|
results.set(path, new Error('No default export found'));
|
|
147
147
|
}
|
package/src/core/node.ts
CHANGED
|
@@ -8,13 +8,13 @@ export { loadConfig, findConfigFile } from './config.js';
|
|
|
8
8
|
|
|
9
9
|
// Discovery
|
|
10
10
|
export {
|
|
11
|
-
|
|
11
|
+
discoverFragmentFiles,
|
|
12
12
|
discoverBlockFiles,
|
|
13
13
|
discoverRecipeFiles, // @deprecated - use discoverBlockFiles
|
|
14
14
|
discoverComponentFiles,
|
|
15
15
|
discoverInstalledFragments,
|
|
16
16
|
extractComponentName,
|
|
17
|
-
// New: Component discovery from source files (no
|
|
17
|
+
// New: Component discovery from source files (no fragment files needed)
|
|
18
18
|
discoverComponentsFromSource,
|
|
19
19
|
discoverComponentsFromBarrel,
|
|
20
20
|
discoverAllComponents,
|
|
@@ -23,11 +23,11 @@ export {
|
|
|
23
23
|
export type { DiscoveredFile, DiscoveredComponent } from './discovery.js';
|
|
24
24
|
|
|
25
25
|
// Loader (TSX/TS support)
|
|
26
|
-
export {
|
|
26
|
+
export { loadFragmentFile, loadFragmentFiles } from './loader.js';
|
|
27
27
|
|
|
28
28
|
// AST Parser (no execution, static analysis only)
|
|
29
|
-
export {
|
|
30
|
-
export type {
|
|
29
|
+
export { parseFragmentFile } from './parser.js';
|
|
30
|
+
export type { ParsedFragmentMetadata } from './parser.js';
|
|
31
31
|
|
|
32
32
|
// Preview loader (Storybook .storybook/preview.tsx support)
|
|
33
33
|
export {
|
package/src/core/parser.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AST-Based
|
|
2
|
+
* AST-Based Fragment Parser
|
|
3
3
|
*
|
|
4
|
-
* Extracts
|
|
5
|
-
* This allows `
|
|
4
|
+
* Extracts fragment metadata from .fragment.tsx files WITHOUT executing them.
|
|
5
|
+
* This allows `fragments build` to work without any project dependencies.
|
|
6
6
|
*
|
|
7
7
|
* Uses TypeScript's compiler API to parse and analyze the AST.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import ts from "typescript";
|
|
11
|
-
import type {
|
|
11
|
+
import type { FragmentMeta, FragmentUsage, PropDefinition, AIMetadata } from "./types.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Parsed
|
|
14
|
+
* Parsed fragment metadata (extracted statically from AST)
|
|
15
15
|
*/
|
|
16
|
-
export interface
|
|
16
|
+
export interface ParsedFragmentMetadata {
|
|
17
17
|
/** Component import path (e.g., "./Button" or "@/components/Button") */
|
|
18
18
|
componentImport: string | null;
|
|
19
19
|
|
|
@@ -21,10 +21,10 @@ export interface ParsedSegmentMetadata {
|
|
|
21
21
|
componentName: string | null;
|
|
22
22
|
|
|
23
23
|
/** Component metadata */
|
|
24
|
-
meta: Partial<
|
|
24
|
+
meta: Partial<FragmentMeta>;
|
|
25
25
|
|
|
26
26
|
/** Usage guidelines */
|
|
27
|
-
usage: Partial<
|
|
27
|
+
usage: Partial<FragmentUsage>;
|
|
28
28
|
|
|
29
29
|
/** Props documentation */
|
|
30
30
|
props: Record<string, Partial<PropDefinition>>;
|
|
@@ -53,17 +53,17 @@ export interface ParsedSegmentMetadata {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
|
-
* Parse a
|
|
56
|
+
* Parse a fragment file and extract metadata without executing it.
|
|
57
57
|
*/
|
|
58
|
-
export function
|
|
58
|
+
export function parseFragmentFile(
|
|
59
59
|
fileContent: string,
|
|
60
60
|
filePath?: string
|
|
61
|
-
):
|
|
61
|
+
): ParsedFragmentMetadata {
|
|
62
62
|
const warnings: string[] = [];
|
|
63
63
|
|
|
64
64
|
// Parse the file
|
|
65
65
|
const sourceFile = ts.createSourceFile(
|
|
66
|
-
filePath ?? "
|
|
66
|
+
filePath ?? "fragment.tsx",
|
|
67
67
|
fileContent,
|
|
68
68
|
ts.ScriptTarget.Latest,
|
|
69
69
|
true,
|
|
@@ -73,11 +73,11 @@ export function parseSegmentFile(
|
|
|
73
73
|
// Find imports
|
|
74
74
|
const imports = extractImports(sourceFile);
|
|
75
75
|
|
|
76
|
-
// Find the
|
|
77
|
-
const
|
|
76
|
+
// Find the defineFragment call
|
|
77
|
+
const defineFragmentCall = findDefineFragmentCall(sourceFile);
|
|
78
78
|
|
|
79
|
-
if (!
|
|
80
|
-
warnings.push("No
|
|
79
|
+
if (!defineFragmentCall) {
|
|
80
|
+
warnings.push("No defineFragment() call found");
|
|
81
81
|
return {
|
|
82
82
|
componentImport: null,
|
|
83
83
|
componentName: null,
|
|
@@ -91,9 +91,9 @@ export function parseSegmentFile(
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// Extract the argument (object literal)
|
|
94
|
-
const arg =
|
|
94
|
+
const arg = defineFragmentCall.arguments[0];
|
|
95
95
|
if (!arg || !ts.isObjectLiteralExpression(arg)) {
|
|
96
|
-
warnings.push("
|
|
96
|
+
warnings.push("defineFragment() argument is not an object literal");
|
|
97
97
|
return {
|
|
98
98
|
componentImport: null,
|
|
99
99
|
componentName: null,
|
|
@@ -185,9 +185,9 @@ function extractImports(sourceFile: ts.SourceFile): Map<string, string> {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
/**
|
|
188
|
-
* Find the
|
|
188
|
+
* Find the defineFragment() call in the source file.
|
|
189
189
|
*/
|
|
190
|
-
function
|
|
190
|
+
function findDefineFragmentCall(
|
|
191
191
|
sourceFile: ts.SourceFile
|
|
192
192
|
): ts.CallExpression | null {
|
|
193
193
|
let result: ts.CallExpression | null = null;
|
|
@@ -195,7 +195,7 @@ function findDefineSegmentCall(
|
|
|
195
195
|
function visit(node: ts.Node): void {
|
|
196
196
|
if (ts.isCallExpression(node)) {
|
|
197
197
|
const expression = node.expression;
|
|
198
|
-
if (ts.isIdentifier(expression) && expression.text === "
|
|
198
|
+
if (ts.isIdentifier(expression) && expression.text === "defineFragment") {
|
|
199
199
|
result = node;
|
|
200
200
|
return;
|
|
201
201
|
}
|
|
@@ -226,19 +226,19 @@ function findProperty(
|
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
/**
|
|
229
|
-
* Extract meta object from
|
|
229
|
+
* Extract meta object from defineFragment call.
|
|
230
230
|
*/
|
|
231
231
|
function extractMeta(
|
|
232
232
|
arg: ts.ObjectLiteralExpression,
|
|
233
233
|
warnings: string[]
|
|
234
|
-
): Partial<
|
|
234
|
+
): Partial<FragmentMeta> {
|
|
235
235
|
const metaProp = findProperty(arg, "meta");
|
|
236
236
|
if (!metaProp || !ts.isObjectLiteralExpression(metaProp)) {
|
|
237
237
|
warnings.push("No meta object found");
|
|
238
238
|
return {};
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
const meta: Partial<
|
|
241
|
+
const meta: Partial<FragmentMeta> = {};
|
|
242
242
|
|
|
243
243
|
// Extract string properties
|
|
244
244
|
const name = extractStringProperty(metaProp, "name");
|
|
@@ -250,7 +250,7 @@ function extractMeta(
|
|
|
250
250
|
const category = extractStringProperty(metaProp, "category");
|
|
251
251
|
if (category) meta.category = category;
|
|
252
252
|
|
|
253
|
-
const status = extractStringProperty(metaProp, "status") as
|
|
253
|
+
const status = extractStringProperty(metaProp, "status") as FragmentMeta["status"];
|
|
254
254
|
if (status) meta.status = status;
|
|
255
255
|
|
|
256
256
|
const since = extractStringProperty(metaProp, "since");
|
|
@@ -268,12 +268,12 @@ function extractMeta(
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
/**
|
|
271
|
-
* Extract usage object from
|
|
271
|
+
* Extract usage object from defineFragment call.
|
|
272
272
|
*/
|
|
273
273
|
function extractUsage(
|
|
274
274
|
arg: ts.ObjectLiteralExpression,
|
|
275
275
|
warnings: string[]
|
|
276
|
-
): Partial<
|
|
276
|
+
): Partial<FragmentUsage> {
|
|
277
277
|
const usageProp = findProperty(arg, "usage");
|
|
278
278
|
if (!usageProp || !ts.isObjectLiteralExpression(usageProp)) {
|
|
279
279
|
return { when: [], whenNot: [] };
|
|
@@ -288,7 +288,7 @@ function extractUsage(
|
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
/**
|
|
291
|
-
* Extract props object from
|
|
291
|
+
* Extract props object from defineFragment call.
|
|
292
292
|
*/
|
|
293
293
|
function extractProps(
|
|
294
294
|
arg: ts.ObjectLiteralExpression,
|
|
@@ -348,7 +348,7 @@ function extractPropDefinition(
|
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
/**
|
|
351
|
-
* Extract variants array from
|
|
351
|
+
* Extract variants array from defineFragment call.
|
|
352
352
|
*/
|
|
353
353
|
function extractVariants(
|
|
354
354
|
arg: ts.ObjectLiteralExpression,
|
|
@@ -483,7 +483,7 @@ function extractRenderCode(
|
|
|
483
483
|
}
|
|
484
484
|
|
|
485
485
|
/**
|
|
486
|
-
* Extract relations array from
|
|
486
|
+
* Extract relations array from defineFragment call.
|
|
487
487
|
*/
|
|
488
488
|
function extractRelations(
|
|
489
489
|
arg: ts.ObjectLiteralExpression,
|
|
@@ -516,7 +516,7 @@ function extractRelations(
|
|
|
516
516
|
}
|
|
517
517
|
|
|
518
518
|
/**
|
|
519
|
-
* Extract AI metadata from
|
|
519
|
+
* Extract AI metadata from defineFragment call.
|
|
520
520
|
*/
|
|
521
521
|
function extractAIMetadata(
|
|
522
522
|
arg: ts.ObjectLiteralExpression,
|
|
@@ -91,7 +91,7 @@ export async function loadPreviewConfig(
|
|
|
91
91
|
return config;
|
|
92
92
|
} catch (error) {
|
|
93
93
|
console.warn(
|
|
94
|
-
`[
|
|
94
|
+
`[Fragments] Failed to load preview config from ${previewPath}:`,
|
|
95
95
|
error instanceof Error ? error.message : error
|
|
96
96
|
);
|
|
97
97
|
return {};
|
package/src/core/schema.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Zod schemas for runtime validation of
|
|
4
|
+
* Zod schemas for runtime validation of fragment definitions
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
// Figma property mapping schemas
|
|
@@ -46,7 +46,7 @@ export const figmaPropMappingSchema = z.discriminatedUnion('__type', [
|
|
|
46
46
|
figmaTextContentMappingSchema,
|
|
47
47
|
]);
|
|
48
48
|
|
|
49
|
-
export const
|
|
49
|
+
export const fragmentMetaSchema = z.object({
|
|
50
50
|
name: z.string().min(1),
|
|
51
51
|
description: z.string().min(1),
|
|
52
52
|
category: z.string().min(1),
|
|
@@ -57,7 +57,7 @@ export const segmentMetaSchema = z.object({
|
|
|
57
57
|
figmaProps: z.record(figmaPropMappingSchema).optional(),
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
export const
|
|
60
|
+
export const fragmentUsageSchema = z.object({
|
|
61
61
|
when: z.array(z.string()).min(1),
|
|
62
62
|
whenNot: z.array(z.string()).min(1),
|
|
63
63
|
guidelines: z.array(z.string()).optional(),
|
|
@@ -104,7 +104,7 @@ export const componentRelationSchema = z.object({
|
|
|
104
104
|
note: z.string().min(1),
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
export const
|
|
107
|
+
export const fragmentVariantSchema = z.object({
|
|
108
108
|
name: z.string().min(1),
|
|
109
109
|
description: z.string().min(1),
|
|
110
110
|
render: z.function().returns(z.unknown()),
|
|
@@ -115,7 +115,7 @@ export const segmentVariantSchema = z.object({
|
|
|
115
115
|
/**
|
|
116
116
|
* Schema for banned patterns in codebase
|
|
117
117
|
*/
|
|
118
|
-
export const
|
|
118
|
+
export const fragmentBanSchema = z.object({
|
|
119
119
|
pattern: z.string().min(1),
|
|
120
120
|
message: z.string().min(1),
|
|
121
121
|
});
|
|
@@ -123,17 +123,17 @@ export const segmentBanSchema = z.object({
|
|
|
123
123
|
/**
|
|
124
124
|
* Schema for agent-optimized contract metadata
|
|
125
125
|
*/
|
|
126
|
-
export const
|
|
126
|
+
export const fragmentContractSchema = z.object({
|
|
127
127
|
propsSummary: z.array(z.string()).optional(),
|
|
128
128
|
a11yRules: z.array(z.string()).optional(),
|
|
129
|
-
bans: z.array(
|
|
129
|
+
bans: z.array(fragmentBanSchema).optional(),
|
|
130
130
|
scenarioTags: z.array(z.string()).optional(),
|
|
131
131
|
});
|
|
132
132
|
|
|
133
133
|
/**
|
|
134
|
-
* Schema for provenance tracking of generated
|
|
134
|
+
* Schema for provenance tracking of generated fragments
|
|
135
135
|
*/
|
|
136
|
-
export const
|
|
136
|
+
export const fragmentGeneratedSchema = z.object({
|
|
137
137
|
source: z.enum(['storybook', 'manual', 'ai']),
|
|
138
138
|
sourceFile: z.string().optional(),
|
|
139
139
|
confidence: z.number().min(0).max(1).optional(),
|
|
@@ -162,23 +162,23 @@ export const blockDefinitionSchema = z.object({
|
|
|
162
162
|
tags: z.array(z.string()).optional(),
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
-
export const
|
|
165
|
+
export const fragmentDefinitionSchema = z.object({
|
|
166
166
|
component: z.any(), // Allow any component type (function, class, forwardRef, etc.)
|
|
167
|
-
meta:
|
|
168
|
-
usage:
|
|
167
|
+
meta: fragmentMetaSchema,
|
|
168
|
+
usage: fragmentUsageSchema,
|
|
169
169
|
props: z.record(propDefinitionSchema),
|
|
170
170
|
relations: z.array(componentRelationSchema).optional(),
|
|
171
|
-
variants: z.array(
|
|
172
|
-
contract:
|
|
171
|
+
variants: z.array(fragmentVariantSchema), // Allow empty variants array
|
|
172
|
+
contract: fragmentContractSchema.optional(),
|
|
173
173
|
ai: aiMetadataSchema.optional(),
|
|
174
|
-
_generated:
|
|
174
|
+
_generated: fragmentGeneratedSchema.optional(),
|
|
175
175
|
});
|
|
176
176
|
|
|
177
177
|
/**
|
|
178
178
|
* Config schema - validates required fields, passes through optional config objects.
|
|
179
179
|
* Type definitions are in types.ts - schema just ensures basic structure.
|
|
180
180
|
*/
|
|
181
|
-
export const
|
|
181
|
+
export const fragmentsConfigSchema = z.object({
|
|
182
182
|
include: z.array(z.string()).min(1),
|
|
183
183
|
exclude: z.array(z.string()).optional(),
|
|
184
184
|
components: z.array(z.string()).optional(),
|