@usefragments/core 1.0.0
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/dist/chunk-243QYRUF.js +2145 -0
- package/dist/chunk-243QYRUF.js.map +1 -0
- package/dist/chunk-3LLRNCPX.js +111 -0
- package/dist/chunk-3LLRNCPX.js.map +1 -0
- package/dist/chunk-EIYNNS77.js +48 -0
- package/dist/chunk-EIYNNS77.js.map +1 -0
- package/dist/chunk-JNBFJ34I.js +326 -0
- package/dist/chunk-JNBFJ34I.js.map +1 -0
- package/dist/chunk-R3X7UBHU.js +228 -0
- package/dist/chunk-R3X7UBHU.js.map +1 -0
- package/dist/chunk-SH4KPIYH.js +393 -0
- package/dist/chunk-SH4KPIYH.js.map +1 -0
- package/dist/chunk-V4VQB57N.js +56 -0
- package/dist/chunk-V4VQB57N.js.map +1 -0
- package/dist/chunk-X34IA4LR.js +319 -0
- package/dist/chunk-X34IA4LR.js.map +1 -0
- package/dist/chunk-YF65VYRY.js +493 -0
- package/dist/chunk-YF65VYRY.js.map +1 -0
- package/dist/codes/index.d.ts +40 -0
- package/dist/codes/index.js +23 -0
- package/dist/codes/index.js.map +1 -0
- package/dist/compiled-types/index.d.ts +5 -0
- package/dist/compiled-types/index.js +1 -0
- package/dist/compiled-types/index.js.map +1 -0
- package/dist/generate/index.d.ts +47 -0
- package/dist/generate/index.js +11 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/governance-BOa3KyiJ.d.ts +3279 -0
- package/dist/graph/index.d.ts +66 -0
- package/dist/graph/index.js +17 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/index.d.ts +11388 -0
- package/dist/index.js +8711 -0
- package/dist/index.js.map +1 -0
- package/dist/package-identity.d.ts +42 -0
- package/dist/package-identity.js +23 -0
- package/dist/package-identity.js.map +1 -0
- package/dist/preview/index.d.ts +484 -0
- package/dist/preview/index.js +1129 -0
- package/dist/preview/index.js.map +1 -0
- package/dist/react-types.d.ts +22 -0
- package/dist/react-types.js +1 -0
- package/dist/react-types.js.map +1 -0
- package/dist/registry.d.ts +2367 -0
- package/dist/registry.js +62 -0
- package/dist/registry.js.map +1 -0
- package/dist/schemas/index.d.ts +2584 -0
- package/dist/schemas/index.js +55 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/severity.d.ts +18 -0
- package/dist/severity.js +27 -0
- package/dist/severity.js.map +1 -0
- package/dist/test-utils.d.ts +14 -0
- package/dist/test-utils.js +63 -0
- package/dist/test-utils.js.map +1 -0
- package/dist/topology/index.d.ts +48 -0
- package/dist/topology/index.js +7 -0
- package/dist/topology/index.js.map +1 -0
- package/dist/types-xJ2xyp_G.d.ts +119 -0
- package/package.json +120 -0
- package/src/__tests__/contract-parser.test.ts +614 -0
- package/src/__tests__/dtcg-generators.test.ts +439 -0
- package/src/__tests__/dtcg-parser.test.ts +884 -0
- package/src/__tests__/preview-runtime.test.tsx +111 -0
- package/src/__tests__/schema.test.ts +31 -0
- package/src/__tests__/severity.test.ts +34 -0
- package/src/__tests__/style-comparison.test.ts +662 -0
- package/src/__tests__/tokens-compat.test.ts +51 -0
- package/src/agent-format.test.ts +105 -0
- package/src/agent-format.ts +141 -0
- package/src/bundle.ts +149 -0
- package/src/codes/__tests__/codes.test.ts +73 -0
- package/src/codes/codes.ts +463 -0
- package/src/codes/index.ts +7 -0
- package/src/codes/source-finding-bridge.ts +113 -0
- package/src/compiled-types/index.ts +293 -0
- package/src/component-contract.ts +231 -0
- package/src/component-discovery.ts +80 -0
- package/src/composition.test.ts +262 -0
- package/src/composition.ts +318 -0
- package/src/config-paths.test.ts +78 -0
- package/src/config-paths.ts +47 -0
- package/src/config.ts +18 -0
- package/src/conform-prove.test.ts +274 -0
- package/src/conform-prove.ts +326 -0
- package/src/conform.ts +160 -0
- package/src/constants.ts +114 -0
- package/src/context.ts +2 -0
- package/src/contract/fixture.ts +110 -0
- package/src/contract/hash.test.ts +86 -0
- package/src/contract/hash.ts +195 -0
- package/src/contract/index.ts +43 -0
- package/src/contract/preimage.test.ts +254 -0
- package/src/contract/preimage.ts +365 -0
- package/src/contract/stamp.test.ts +100 -0
- package/src/contract/stamp.ts +105 -0
- package/src/contract-parser.ts +141 -0
- package/src/defineFragment.test.ts +257 -0
- package/src/defineFragment.ts +293 -0
- package/src/dtcg-generators.ts +324 -0
- package/src/dtcg-parser.ts +1 -0
- package/src/dtcg.ts +237 -0
- package/src/facts/__snapshots__/facts.test.ts.snap +124 -0
- package/src/facts/builders.ts +835 -0
- package/src/facts/compile.ts +422 -0
- package/src/facts/fact-index.ts +394 -0
- package/src/facts/facts.test.ts +494 -0
- package/src/facts/ids.ts +125 -0
- package/src/facts/index.ts +119 -0
- package/src/facts/types.ts +614 -0
- package/src/figma.ts +263 -0
- package/src/fragment-types.ts +214 -0
- package/src/generate/generate.test.ts +594 -0
- package/src/generate/index.ts +438 -0
- package/src/governance-integrity.test.ts +186 -0
- package/src/governance-integrity.ts +282 -0
- package/src/governance.test.ts +300 -0
- package/src/governance.ts +605 -0
- package/src/governance.type-test.ts +75 -0
- package/src/graph/engine.ts +446 -0
- package/src/graph/graph.test.ts +746 -0
- package/src/graph/index.ts +32 -0
- package/src/graph/serialization.ts +55 -0
- package/src/graph/types.ts +178 -0
- package/src/index.ts +891 -0
- package/src/local-canonical.ts +102 -0
- package/src/mcp-snapshot.ts +222 -0
- package/src/package-identity-match.ts +33 -0
- package/src/package-identity.generated.ts +233 -0
- package/src/package-identity.test.ts +99 -0
- package/src/package-identity.ts +157 -0
- package/src/performance-presets.ts +142 -0
- package/src/preview/comparison-artifact.test.ts +228 -0
- package/src/preview/comparison-artifact.ts +181 -0
- package/src/preview/comparison-context.ts +93 -0
- package/src/preview/comparison-evidence.ts +112 -0
- package/src/preview/comparison-format.ts +21 -0
- package/src/preview/comparison-presentation.ts +187 -0
- package/src/preview/comparison-references.test.ts +430 -0
- package/src/preview/comparison-references.ts +72 -0
- package/src/preview/comparison-score.ts +59 -0
- package/src/preview/comparison-styles.ts +197 -0
- package/src/preview/comparison.test.ts +559 -0
- package/src/preview/comparison.ts +488 -0
- package/src/preview/index.ts +10 -0
- package/src/preview/types.ts +309 -0
- package/src/preview/validation.test.ts +290 -0
- package/src/preview/validation.ts +356 -0
- package/src/preview-runtime.tsx +144 -0
- package/src/raw-html-canonical.test.ts +41 -0
- package/src/raw-html-canonical.ts +179 -0
- package/src/react-types.ts +21 -0
- package/src/registry-install-plan.ts +344 -0
- package/src/registry.test.ts +245 -0
- package/src/registry.ts +369 -0
- package/src/rules/a11y-required-accessible-name.ts +93 -0
- package/src/rules/color-math.test.ts +72 -0
- package/src/rules/color-math.ts +192 -0
- package/src/rules/components-forbidden-prop-value.ts +108 -0
- package/src/rules/components-prefer-library.ts +943 -0
- package/src/rules/components-unknown-prop.ts +94 -0
- package/src/rules/composition-pattern-schema.ts +125 -0
- package/src/rules/composition-pattern.test.ts +320 -0
- package/src/rules/composition-pattern.ts +271 -0
- package/src/rules/emit-gate.test.ts +42 -0
- package/src/rules/emit-gate.ts +60 -0
- package/src/rules/finding.ts +54 -0
- package/src/rules/index.ts +235 -0
- package/src/rules/jsx-preferred-component.ts +68 -0
- package/src/rules/jsx-preferred-import-path.ts +67 -0
- package/src/rules/presets.ts +57 -0
- package/src/rules/props-invalid-value.ts +115 -0
- package/src/rules/rules.test.ts +3636 -0
- package/src/rules/spacing-resolution.ts +184 -0
- package/src/rules/styles-no-raw-color.ts +329 -0
- package/src/rules/styles-no-raw-dimensions.ts +357 -0
- package/src/rules/styles-no-raw-spacing.ts +236 -0
- package/src/rules/styles-no-raw-typography.ts +237 -0
- package/src/rules/tailwind-arbitrary-color.test.ts +128 -0
- package/src/rules/tailwind-arbitrary-color.ts +93 -0
- package/src/rules/tailwind-arbitrary-spacing.test.ts +157 -0
- package/src/rules/tailwind-arbitrary-spacing.ts +120 -0
- package/src/rules/tailwind-forbidden-palette.test.ts +116 -0
- package/src/rules/tailwind-forbidden-palette.ts +107 -0
- package/src/rules/tailwind-off-scale-spacing-token.test.ts +100 -0
- package/src/rules/tailwind-off-scale-spacing-token.ts +108 -0
- package/src/rules/tailwind-raw-color-via-token.test.ts +108 -0
- package/src/rules/tailwind-raw-color-via-token.ts +82 -0
- package/src/rules/tailwind-rule-utils.ts +106 -0
- package/src/rules/tailwind-unknown-class.test.ts +157 -0
- package/src/rules/tailwind-unknown-class.ts +121 -0
- package/src/rules/taxonomy.test.ts +238 -0
- package/src/rules/theme-no-theme-coupled-literal.ts +132 -0
- package/src/rules/tiers.ts +111 -0
- package/src/rules/tokens-css-vars-must-be-defined.test.ts +244 -0
- package/src/rules/tokens-css-vars-must-be-defined.ts +156 -0
- package/src/rules/tokens-require-dual-fallback.ts +78 -0
- package/src/rules/types.ts +27 -0
- package/src/rules/utils.test.ts +110 -0
- package/src/rules/utils.ts +599 -0
- package/src/schema.ts +427 -0
- package/src/schemas/index.ts +275 -0
- package/src/schemas/schemas.test.ts +124 -0
- package/src/severity.ts +54 -0
- package/src/storyAdapter.test.ts +571 -0
- package/src/storyAdapter.ts +761 -0
- package/src/storyFilters.test.ts +350 -0
- package/src/storyFilters.ts +253 -0
- package/src/storybook-csf.ts +11 -0
- package/src/style-comparison.ts +423 -0
- package/src/test-utils.ts +68 -0
- package/src/token-parser.ts +2 -0
- package/src/token-types.ts +287 -0
- package/src/tokens/categories.ts +131 -0
- package/src/tokens/color.ts +193 -0
- package/src/tokens/design-token-parser.test.ts +159 -0
- package/src/tokens/design-token-parser.ts +402 -0
- package/src/tokens/dtcg.ts +428 -0
- package/src/tokens/index.ts +130 -0
- package/src/tokens/lookup.ts +19 -0
- package/src/tokens/scss.ts +171 -0
- package/src/tokens/tailwind-v4.ts +187 -0
- package/src/tokens/types.ts +43 -0
- package/src/topology/index.ts +9 -0
- package/src/topology/resolve-area.test.ts +174 -0
- package/src/topology/resolve-area.ts +215 -0
- package/src/types.ts +1057 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compiled fragment types — shared between CLI and MCP packages.
|
|
3
|
+
*
|
|
4
|
+
* These are the JSON-serializable types used in fragments.json and consumed
|
|
5
|
+
* by AI agents, MCP servers, and context generators.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ComponentGovernanceRecord } from '../governance.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Component metadata
|
|
12
|
+
*/
|
|
13
|
+
export interface FragmentMeta {
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
category: string;
|
|
17
|
+
tags?: string[];
|
|
18
|
+
status?: "stable" | "beta" | "deprecated" | "experimental";
|
|
19
|
+
since?: string;
|
|
20
|
+
dependencies?: Array<{ name: string; version: string; reason?: string }>;
|
|
21
|
+
figma?: string;
|
|
22
|
+
figmaProps?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Usage guidelines for AI agents and developers
|
|
27
|
+
*/
|
|
28
|
+
export interface FragmentUsage {
|
|
29
|
+
when: string[];
|
|
30
|
+
whenNot: string[];
|
|
31
|
+
guidelines?: string[];
|
|
32
|
+
accessibility?: string[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Definition for a single prop
|
|
37
|
+
*/
|
|
38
|
+
export interface PropDefinition {
|
|
39
|
+
type: string;
|
|
40
|
+
values?: readonly string[];
|
|
41
|
+
default?: unknown;
|
|
42
|
+
description: string;
|
|
43
|
+
required?: boolean;
|
|
44
|
+
constraints?: string[];
|
|
45
|
+
typeDetails?: Record<string, unknown>;
|
|
46
|
+
controlType?: string;
|
|
47
|
+
controlOptions?: {
|
|
48
|
+
min?: number;
|
|
49
|
+
max?: number;
|
|
50
|
+
step?: number;
|
|
51
|
+
presetColors?: string[];
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Relationship to another component
|
|
57
|
+
*/
|
|
58
|
+
export interface ComponentRelation {
|
|
59
|
+
component: string;
|
|
60
|
+
relationship: string;
|
|
61
|
+
note: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Agent-optimized contract metadata
|
|
66
|
+
*/
|
|
67
|
+
export interface FragmentContract {
|
|
68
|
+
propsSummary?: string[];
|
|
69
|
+
a11yRules?: string[];
|
|
70
|
+
bans?: Array<{ pattern: string; message: string }>;
|
|
71
|
+
scenarioTags?: string[];
|
|
72
|
+
/** Per-component performance budget override in bytes (gzipped) */
|
|
73
|
+
performanceBudget?: number;
|
|
74
|
+
/** Sub-component slot metadata for compound components */
|
|
75
|
+
compoundChildren?: Record<string, {
|
|
76
|
+
required?: boolean;
|
|
77
|
+
accepts?: string[];
|
|
78
|
+
description?: string;
|
|
79
|
+
}>;
|
|
80
|
+
/** Canonical JSX usage examples showing how to assemble the component */
|
|
81
|
+
canonicalUsage?: string[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Provenance tracking for generated fragments
|
|
86
|
+
*/
|
|
87
|
+
export interface FragmentGenerated {
|
|
88
|
+
source: "storybook" | "manual" | "ai" | "extracted" | "merged" | "migrated";
|
|
89
|
+
sourceFile?: string;
|
|
90
|
+
/** @deprecated Use provenance.verified instead */
|
|
91
|
+
confidence?: number;
|
|
92
|
+
verified?: boolean;
|
|
93
|
+
timestamp?: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* AI-specific metadata
|
|
98
|
+
*/
|
|
99
|
+
export interface AIMetadata {
|
|
100
|
+
compositionPattern?: "compound" | "simple" | "controlled" | "wrapper";
|
|
101
|
+
subComponents?: string[];
|
|
102
|
+
requiredChildren?: string[];
|
|
103
|
+
commonPatterns?: string[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Performance data for a component (from bundle size measurement)
|
|
108
|
+
*/
|
|
109
|
+
/**
|
|
110
|
+
* A single import contributing to bundle size
|
|
111
|
+
*/
|
|
112
|
+
export interface ImportEntry {
|
|
113
|
+
/** Resolved file path (relative to project root) */
|
|
114
|
+
path: string;
|
|
115
|
+
/** Bytes contributed to the bundle */
|
|
116
|
+
bytes: number;
|
|
117
|
+
/** Percentage of total bundle size */
|
|
118
|
+
percent: number;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface PerformanceData {
|
|
122
|
+
/** Gzipped bundle size in bytes */
|
|
123
|
+
bundleSize: number;
|
|
124
|
+
/** Raw (minified, not gzipped) bundle size in bytes */
|
|
125
|
+
rawSize: number;
|
|
126
|
+
/** Complexity classification */
|
|
127
|
+
complexity: 'lightweight' | 'moderate' | 'heavy';
|
|
128
|
+
/** Percentage of budget used (0-100+) */
|
|
129
|
+
budgetPercent: number;
|
|
130
|
+
/** Whether the component exceeds its budget */
|
|
131
|
+
overBudget: boolean;
|
|
132
|
+
/** ISO timestamp when measured */
|
|
133
|
+
measuredAt: string;
|
|
134
|
+
/** Top imports by size (largest first) */
|
|
135
|
+
imports?: ImportEntry[];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface ObservedUsageProp {
|
|
139
|
+
name: string;
|
|
140
|
+
kind: 'static' | 'dynamic' | 'spread' | 'jsx' | 'boolean' | 'null';
|
|
141
|
+
value?: string | number | boolean | null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface ObservedComponentUsage {
|
|
145
|
+
/** Source file path relative to the fragments config root */
|
|
146
|
+
file: string;
|
|
147
|
+
/** 1-indexed source line */
|
|
148
|
+
line: number;
|
|
149
|
+
/** 0-indexed source column */
|
|
150
|
+
column: number;
|
|
151
|
+
props: ObservedUsageProp[];
|
|
152
|
+
parentElement?: string;
|
|
153
|
+
conditional?: boolean;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Compiled fragment data (JSON-serializable for AI consumption)
|
|
158
|
+
*/
|
|
159
|
+
export interface CompiledFragment {
|
|
160
|
+
filePath: string;
|
|
161
|
+
meta: FragmentMeta;
|
|
162
|
+
/** Canonical v2 guidance. `usage` is retained for compatibility. */
|
|
163
|
+
guidance?: FragmentUsage;
|
|
164
|
+
usage: FragmentUsage;
|
|
165
|
+
props: Record<string, PropDefinition>;
|
|
166
|
+
/** Normalized component governance records emitted from *.fragment.ts. */
|
|
167
|
+
governance?: ComponentGovernanceRecord[];
|
|
168
|
+
relations?: ComponentRelation[];
|
|
169
|
+
variants: Array<{
|
|
170
|
+
name: string;
|
|
171
|
+
description: string;
|
|
172
|
+
code?: string;
|
|
173
|
+
figma?: string;
|
|
174
|
+
args?: Record<string, unknown>;
|
|
175
|
+
}>;
|
|
176
|
+
contract?: FragmentContract;
|
|
177
|
+
ai?: AIMetadata;
|
|
178
|
+
/** Framework hint from contract, used by preview adapters and Cloud */
|
|
179
|
+
framework?: string;
|
|
180
|
+
/** Top-level compact prop summaries for agent first-pass */
|
|
181
|
+
propsSummary?: string[];
|
|
182
|
+
/** Source file path relative to config root (for contract-sourced fragments) */
|
|
183
|
+
sourcePath?: string;
|
|
184
|
+
/** Named export for preview adapter resolution */
|
|
185
|
+
exportName?: string;
|
|
186
|
+
/** Clean provenance tracking (V2) */
|
|
187
|
+
provenance?: {
|
|
188
|
+
source: string;
|
|
189
|
+
verified: boolean;
|
|
190
|
+
frameworkSupport?: string;
|
|
191
|
+
sourceHash?: string;
|
|
192
|
+
extractedAt?: string;
|
|
193
|
+
};
|
|
194
|
+
/** Component performance data from bundle size measurement */
|
|
195
|
+
performance?: PerformanceData;
|
|
196
|
+
/** Observed JSX call sites captured during `fragments scan` */
|
|
197
|
+
usages?: ObservedComponentUsage[];
|
|
198
|
+
_generated?: FragmentGenerated;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Compiled block data (JSON-serializable for AI consumption)
|
|
203
|
+
*/
|
|
204
|
+
export interface CompiledBlock {
|
|
205
|
+
filePath: string;
|
|
206
|
+
name: string;
|
|
207
|
+
description: string;
|
|
208
|
+
category: string;
|
|
209
|
+
components: string[];
|
|
210
|
+
code: string;
|
|
211
|
+
tags?: string[];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* A single token entry in the compiled output
|
|
216
|
+
*/
|
|
217
|
+
export interface CompiledTokenEntry {
|
|
218
|
+
name: string;
|
|
219
|
+
value?: string;
|
|
220
|
+
description?: string;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Compiled token data stored in fragments.json
|
|
225
|
+
*/
|
|
226
|
+
export interface CompiledTokenData {
|
|
227
|
+
prefix: string;
|
|
228
|
+
total: number;
|
|
229
|
+
categories: Record<string, CompiledTokenEntry[]>;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Performance summary across all components
|
|
234
|
+
*/
|
|
235
|
+
export interface PerformanceSummary {
|
|
236
|
+
/** Preset name used */
|
|
237
|
+
preset: string;
|
|
238
|
+
/** Budget applied in bytes */
|
|
239
|
+
budget: number;
|
|
240
|
+
/** Total components measured */
|
|
241
|
+
total: number;
|
|
242
|
+
/** Number of components over budget */
|
|
243
|
+
overBudget: number;
|
|
244
|
+
/** Distribution by tier */
|
|
245
|
+
tiers: Record<string, number>;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* The compiled fragments.json structure
|
|
250
|
+
*/
|
|
251
|
+
export interface CompiledFragmentsFile {
|
|
252
|
+
version: string;
|
|
253
|
+
generatedAt: string;
|
|
254
|
+
/** CLI version that produced this file, used for freshness checks */
|
|
255
|
+
generatorVersion?: string;
|
|
256
|
+
/** Relative source/config inputs used to build this file, used for freshness checks */
|
|
257
|
+
buildInputs?: string[];
|
|
258
|
+
packageName?: string;
|
|
259
|
+
fragments: Record<string, CompiledFragment>;
|
|
260
|
+
blocks?: Record<string, CompiledBlock>;
|
|
261
|
+
tokens?: CompiledTokenData;
|
|
262
|
+
/** Component relationship graph for AI structural queries */
|
|
263
|
+
graph?: import('../graph/types.js').SerializedComponentGraph;
|
|
264
|
+
/** Performance measurement summary */
|
|
265
|
+
performanceSummary?: PerformanceSummary;
|
|
266
|
+
/** @deprecated Use blocks instead */
|
|
267
|
+
recipes?: Record<string, CompiledBlock>;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Theme identifier
|
|
272
|
+
*/
|
|
273
|
+
export type Theme = "light" | "dark";
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Verification result
|
|
277
|
+
*/
|
|
278
|
+
export interface VerifyResult {
|
|
279
|
+
verdict: "pass" | "fail" | "error";
|
|
280
|
+
matches: boolean;
|
|
281
|
+
diffPercentage: number;
|
|
282
|
+
screenshot: string;
|
|
283
|
+
baseline: string;
|
|
284
|
+
diffImage?: string;
|
|
285
|
+
notes: string[];
|
|
286
|
+
error?: string;
|
|
287
|
+
timing: {
|
|
288
|
+
renderMs: number;
|
|
289
|
+
captureMs: number;
|
|
290
|
+
diffMs: number;
|
|
291
|
+
totalMs: number;
|
|
292
|
+
};
|
|
293
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-agnostic component contract format.
|
|
3
|
+
*
|
|
4
|
+
* Allows non-React teams to define component metadata via `.contract.json`
|
|
5
|
+
* files instead of `.fragment.tsx`. Maps trivially to CompiledFragment.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Component Contract interface
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
export interface ComponentContract {
|
|
15
|
+
/** JSON Schema reference for tooling — required for validation */
|
|
16
|
+
$schema: string;
|
|
17
|
+
|
|
18
|
+
/** Component name */
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
category: string;
|
|
22
|
+
tags?: string[];
|
|
23
|
+
status?: 'stable' | 'beta' | 'deprecated' | 'experimental';
|
|
24
|
+
|
|
25
|
+
/** Framework hint (for extraction and documentation) */
|
|
26
|
+
framework?: 'react' | 'vue' | 'svelte' | 'web-components' | 'angular';
|
|
27
|
+
|
|
28
|
+
/** Path to the component source file, relative to fragments.config.ts root */
|
|
29
|
+
sourcePath: string;
|
|
30
|
+
|
|
31
|
+
/** Named export from the source file */
|
|
32
|
+
exportName: string;
|
|
33
|
+
|
|
34
|
+
/** Compact one-line-per-prop summaries for agent first-pass (e.g., "variant: primary|secondary (required)") */
|
|
35
|
+
propsSummary: string[];
|
|
36
|
+
|
|
37
|
+
/** Component props schema */
|
|
38
|
+
props: Record<string, {
|
|
39
|
+
type: string;
|
|
40
|
+
values?: string[];
|
|
41
|
+
default?: unknown;
|
|
42
|
+
description: string;
|
|
43
|
+
required?: boolean;
|
|
44
|
+
constraints?: string[];
|
|
45
|
+
}>;
|
|
46
|
+
|
|
47
|
+
/** Usage guidelines */
|
|
48
|
+
usage: {
|
|
49
|
+
when: string[];
|
|
50
|
+
whenNot: string[];
|
|
51
|
+
guidelines?: string[];
|
|
52
|
+
accessibility?: string[];
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** Code examples (as strings, not render functions) */
|
|
56
|
+
examples?: Array<{
|
|
57
|
+
name: string;
|
|
58
|
+
description: string;
|
|
59
|
+
code: string;
|
|
60
|
+
args?: Record<string, unknown>;
|
|
61
|
+
}>;
|
|
62
|
+
|
|
63
|
+
/** Relations to other components */
|
|
64
|
+
relations?: Array<{
|
|
65
|
+
component: string;
|
|
66
|
+
relationship: 'alternative' | 'parent' | 'child' | 'sibling' | 'composition' | 'complementary' | 'used-by';
|
|
67
|
+
note: string;
|
|
68
|
+
}>;
|
|
69
|
+
|
|
70
|
+
/** AI generation contract */
|
|
71
|
+
contract?: {
|
|
72
|
+
propsSummary?: string[];
|
|
73
|
+
scenarioTags?: string[];
|
|
74
|
+
a11yRules?: string[];
|
|
75
|
+
bans?: Array<{ pattern: string; message: string }>;
|
|
76
|
+
/** Sub-component slot metadata for compound components */
|
|
77
|
+
compoundChildren?: Record<string, {
|
|
78
|
+
required?: boolean;
|
|
79
|
+
accepts?: string[];
|
|
80
|
+
description?: string;
|
|
81
|
+
}>;
|
|
82
|
+
/** Canonical JSX usage examples */
|
|
83
|
+
canonicalUsage?: string[];
|
|
84
|
+
/** Per-component performance budget override in bytes (gzipped) */
|
|
85
|
+
performanceBudget?: number;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/** AI metadata for compound component generation */
|
|
89
|
+
ai?: {
|
|
90
|
+
compositionPattern?: 'compound' | 'simple' | 'controlled' | 'wrapper';
|
|
91
|
+
subComponents?: string[];
|
|
92
|
+
requiredChildren?: string[];
|
|
93
|
+
commonPatterns?: string[];
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/** Per-component preview configuration */
|
|
97
|
+
preview?: {
|
|
98
|
+
setupModule?: string;
|
|
99
|
+
wrapperModule?: string;
|
|
100
|
+
wrapperExport?: string;
|
|
101
|
+
css?: string[];
|
|
102
|
+
theme?: 'light' | 'dark';
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/** Provenance tracking — required for verification */
|
|
106
|
+
provenance: {
|
|
107
|
+
source: 'manual' | 'extracted' | 'merged' | 'migrated';
|
|
108
|
+
verified: boolean;
|
|
109
|
+
frameworkSupport?: 'native' | 'manual-only';
|
|
110
|
+
sourceHash?: string;
|
|
111
|
+
extractedAt?: string;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/** Design token references used by this component */
|
|
115
|
+
tokens?: string[];
|
|
116
|
+
|
|
117
|
+
/** Figma mappings (same DSL as .fragment.tsx but in JSON form) */
|
|
118
|
+
figma?: {
|
|
119
|
+
nodeUrl?: string;
|
|
120
|
+
propMappings?: Record<string, {
|
|
121
|
+
type: 'string' | 'boolean' | 'enum' | 'instance' | 'children' | 'textContent';
|
|
122
|
+
figmaProperty: string;
|
|
123
|
+
values?: Record<string, string>;
|
|
124
|
+
}>;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Zod schema for validation
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
const contractPropSchema = z.object({
|
|
133
|
+
type: z.string(),
|
|
134
|
+
values: z.array(z.string()).optional(),
|
|
135
|
+
default: z.unknown().optional(),
|
|
136
|
+
description: z.string(),
|
|
137
|
+
required: z.boolean().optional(),
|
|
138
|
+
constraints: z.array(z.string()).optional(),
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const contractUsageSchema = z.object({
|
|
142
|
+
when: z.array(z.string()),
|
|
143
|
+
whenNot: z.array(z.string()),
|
|
144
|
+
guidelines: z.array(z.string()).optional(),
|
|
145
|
+
accessibility: z.array(z.string()).optional(),
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const contractExampleSchema = z.object({
|
|
149
|
+
name: z.string(),
|
|
150
|
+
description: z.string(),
|
|
151
|
+
code: z.string(),
|
|
152
|
+
args: z.record(z.string(), z.unknown()).optional(),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const contractRelationSchema = z.object({
|
|
156
|
+
component: z.string(),
|
|
157
|
+
relationship: z.enum(['alternative', 'parent', 'child', 'sibling', 'composition', 'complementary', 'used-by']),
|
|
158
|
+
note: z.string(),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const contractContractSchema = z.object({
|
|
162
|
+
propsSummary: z.array(z.string()).optional(),
|
|
163
|
+
scenarioTags: z.array(z.string()).optional(),
|
|
164
|
+
a11yRules: z.array(z.string()).optional(),
|
|
165
|
+
bans: z.array(z.object({
|
|
166
|
+
pattern: z.string(),
|
|
167
|
+
message: z.string(),
|
|
168
|
+
})).optional(),
|
|
169
|
+
compoundChildren: z.record(z.string(), z.object({
|
|
170
|
+
required: z.boolean().optional(),
|
|
171
|
+
accepts: z.array(z.string()).optional(),
|
|
172
|
+
description: z.string().optional(),
|
|
173
|
+
})).optional(),
|
|
174
|
+
canonicalUsage: z.array(z.string()).optional(),
|
|
175
|
+
performanceBudget: z.number().optional(),
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const contractAiSchema = z.object({
|
|
179
|
+
compositionPattern: z.enum(['compound', 'simple', 'controlled', 'wrapper']).optional(),
|
|
180
|
+
subComponents: z.array(z.string()).optional(),
|
|
181
|
+
requiredChildren: z.array(z.string()).optional(),
|
|
182
|
+
commonPatterns: z.array(z.string()).optional(),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const contractPreviewSchema = z.object({
|
|
186
|
+
setupModule: z.string().optional(),
|
|
187
|
+
wrapperModule: z.string().optional(),
|
|
188
|
+
wrapperExport: z.string().optional(),
|
|
189
|
+
css: z.array(z.string()).optional(),
|
|
190
|
+
theme: z.enum(['light', 'dark']).optional(),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const contractProvenanceSchema = z.object({
|
|
194
|
+
source: z.enum(['manual', 'extracted', 'merged', 'migrated']),
|
|
195
|
+
verified: z.boolean(),
|
|
196
|
+
frameworkSupport: z.enum(['native', 'manual-only']).optional(),
|
|
197
|
+
sourceHash: z.string().optional(),
|
|
198
|
+
extractedAt: z.string().optional(),
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const contractFigmaSchema = z.object({
|
|
202
|
+
nodeUrl: z.string().optional(),
|
|
203
|
+
propMappings: z.record(z.string(), z.object({
|
|
204
|
+
type: z.enum(['string', 'boolean', 'enum', 'instance', 'children', 'textContent']),
|
|
205
|
+
figmaProperty: z.string(),
|
|
206
|
+
values: z.record(z.string(), z.string()).optional(),
|
|
207
|
+
})).optional(),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
export const componentContractSchema = z.object({
|
|
211
|
+
$schema: z.string(),
|
|
212
|
+
name: z.string(),
|
|
213
|
+
description: z.string(),
|
|
214
|
+
category: z.string(),
|
|
215
|
+
tags: z.array(z.string()).optional(),
|
|
216
|
+
status: z.enum(['stable', 'beta', 'deprecated', 'experimental']).optional(),
|
|
217
|
+
framework: z.enum(['react', 'vue', 'svelte', 'web-components', 'angular']).optional(),
|
|
218
|
+
sourcePath: z.string(),
|
|
219
|
+
exportName: z.string(),
|
|
220
|
+
propsSummary: z.array(z.string()),
|
|
221
|
+
props: z.record(z.string(), contractPropSchema),
|
|
222
|
+
usage: contractUsageSchema,
|
|
223
|
+
examples: z.array(contractExampleSchema).optional(),
|
|
224
|
+
relations: z.array(contractRelationSchema).optional(),
|
|
225
|
+
contract: contractContractSchema.optional(),
|
|
226
|
+
ai: contractAiSchema.optional(),
|
|
227
|
+
preview: contractPreviewSchema.optional(),
|
|
228
|
+
provenance: contractProvenanceSchema,
|
|
229
|
+
tokens: z.array(z.string()).optional(),
|
|
230
|
+
figma: contractFigmaSchema.optional(),
|
|
231
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component discovery utilities.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from the docs app component-registry so that any consumer
|
|
5
|
+
* (govern presets, CLI tools, third-party integrations) can discover
|
|
6
|
+
* components from a module's exports without duplicating the logic.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Check if a value is likely a React component.
|
|
11
|
+
* Functions or objects with $$typeof (forwardRef, memo) qualify.
|
|
12
|
+
*/
|
|
13
|
+
export function isReactComponent(value: unknown): boolean {
|
|
14
|
+
if (!value) return false;
|
|
15
|
+
|
|
16
|
+
// Function component (most common case)
|
|
17
|
+
if (typeof value === 'function') {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// ForwardRef, memo, etc. have $$typeof
|
|
22
|
+
if (typeof value === 'object') {
|
|
23
|
+
const obj = value as Record<string, unknown>;
|
|
24
|
+
if (obj.$$typeof) return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface DiscoverComponentsOptions {
|
|
31
|
+
/** Set of export names to skip */
|
|
32
|
+
exclude?: Set<string>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Discover all components and sub-components from a module's exports.
|
|
37
|
+
* Returns a sorted array of component names including compound names (e.g. 'Card.Header').
|
|
38
|
+
*
|
|
39
|
+
* @param moduleExports - The exports object from a component library (e.g. `import * as UI from '@usefragments/ui'`)
|
|
40
|
+
* @param options - Optional configuration
|
|
41
|
+
*/
|
|
42
|
+
export function discoverComponents(
|
|
43
|
+
moduleExports: Record<string, unknown>,
|
|
44
|
+
options?: DiscoverComponentsOptions,
|
|
45
|
+
): string[] {
|
|
46
|
+
const exclude = options?.exclude;
|
|
47
|
+
const names: string[] = [];
|
|
48
|
+
|
|
49
|
+
for (const [exportName, exportValue] of Object.entries(moduleExports)) {
|
|
50
|
+
// Skip excluded exports
|
|
51
|
+
if (exclude?.has(exportName)) continue;
|
|
52
|
+
|
|
53
|
+
// Skip non-components (types, constants, etc.)
|
|
54
|
+
if (!isReactComponent(exportValue)) continue;
|
|
55
|
+
|
|
56
|
+
// Skip lowercase exports (likely utilities)
|
|
57
|
+
if (exportName[0] !== exportName[0].toUpperCase()) continue;
|
|
58
|
+
|
|
59
|
+
// Add the main component
|
|
60
|
+
names.push(exportName);
|
|
61
|
+
|
|
62
|
+
// Check for sub-components by looking at ALL properties of the component
|
|
63
|
+
const componentObj = exportValue as Record<string, unknown>;
|
|
64
|
+
|
|
65
|
+
for (const key of Object.keys(componentObj)) {
|
|
66
|
+
// Skip internal properties and non-component properties
|
|
67
|
+
if (key.startsWith('_') || key.startsWith('$')) continue;
|
|
68
|
+
if (key === 'displayName' || key === 'propTypes' || key === 'defaultProps') continue;
|
|
69
|
+
// Skip 'render' which is a forwardRef internal, and 'Tabbed' which is a special variant
|
|
70
|
+
if (key === 'render' || key === 'Tabbed') continue;
|
|
71
|
+
|
|
72
|
+
const subComponent = componentObj[key];
|
|
73
|
+
if (isReactComponent(subComponent)) {
|
|
74
|
+
names.push(`${exportName}.${key}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return names.sort();
|
|
80
|
+
}
|