@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
|
@@ -8,57 +8,57 @@ import {
|
|
|
8
8
|
formatMs,
|
|
9
9
|
generateHtmlReport,
|
|
10
10
|
getGrade
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-GKX2HPZ6.js";
|
|
12
12
|
import {
|
|
13
13
|
discoverBlockFiles,
|
|
14
14
|
discoverComponentFiles,
|
|
15
|
-
|
|
15
|
+
discoverFragmentFiles,
|
|
16
16
|
discoverTokenFiles,
|
|
17
17
|
extractComponentName,
|
|
18
18
|
generateContextMd,
|
|
19
19
|
generateRegistry,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} from "./chunk-
|
|
20
|
+
loadFragmentFile,
|
|
21
|
+
parseFragmentFile
|
|
22
|
+
} from "./chunk-3T6QL7IY.js";
|
|
23
23
|
import {
|
|
24
24
|
compileBlock,
|
|
25
25
|
parseTokenFile
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-OOGTG5FM.js";
|
|
27
27
|
import {
|
|
28
28
|
BRAND,
|
|
29
29
|
DEFAULTS,
|
|
30
|
-
|
|
31
|
-
} from "./chunk-
|
|
30
|
+
fragmentDefinitionSchema
|
|
31
|
+
} from "./chunk-GHYYFAQN.js";
|
|
32
32
|
|
|
33
33
|
// src/validators.ts
|
|
34
34
|
async function validateSchema(config, configDir) {
|
|
35
|
-
const files = await
|
|
35
|
+
const files = await discoverFragmentFiles(config, configDir);
|
|
36
36
|
const errors = [];
|
|
37
37
|
const warnings = [];
|
|
38
38
|
for (const file of files) {
|
|
39
39
|
try {
|
|
40
|
-
const
|
|
41
|
-
if (!
|
|
40
|
+
const fragment = await loadFragmentFile(file.absolutePath);
|
|
41
|
+
if (!fragment) {
|
|
42
42
|
errors.push({
|
|
43
43
|
file: file.relativePath,
|
|
44
44
|
message: "No default export found",
|
|
45
|
-
details: `
|
|
45
|
+
details: `Fragment files must have a default export from defineFragment()`
|
|
46
46
|
});
|
|
47
47
|
continue;
|
|
48
48
|
}
|
|
49
|
-
const result =
|
|
49
|
+
const result = fragmentDefinitionSchema.safeParse(fragment);
|
|
50
50
|
if (!result.success) {
|
|
51
51
|
const details = result.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join("; ");
|
|
52
52
|
errors.push({
|
|
53
53
|
file: file.relativePath,
|
|
54
|
-
message: "Invalid
|
|
54
|
+
message: "Invalid fragment schema",
|
|
55
55
|
details
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
58
|
} catch (error) {
|
|
59
59
|
errors.push({
|
|
60
60
|
file: file.relativePath,
|
|
61
|
-
message: "Failed to load
|
|
61
|
+
message: "Failed to load fragment file",
|
|
62
62
|
details: error instanceof Error ? error.message : String(error)
|
|
63
63
|
});
|
|
64
64
|
}
|
|
@@ -70,33 +70,33 @@ async function validateSchema(config, configDir) {
|
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
72
|
async function validateCoverage(config, configDir) {
|
|
73
|
-
const
|
|
73
|
+
const fragmentFiles = await discoverFragmentFiles(config, configDir);
|
|
74
74
|
const componentFiles = await discoverComponentFiles(config, configDir);
|
|
75
75
|
const errors = [];
|
|
76
76
|
const warnings = [];
|
|
77
77
|
const documentedComponents = /* @__PURE__ */ new Set();
|
|
78
|
-
for (const file of
|
|
78
|
+
for (const file of fragmentFiles) {
|
|
79
79
|
try {
|
|
80
|
-
const
|
|
81
|
-
if (
|
|
82
|
-
documentedComponents.add(
|
|
80
|
+
const fragment = await loadFragmentFile(file.absolutePath);
|
|
81
|
+
if (fragment?.meta?.name) {
|
|
82
|
+
documentedComponents.add(fragment.meta.name);
|
|
83
83
|
}
|
|
84
84
|
} catch {
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
for (const file of componentFiles) {
|
|
88
88
|
const componentName = extractComponentName(file.relativePath);
|
|
89
|
-
const
|
|
89
|
+
const fragmentPath = file.relativePath.replace(
|
|
90
90
|
/\.(tsx?|jsx?)$/,
|
|
91
91
|
BRAND.fileExtension
|
|
92
92
|
);
|
|
93
|
-
const
|
|
94
|
-
(s) => s.relativePath ===
|
|
93
|
+
const hasFragmentFile = fragmentFiles.some(
|
|
94
|
+
(s) => s.relativePath === fragmentPath
|
|
95
95
|
);
|
|
96
|
-
if (!
|
|
96
|
+
if (!hasFragmentFile && !documentedComponents.has(componentName)) {
|
|
97
97
|
warnings.push({
|
|
98
98
|
file: file.relativePath,
|
|
99
|
-
message: `Component "${componentName}" has no
|
|
99
|
+
message: `Component "${componentName}" has no fragment documentation`
|
|
100
100
|
});
|
|
101
101
|
}
|
|
102
102
|
}
|
|
@@ -162,11 +162,11 @@ function resolveModulePath(basePath) {
|
|
|
162
162
|
}
|
|
163
163
|
return null;
|
|
164
164
|
}
|
|
165
|
-
function resolveComponentSourcePath(
|
|
165
|
+
function resolveComponentSourcePath(fragmentFileAbsolutePath, componentImportPath) {
|
|
166
166
|
if (!componentImportPath) return null;
|
|
167
167
|
if (!componentImportPath.startsWith(".")) return null;
|
|
168
|
-
const
|
|
169
|
-
const basePath = resolve(
|
|
168
|
+
const fragmentDir = dirname(fragmentFileAbsolutePath);
|
|
169
|
+
const basePath = resolve(fragmentDir, componentImportPath);
|
|
170
170
|
return resolveModulePath(basePath);
|
|
171
171
|
}
|
|
172
172
|
function collectTopLevelDeclarations(sourceFile) {
|
|
@@ -435,8 +435,8 @@ import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
|
435
435
|
import { join as join2 } from "path";
|
|
436
436
|
import { readdirSync } from "fs";
|
|
437
437
|
import { EDGE_TYPE_WEIGHTS, computeHealthFromData } from "@fragments-sdk/context/graph";
|
|
438
|
-
async function buildComponentGraph(
|
|
439
|
-
const knownComponents = new Set(Object.keys(
|
|
438
|
+
async function buildComponentGraph(fragments, blocks, componentDir, options) {
|
|
439
|
+
const knownComponents = new Set(Object.keys(fragments));
|
|
440
440
|
const allEdges = [];
|
|
441
441
|
const autoDetected = /* @__PURE__ */ new Map();
|
|
442
442
|
const warnings = [];
|
|
@@ -452,31 +452,31 @@ async function buildComponentGraph(segments, blocks, componentDir, options) {
|
|
|
452
452
|
});
|
|
453
453
|
}
|
|
454
454
|
}
|
|
455
|
-
const jsxEdges = extractJsxUsageEdges(
|
|
455
|
+
const jsxEdges = extractJsxUsageEdges(fragments, knownComponents);
|
|
456
456
|
allEdges.push(...jsxEdges);
|
|
457
457
|
const blockEdges = extractBlockEdges(blocks);
|
|
458
458
|
allEdges.push(...blockEdges);
|
|
459
|
-
const relationEdges = extractRelationEdges(
|
|
459
|
+
const relationEdges = extractRelationEdges(fragments);
|
|
460
460
|
allEdges.push(...relationEdges);
|
|
461
|
-
const requiredChildrenMap = inferRequiredChildren(
|
|
461
|
+
const requiredChildrenMap = inferRequiredChildren(fragments, autoDetected);
|
|
462
462
|
for (const [name, children] of requiredChildrenMap) {
|
|
463
463
|
const existing = autoDetected.get(name) ?? {};
|
|
464
464
|
autoDetected.set(name, { ...existing, requiredChildren: children });
|
|
465
465
|
}
|
|
466
|
-
const patternsMap = generateCommonPatterns(
|
|
466
|
+
const patternsMap = generateCommonPatterns(fragments, autoDetected);
|
|
467
467
|
for (const [name, patterns] of patternsMap) {
|
|
468
468
|
const existing = autoDetected.get(name) ?? {};
|
|
469
469
|
autoDetected.set(name, { ...existing, commonPatterns: patterns });
|
|
470
470
|
}
|
|
471
471
|
const mergedEdges = mergeAndDeduplicate(allEdges);
|
|
472
|
-
const nodes = Object.entries(
|
|
472
|
+
const nodes = Object.entries(fragments).map(([name, fragment]) => {
|
|
473
473
|
const detected = autoDetected.get(name);
|
|
474
474
|
return {
|
|
475
475
|
name,
|
|
476
|
-
category:
|
|
477
|
-
status:
|
|
478
|
-
compositionPattern:
|
|
479
|
-
subComponents:
|
|
476
|
+
category: fragment.meta.category,
|
|
477
|
+
status: fragment.meta.status ?? "stable",
|
|
478
|
+
compositionPattern: fragment.ai?.compositionPattern ?? detected?.compositionPattern,
|
|
479
|
+
subComponents: fragment.ai?.subComponents ?? detected?.subComponents
|
|
480
480
|
};
|
|
481
481
|
});
|
|
482
482
|
const blockIndex = /* @__PURE__ */ new Map();
|
|
@@ -488,14 +488,14 @@ async function buildComponentGraph(segments, blocks, componentDir, options) {
|
|
|
488
488
|
}
|
|
489
489
|
}
|
|
490
490
|
const health = computeHealthFromData(nodes, mergedEdges, blockIndex);
|
|
491
|
-
for (const [name,
|
|
491
|
+
for (const [name, fragment] of Object.entries(fragments)) {
|
|
492
492
|
const detected = autoDetected.get(name);
|
|
493
493
|
if (!detected) continue;
|
|
494
|
-
if (
|
|
495
|
-
const declared = new Set(
|
|
494
|
+
if (fragment.ai?.subComponents && detected.subComponents) {
|
|
495
|
+
const declared = new Set(fragment.ai.subComponents);
|
|
496
496
|
const found = new Set(detected.subComponents);
|
|
497
497
|
const missing = detected.subComponents.filter((s) => !declared.has(s));
|
|
498
|
-
const extra =
|
|
498
|
+
const extra = fragment.ai.subComponents.filter((s) => !found.has(s));
|
|
499
499
|
if (missing.length > 0) {
|
|
500
500
|
warnings.push(
|
|
501
501
|
`${name}: declares ${declared.size} subComponents but code has ${found.size}. Missing from declaration: ${missing.join(", ")}`
|
|
@@ -631,12 +631,12 @@ function extractSubComponents(componentDir, knownComponents) {
|
|
|
631
631
|
}
|
|
632
632
|
return result;
|
|
633
633
|
}
|
|
634
|
-
function extractJsxUsageEdges(
|
|
634
|
+
function extractJsxUsageEdges(fragments, knownComponents) {
|
|
635
635
|
const edges = [];
|
|
636
636
|
const jsxTagRegex = /<([A-Z][a-zA-Z]*(?:\.[A-Z][a-zA-Z]*)?)/g;
|
|
637
|
-
for (const [name,
|
|
637
|
+
for (const [name, fragment] of Object.entries(fragments)) {
|
|
638
638
|
const usedComponents = /* @__PURE__ */ new Set();
|
|
639
|
-
for (const variant of
|
|
639
|
+
for (const variant of fragment.variants) {
|
|
640
640
|
if (!variant.code) continue;
|
|
641
641
|
let match;
|
|
642
642
|
jsxTagRegex.lastIndex = 0;
|
|
@@ -680,7 +680,7 @@ function extractBlockEdges(blocks) {
|
|
|
680
680
|
}
|
|
681
681
|
return edges;
|
|
682
682
|
}
|
|
683
|
-
function extractRelationEdges(
|
|
683
|
+
function extractRelationEdges(fragments) {
|
|
684
684
|
const edges = [];
|
|
685
685
|
const relationToEdgeType = {
|
|
686
686
|
parent: "parent-of",
|
|
@@ -690,9 +690,9 @@ function extractRelationEdges(segments) {
|
|
|
690
690
|
alternative: "alternative-to",
|
|
691
691
|
sibling: "sibling-of"
|
|
692
692
|
};
|
|
693
|
-
for (const [name,
|
|
694
|
-
if (!
|
|
695
|
-
for (const rel of
|
|
693
|
+
for (const [name, fragment] of Object.entries(fragments)) {
|
|
694
|
+
if (!fragment.relations) continue;
|
|
695
|
+
for (const rel of fragment.relations) {
|
|
696
696
|
const edgeType = relationToEdgeType[rel.relationship];
|
|
697
697
|
if (!edgeType) continue;
|
|
698
698
|
let source;
|
|
@@ -716,13 +716,13 @@ function extractRelationEdges(segments) {
|
|
|
716
716
|
}
|
|
717
717
|
return edges;
|
|
718
718
|
}
|
|
719
|
-
function inferRequiredChildren(
|
|
719
|
+
function inferRequiredChildren(fragments, autoDetected) {
|
|
720
720
|
const result = /* @__PURE__ */ new Map();
|
|
721
|
-
for (const [name,
|
|
721
|
+
for (const [name, fragment] of Object.entries(fragments)) {
|
|
722
722
|
const detected = autoDetected.get(name);
|
|
723
|
-
const subs = detected?.subComponents ??
|
|
723
|
+
const subs = detected?.subComponents ?? fragment.ai?.subComponents;
|
|
724
724
|
if (!subs || subs.length === 0) continue;
|
|
725
|
-
const variantsWithCode =
|
|
725
|
+
const variantsWithCode = fragment.variants.filter((v) => v.code);
|
|
726
726
|
if (variantsWithCode.length === 0) continue;
|
|
727
727
|
const required = [];
|
|
728
728
|
for (const sub of subs) {
|
|
@@ -741,13 +741,13 @@ function inferRequiredChildren(segments, autoDetected) {
|
|
|
741
741
|
}
|
|
742
742
|
return result;
|
|
743
743
|
}
|
|
744
|
-
function generateCommonPatterns(
|
|
744
|
+
function generateCommonPatterns(fragments, autoDetected) {
|
|
745
745
|
const result = /* @__PURE__ */ new Map();
|
|
746
|
-
for (const [name,
|
|
746
|
+
for (const [name, fragment] of Object.entries(fragments)) {
|
|
747
747
|
const detected = autoDetected.get(name);
|
|
748
|
-
const subs = detected?.subComponents ??
|
|
748
|
+
const subs = detected?.subComponents ?? fragment.ai?.subComponents;
|
|
749
749
|
if (!subs || subs.length === 0) continue;
|
|
750
|
-
const firstVariant =
|
|
750
|
+
const firstVariant = fragment.variants.find((v) => v.code);
|
|
751
751
|
if (!firstVariant?.code) continue;
|
|
752
752
|
const usedSubs = [];
|
|
753
753
|
for (const sub of subs) {
|
|
@@ -848,15 +848,15 @@ function mergeDocumentedAndAutoProps(documentedProps, autoProps) {
|
|
|
848
848
|
})
|
|
849
849
|
);
|
|
850
850
|
}
|
|
851
|
-
async function
|
|
852
|
-
const files = await
|
|
851
|
+
async function buildFragments(config, configDir) {
|
|
852
|
+
const files = await discoverFragmentFiles(config, configDir);
|
|
853
853
|
const errors = [];
|
|
854
854
|
const warnings = [];
|
|
855
|
-
const
|
|
855
|
+
const fragments = {};
|
|
856
856
|
for (const file of files) {
|
|
857
857
|
try {
|
|
858
858
|
const content = await readFile(file.absolutePath, "utf-8");
|
|
859
|
-
const parsed =
|
|
859
|
+
const parsed = parseFragmentFile(content, file.relativePath);
|
|
860
860
|
for (const warning of parsed.warnings) {
|
|
861
861
|
warnings.push({ file: file.relativePath, warning });
|
|
862
862
|
}
|
|
@@ -945,9 +945,11 @@ async function buildSegments(config, configDir) {
|
|
|
945
945
|
...v.args && { args: v.args }
|
|
946
946
|
})),
|
|
947
947
|
// Include AI metadata if present
|
|
948
|
-
...parsed.ai && { ai: parsed.ai }
|
|
948
|
+
...parsed.ai && { ai: parsed.ai },
|
|
949
|
+
// Include contract metadata if present
|
|
950
|
+
...parsed.contract && { contract: parsed.contract }
|
|
949
951
|
};
|
|
950
|
-
|
|
952
|
+
fragments[parsed.meta.name] = compiled;
|
|
951
953
|
} catch (error) {
|
|
952
954
|
errors.push({
|
|
953
955
|
file: file.relativePath,
|
|
@@ -960,7 +962,7 @@ async function buildSegments(config, configDir) {
|
|
|
960
962
|
const blockFiles = await discoverBlockFiles(configDir, config.exclude);
|
|
961
963
|
for (const file of blockFiles) {
|
|
962
964
|
try {
|
|
963
|
-
let raw = await
|
|
965
|
+
let raw = await loadFragmentFile(file.absolutePath);
|
|
964
966
|
if (raw && "default" in raw && typeof raw.default === "object") {
|
|
965
967
|
raw = raw.default;
|
|
966
968
|
}
|
|
@@ -997,7 +999,7 @@ async function buildSegments(config, configDir) {
|
|
|
997
999
|
}
|
|
998
1000
|
for (const t of catTokens) {
|
|
999
1001
|
if (!mergedCategories[cat].some((e) => e.name === t.name)) {
|
|
1000
|
-
mergedCategories[cat].push({ name: t.name, description: t.description });
|
|
1002
|
+
mergedCategories[cat].push({ name: t.name, ...t.value && { value: t.value }, description: t.description });
|
|
1001
1003
|
}
|
|
1002
1004
|
}
|
|
1003
1005
|
}
|
|
@@ -1020,22 +1022,22 @@ async function buildSegments(config, configDir) {
|
|
|
1020
1022
|
const componentDir = resolve3(configDir, "src", "components");
|
|
1021
1023
|
let graphData;
|
|
1022
1024
|
try {
|
|
1023
|
-
const graphResult = await buildComponentGraph(
|
|
1024
|
-
for (const [name,
|
|
1025
|
+
const graphResult = await buildComponentGraph(fragments, blocks, componentDir);
|
|
1026
|
+
for (const [name, fragment] of Object.entries(fragments)) {
|
|
1025
1027
|
const detected = graphResult.autoDetected.get(name);
|
|
1026
1028
|
if (!detected) continue;
|
|
1027
|
-
if (!
|
|
1028
|
-
if (!
|
|
1029
|
-
|
|
1029
|
+
if (!fragment.ai) fragment.ai = {};
|
|
1030
|
+
if (!fragment.ai.subComponents && detected.subComponents) {
|
|
1031
|
+
fragment.ai.subComponents = detected.subComponents;
|
|
1030
1032
|
}
|
|
1031
|
-
if (!
|
|
1032
|
-
|
|
1033
|
+
if (!fragment.ai.compositionPattern && detected.compositionPattern) {
|
|
1034
|
+
fragment.ai.compositionPattern = detected.compositionPattern;
|
|
1033
1035
|
}
|
|
1034
|
-
if (!
|
|
1035
|
-
|
|
1036
|
+
if (!fragment.ai.commonPatterns && detected.commonPatterns) {
|
|
1037
|
+
fragment.ai.commonPatterns = detected.commonPatterns;
|
|
1036
1038
|
}
|
|
1037
|
-
if (!
|
|
1038
|
-
|
|
1039
|
+
if (!fragment.ai.requiredChildren && detected.requiredChildren) {
|
|
1040
|
+
fragment.ai.requiredChildren = detected.requiredChildren;
|
|
1039
1041
|
}
|
|
1040
1042
|
}
|
|
1041
1043
|
for (const w of graphResult.warnings) {
|
|
@@ -1052,7 +1054,7 @@ async function buildSegments(config, configDir) {
|
|
|
1052
1054
|
version: "1.0.0",
|
|
1053
1055
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1054
1056
|
...packageName && { packageName },
|
|
1055
|
-
|
|
1057
|
+
fragments,
|
|
1056
1058
|
...Object.keys(blocks).length > 0 && { blocks },
|
|
1057
1059
|
...tokens && { tokens },
|
|
1058
1060
|
...graphData && { graph: graphData }
|
|
@@ -1062,7 +1064,7 @@ async function buildSegments(config, configDir) {
|
|
|
1062
1064
|
return {
|
|
1063
1065
|
success: errors.length === 0,
|
|
1064
1066
|
outputPath,
|
|
1065
|
-
|
|
1067
|
+
fragmentCount: Object.keys(fragments).length,
|
|
1066
1068
|
errors,
|
|
1067
1069
|
warnings
|
|
1068
1070
|
};
|
|
@@ -1118,9 +1120,9 @@ async function runScreenshotCommand(config, configDir, options = {}) {
|
|
|
1118
1120
|
viewport: options.width && options.height ? { width: options.width, height: options.height } : config.screenshots?.viewport
|
|
1119
1121
|
});
|
|
1120
1122
|
await storage.initialize();
|
|
1121
|
-
const
|
|
1122
|
-
if (
|
|
1123
|
-
console.log(pc.yellow("No
|
|
1123
|
+
const fragmentFiles = await discoverFragmentFiles(config, configDir);
|
|
1124
|
+
if (fragmentFiles.length === 0) {
|
|
1125
|
+
console.log(pc.yellow("No fragment files found."));
|
|
1124
1126
|
return {
|
|
1125
1127
|
success: true,
|
|
1126
1128
|
captured: 0,
|
|
@@ -1129,12 +1131,12 @@ async function runScreenshotCommand(config, configDir, options = {}) {
|
|
|
1129
1131
|
totalTimeMs: Date.now() - startTime
|
|
1130
1132
|
};
|
|
1131
1133
|
}
|
|
1132
|
-
const
|
|
1133
|
-
for (const file of
|
|
1134
|
+
const fragments = [];
|
|
1135
|
+
for (const file of fragmentFiles) {
|
|
1134
1136
|
try {
|
|
1135
|
-
const
|
|
1136
|
-
if (
|
|
1137
|
-
|
|
1137
|
+
const fragment = await loadFragmentFile(file.absolutePath);
|
|
1138
|
+
if (fragment) {
|
|
1139
|
+
fragments.push({ path: file.relativePath, fragment });
|
|
1138
1140
|
}
|
|
1139
1141
|
} catch (error) {
|
|
1140
1142
|
errors.push({
|
|
@@ -1144,8 +1146,8 @@ async function runScreenshotCommand(config, configDir, options = {}) {
|
|
|
1144
1146
|
});
|
|
1145
1147
|
}
|
|
1146
1148
|
}
|
|
1147
|
-
const
|
|
1148
|
-
if (options.component &&
|
|
1149
|
+
const filteredFragments = options.component ? fragments.filter((s) => s.fragment.meta.name === options.component) : fragments;
|
|
1150
|
+
if (options.component && filteredFragments.length === 0) {
|
|
1149
1151
|
console.log(pc.yellow(`Component "${options.component}" not found.`));
|
|
1150
1152
|
return {
|
|
1151
1153
|
success: false,
|
|
@@ -1156,11 +1158,11 @@ async function runScreenshotCommand(config, configDir, options = {}) {
|
|
|
1156
1158
|
};
|
|
1157
1159
|
}
|
|
1158
1160
|
const variantsToCapture = [];
|
|
1159
|
-
for (const {
|
|
1160
|
-
const variants = options.variant ?
|
|
1161
|
+
for (const { fragment } of filteredFragments) {
|
|
1162
|
+
const variants = options.variant ? fragment.variants.filter((v) => v.name === options.variant) : fragment.variants;
|
|
1161
1163
|
for (const variant of variants) {
|
|
1162
1164
|
variantsToCapture.push({
|
|
1163
|
-
component:
|
|
1165
|
+
component: fragment.meta.name,
|
|
1164
1166
|
variant: variant.name,
|
|
1165
1167
|
render: variant.render
|
|
1166
1168
|
});
|
|
@@ -1264,9 +1266,9 @@ async function runDiffCommand(config, configDir, options = {}) {
|
|
|
1264
1266
|
await storage.initialize();
|
|
1265
1267
|
const threshold = options.threshold ?? config.screenshots?.threshold ?? DEFAULTS.diffThreshold;
|
|
1266
1268
|
const diffEngine = new DiffEngine(threshold);
|
|
1267
|
-
const
|
|
1268
|
-
if (
|
|
1269
|
-
console.log(pc2.yellow("No
|
|
1269
|
+
const fragmentFiles = await discoverFragmentFiles(config, configDir);
|
|
1270
|
+
if (fragmentFiles.length === 0) {
|
|
1271
|
+
console.log(pc2.yellow("No fragment files found."));
|
|
1270
1272
|
return {
|
|
1271
1273
|
success: true,
|
|
1272
1274
|
total: 0,
|
|
@@ -1277,18 +1279,18 @@ async function runDiffCommand(config, configDir, options = {}) {
|
|
|
1277
1279
|
totalTimeMs: Date.now() - startTime
|
|
1278
1280
|
};
|
|
1279
1281
|
}
|
|
1280
|
-
const
|
|
1281
|
-
for (const file of
|
|
1282
|
+
const fragments = [];
|
|
1283
|
+
for (const file of fragmentFiles) {
|
|
1282
1284
|
try {
|
|
1283
|
-
const
|
|
1284
|
-
if (
|
|
1285
|
-
|
|
1285
|
+
const fragment = await loadFragmentFile(file.absolutePath);
|
|
1286
|
+
if (fragment) {
|
|
1287
|
+
fragments.push({ path: file.relativePath, fragment });
|
|
1286
1288
|
}
|
|
1287
1289
|
} catch {
|
|
1288
1290
|
}
|
|
1289
1291
|
}
|
|
1290
|
-
const
|
|
1291
|
-
if (options.component &&
|
|
1292
|
+
const filteredFragments = options.component ? fragments.filter((s) => s.fragment.meta.name === options.component) : fragments;
|
|
1293
|
+
if (options.component && filteredFragments.length === 0) {
|
|
1292
1294
|
console.log(pc2.yellow(`Component "${options.component}" not found.`));
|
|
1293
1295
|
return {
|
|
1294
1296
|
success: false,
|
|
@@ -1301,11 +1303,11 @@ async function runDiffCommand(config, configDir, options = {}) {
|
|
|
1301
1303
|
};
|
|
1302
1304
|
}
|
|
1303
1305
|
const variantsToDiff = [];
|
|
1304
|
-
for (const {
|
|
1305
|
-
const variants = options.variant ?
|
|
1306
|
+
for (const { fragment } of filteredFragments) {
|
|
1307
|
+
const variants = options.variant ? fragment.variants.filter((v) => v.name === options.variant) : fragment.variants;
|
|
1306
1308
|
for (const variant of variants) {
|
|
1307
1309
|
variantsToDiff.push({
|
|
1308
|
-
component:
|
|
1310
|
+
component: fragment.meta.name,
|
|
1309
1311
|
variant: variant.name
|
|
1310
1312
|
});
|
|
1311
1313
|
}
|
|
@@ -1458,9 +1460,9 @@ async function runAnalyzeCommand(config, configDir, options = {}) {
|
|
|
1458
1460
|
console.log(pc3.cyan(`
|
|
1459
1461
|
${BRAND.name} Analyzer
|
|
1460
1462
|
`));
|
|
1461
|
-
const
|
|
1462
|
-
if (!existsSync4(
|
|
1463
|
-
console.log(pc3.red(`\u2717 No
|
|
1463
|
+
const fragmentsPath = join4(configDir, config.outFile ?? "fragments.json");
|
|
1464
|
+
if (!existsSync4(fragmentsPath)) {
|
|
1465
|
+
console.log(pc3.red(`\u2717 No fragments.json found. Run \`${BRAND.cliCommand} build\` first.
|
|
1464
1466
|
`));
|
|
1465
1467
|
return {
|
|
1466
1468
|
success: false,
|
|
@@ -1468,7 +1470,7 @@ ${BRAND.name} Analyzer
|
|
|
1468
1470
|
};
|
|
1469
1471
|
}
|
|
1470
1472
|
console.log(pc3.dim("Analyzing design system...\n"));
|
|
1471
|
-
const content = await readFile2(
|
|
1473
|
+
const content = await readFile2(fragmentsPath, "utf-8");
|
|
1472
1474
|
const data = JSON.parse(content);
|
|
1473
1475
|
const analytics = analyzeDesignSystem(data);
|
|
1474
1476
|
printConsoleSummary(analytics);
|
|
@@ -1553,7 +1555,7 @@ function colorizeScore(score) {
|
|
|
1553
1555
|
return pc3.red(`${score}%`);
|
|
1554
1556
|
}
|
|
1555
1557
|
function getDefaultOutputPath(format, configDir) {
|
|
1556
|
-
const filename = format === "html" ? "
|
|
1558
|
+
const filename = format === "html" ? "fragments-report.html" : "fragments-report.json";
|
|
1557
1559
|
return join4(configDir, filename);
|
|
1558
1560
|
}
|
|
1559
1561
|
async function openInBrowser(path) {
|
|
@@ -1616,10 +1618,10 @@ export {
|
|
|
1616
1618
|
validateSchema,
|
|
1617
1619
|
validateCoverage,
|
|
1618
1620
|
validateAll,
|
|
1619
|
-
|
|
1621
|
+
buildFragments,
|
|
1620
1622
|
buildFragmentsDir,
|
|
1621
1623
|
runScreenshotCommand,
|
|
1622
1624
|
runDiffCommand,
|
|
1623
1625
|
runAnalyzeCommand
|
|
1624
1626
|
};
|
|
1625
|
-
//# sourceMappingURL=chunk-
|
|
1627
|
+
//# sourceMappingURL=chunk-7KUSBMI4.js.map
|