@fragments-sdk/core 0.1.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 +84 -0
- package/dist/index.d.ts +2873 -0
- package/dist/index.js +1431 -0
- package/dist/index.js.map +1 -0
- package/package.json +75 -0
- package/src/__tests__/preview-runtime.test.tsx +111 -0
- package/src/composition.test.ts +262 -0
- package/src/composition.ts +318 -0
- package/src/constants.ts +114 -0
- package/src/context.ts +2 -0
- package/src/defineFragment.ts +141 -0
- package/src/figma.ts +263 -0
- package/src/fragment-types.ts +214 -0
- package/src/index.ts +207 -0
- package/src/performance-presets.ts +142 -0
- package/src/preview-runtime.tsx +144 -0
- package/src/schema.ts +229 -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/token-parser.ts +321 -0
- package/src/token-types.ts +287 -0
- package/src/types.ts +784 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { FragmentDefinition, CompiledFragment, FragmentComponent, BlockDefinition, CompiledBlock } from './types.js';
|
|
2
|
+
import { fragmentDefinitionSchema, blockDefinitionSchema } from './schema.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Define a fragment for a component.
|
|
6
|
+
*
|
|
7
|
+
* This is the main API for creating fragment documentation.
|
|
8
|
+
* It provides runtime validation and type safety.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { defineFragment } from '@fragments-sdk/cli/core';
|
|
13
|
+
* import { Button } from './Button';
|
|
14
|
+
*
|
|
15
|
+
* export default defineFragment({
|
|
16
|
+
* component: Button,
|
|
17
|
+
* meta: {
|
|
18
|
+
* name: 'Button',
|
|
19
|
+
* description: 'Primary action trigger',
|
|
20
|
+
* category: 'actions',
|
|
21
|
+
* },
|
|
22
|
+
* usage: {
|
|
23
|
+
* when: ['User needs to trigger an action'],
|
|
24
|
+
* whenNot: ['Navigation without side effects'],
|
|
25
|
+
* },
|
|
26
|
+
* props: {
|
|
27
|
+
* variant: {
|
|
28
|
+
* type: 'enum',
|
|
29
|
+
* values: ['primary', 'secondary'],
|
|
30
|
+
* default: 'primary',
|
|
31
|
+
* description: 'Visual style',
|
|
32
|
+
* },
|
|
33
|
+
* },
|
|
34
|
+
* variants: [
|
|
35
|
+
* {
|
|
36
|
+
* name: 'Default',
|
|
37
|
+
* description: 'Default button',
|
|
38
|
+
* render: () => <Button>Click me</Button>,
|
|
39
|
+
* },
|
|
40
|
+
* ],
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function defineFragment<TProps>(
|
|
45
|
+
definition: FragmentDefinition<TProps>
|
|
46
|
+
): FragmentDefinition<TProps> {
|
|
47
|
+
// Validate at runtime in development
|
|
48
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
49
|
+
const result = fragmentDefinitionSchema.safeParse(definition);
|
|
50
|
+
if (!result.success) {
|
|
51
|
+
const errors = result.error.errors
|
|
52
|
+
.map((e) => ` - ${e.path.join('.')}: ${e.message}`)
|
|
53
|
+
.join('\n');
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Invalid fragment definition for "${definition.meta?.name || 'unknown'}":\n${errors}`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return definition;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Compile a fragment definition to JSON-serializable format.
|
|
65
|
+
* Used for generating fragments.json for AI consumption.
|
|
66
|
+
*/
|
|
67
|
+
export function compileFragment(
|
|
68
|
+
definition: FragmentDefinition,
|
|
69
|
+
filePath: string
|
|
70
|
+
): CompiledFragment {
|
|
71
|
+
return {
|
|
72
|
+
filePath,
|
|
73
|
+
meta: definition.meta,
|
|
74
|
+
usage: definition.usage,
|
|
75
|
+
props: definition.props,
|
|
76
|
+
relations: definition.relations,
|
|
77
|
+
variants: definition.variants.map((v) => ({
|
|
78
|
+
name: v.name,
|
|
79
|
+
description: v.description,
|
|
80
|
+
code: v.code,
|
|
81
|
+
figma: v.figma,
|
|
82
|
+
})),
|
|
83
|
+
contract: definition.contract,
|
|
84
|
+
_generated: definition._generated,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Define a composition block.
|
|
90
|
+
*
|
|
91
|
+
* Blocks are pure data describing how design system components
|
|
92
|
+
* wire together for common use cases.
|
|
93
|
+
*/
|
|
94
|
+
export function defineBlock(definition: BlockDefinition): BlockDefinition {
|
|
95
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
96
|
+
const result = blockDefinitionSchema.safeParse(definition);
|
|
97
|
+
if (!result.success) {
|
|
98
|
+
const errors = result.error.errors
|
|
99
|
+
.map((e) => ` - ${e.path.join('.')}: ${e.message}`)
|
|
100
|
+
.join('\n');
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Invalid block definition for "${definition.name || 'unknown'}":\n${errors}`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return definition;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @deprecated Use defineBlock instead
|
|
112
|
+
*/
|
|
113
|
+
export const defineRecipe = defineBlock;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Compile a block definition to JSON-serializable format.
|
|
117
|
+
*/
|
|
118
|
+
export function compileBlock(
|
|
119
|
+
definition: BlockDefinition,
|
|
120
|
+
filePath: string
|
|
121
|
+
): CompiledBlock {
|
|
122
|
+
return {
|
|
123
|
+
filePath,
|
|
124
|
+
name: definition.name,
|
|
125
|
+
description: definition.description,
|
|
126
|
+
category: definition.category,
|
|
127
|
+
components: definition.components,
|
|
128
|
+
code: definition.code,
|
|
129
|
+
tags: definition.tags,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @deprecated Use compileBlock instead
|
|
135
|
+
*/
|
|
136
|
+
export const compileRecipe = compileBlock;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Type helper for extracting props type from a component
|
|
140
|
+
*/
|
|
141
|
+
export type InferProps<T> = T extends FragmentComponent<infer P> ? P : never;
|
package/src/figma.ts
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Figma property mapping DSL
|
|
3
|
+
*
|
|
4
|
+
* Provides helpers for mapping Figma component properties to code props.
|
|
5
|
+
* Inspired by Figma Code Connect's API.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { defineFragment, figma } from '@fragments-sdk/cli/core';
|
|
10
|
+
*
|
|
11
|
+
* export default defineFragment({
|
|
12
|
+
* component: Button,
|
|
13
|
+
* meta: {
|
|
14
|
+
* name: 'Button',
|
|
15
|
+
* description: 'Primary action trigger',
|
|
16
|
+
* category: 'actions',
|
|
17
|
+
* figma: 'https://figma.com/file/abc/Design?node-id=1-2',
|
|
18
|
+
* figmaProps: {
|
|
19
|
+
* children: figma.string('Label'),
|
|
20
|
+
* disabled: figma.boolean('Disabled'),
|
|
21
|
+
* variant: figma.enum('Type', {
|
|
22
|
+
* 'Primary': 'primary',
|
|
23
|
+
* 'Secondary': 'secondary',
|
|
24
|
+
* }),
|
|
25
|
+
* },
|
|
26
|
+
* },
|
|
27
|
+
* // ...
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import type {
|
|
33
|
+
FigmaStringMapping,
|
|
34
|
+
FigmaBooleanMapping,
|
|
35
|
+
FigmaEnumMapping,
|
|
36
|
+
FigmaInstanceMapping,
|
|
37
|
+
FigmaChildrenMapping,
|
|
38
|
+
FigmaTextContentMapping,
|
|
39
|
+
} from './types.js';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Map a Figma text property to a string prop.
|
|
43
|
+
*
|
|
44
|
+
* @param figmaProperty - The name of the text property in Figma
|
|
45
|
+
* @returns A string mapping descriptor
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```tsx
|
|
49
|
+
* figmaProps: {
|
|
50
|
+
* label: figma.string('Button Text'),
|
|
51
|
+
* placeholder: figma.string('Placeholder'),
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
function string(figmaProperty: string): FigmaStringMapping {
|
|
56
|
+
return {
|
|
57
|
+
__type: 'figma-string',
|
|
58
|
+
figmaProperty,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Map a Figma boolean property to a boolean prop.
|
|
64
|
+
* Optionally map true/false to different values.
|
|
65
|
+
*
|
|
66
|
+
* @param figmaProperty - The name of the boolean property in Figma
|
|
67
|
+
* @param valueMapping - Optional mapping of true/false to other values
|
|
68
|
+
* @returns A boolean mapping descriptor
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```tsx
|
|
72
|
+
* figmaProps: {
|
|
73
|
+
* disabled: figma.boolean('Disabled'),
|
|
74
|
+
* // Map boolean to string values
|
|
75
|
+
* size: figma.boolean('Large', { true: 'lg', false: 'md' }),
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
function boolean(
|
|
80
|
+
figmaProperty: string,
|
|
81
|
+
valueMapping?: { true: unknown; false: unknown }
|
|
82
|
+
): FigmaBooleanMapping {
|
|
83
|
+
return {
|
|
84
|
+
__type: 'figma-boolean',
|
|
85
|
+
figmaProperty,
|
|
86
|
+
valueMapping,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Map a Figma variant property to an enum prop.
|
|
92
|
+
*
|
|
93
|
+
* @param figmaProperty - The name of the variant property in Figma
|
|
94
|
+
* @param valueMapping - Mapping of Figma values to code values
|
|
95
|
+
* @returns An enum mapping descriptor
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```tsx
|
|
99
|
+
* figmaProps: {
|
|
100
|
+
* variant: figma.enum('Type', {
|
|
101
|
+
* 'Primary': 'primary',
|
|
102
|
+
* 'Secondary': 'secondary',
|
|
103
|
+
* 'Outline': 'outline',
|
|
104
|
+
* }),
|
|
105
|
+
* size: figma.enum('Size', {
|
|
106
|
+
* 'Small': 'sm',
|
|
107
|
+
* 'Medium': 'md',
|
|
108
|
+
* 'Large': 'lg',
|
|
109
|
+
* }),
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
function enumValue<T extends Record<string, unknown>>(
|
|
114
|
+
figmaProperty: string,
|
|
115
|
+
valueMapping: T
|
|
116
|
+
): FigmaEnumMapping {
|
|
117
|
+
return {
|
|
118
|
+
__type: 'figma-enum',
|
|
119
|
+
figmaProperty,
|
|
120
|
+
valueMapping,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Reference a nested Figma component instance.
|
|
126
|
+
* Use this when a prop accepts a component that's represented
|
|
127
|
+
* as an instance swap in Figma.
|
|
128
|
+
*
|
|
129
|
+
* @param figmaProperty - The name of the instance property in Figma
|
|
130
|
+
* @returns An instance mapping descriptor
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```tsx
|
|
134
|
+
* figmaProps: {
|
|
135
|
+
* icon: figma.instance('Icon'),
|
|
136
|
+
* avatar: figma.instance('Avatar'),
|
|
137
|
+
* }
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
function instance(figmaProperty: string): FigmaInstanceMapping {
|
|
141
|
+
return {
|
|
142
|
+
__type: 'figma-instance',
|
|
143
|
+
figmaProperty,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Render children from specific Figma layers.
|
|
149
|
+
* Use this when children are represented as named layers in Figma.
|
|
150
|
+
*
|
|
151
|
+
* @param layers - Array of layer names to include as children
|
|
152
|
+
* @returns A children mapping descriptor
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```tsx
|
|
156
|
+
* figmaProps: {
|
|
157
|
+
* children: figma.children(['Title', 'Description', 'Actions']),
|
|
158
|
+
* }
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
function children(layers: string[]): FigmaChildrenMapping {
|
|
162
|
+
return {
|
|
163
|
+
__type: 'figma-children',
|
|
164
|
+
layers,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Extract text content from a Figma text layer.
|
|
170
|
+
* Use this when a prop should be the actual text from a layer.
|
|
171
|
+
*
|
|
172
|
+
* @param layer - The name of the text layer in Figma
|
|
173
|
+
* @returns A text content mapping descriptor
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```tsx
|
|
177
|
+
* figmaProps: {
|
|
178
|
+
* title: figma.textContent('Header Text'),
|
|
179
|
+
* description: figma.textContent('Body Text'),
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
function textContent(layer: string): FigmaTextContentMapping {
|
|
184
|
+
return {
|
|
185
|
+
__type: 'figma-text-content',
|
|
186
|
+
layer,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Figma property mapping helpers.
|
|
192
|
+
*
|
|
193
|
+
* Use these to define how Figma properties map to your component props.
|
|
194
|
+
* The mappings are used for:
|
|
195
|
+
* - Generating accurate code snippets in Figma Dev Mode
|
|
196
|
+
* - AI agents understanding the design-to-code relationship
|
|
197
|
+
* - Automated design verification
|
|
198
|
+
*/
|
|
199
|
+
export const figma = {
|
|
200
|
+
string,
|
|
201
|
+
boolean,
|
|
202
|
+
enum: enumValue,
|
|
203
|
+
instance,
|
|
204
|
+
children,
|
|
205
|
+
textContent,
|
|
206
|
+
} as const;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Helper type to check if a value is a Figma prop mapping
|
|
210
|
+
*/
|
|
211
|
+
export function isFigmaPropMapping(
|
|
212
|
+
value: unknown
|
|
213
|
+
): value is FigmaStringMapping | FigmaBooleanMapping | FigmaEnumMapping | FigmaInstanceMapping | FigmaChildrenMapping | FigmaTextContentMapping {
|
|
214
|
+
if (typeof value !== 'object' || value === null || !('__type' in value)) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
const typeValue = (value as Record<string, unknown>).__type;
|
|
218
|
+
return typeof typeValue === 'string' && typeValue.startsWith('figma-');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Resolve a Figma prop mapping to an actual value given Figma property values.
|
|
223
|
+
*
|
|
224
|
+
* @param mapping - The Figma prop mapping
|
|
225
|
+
* @param figmaValues - Object containing Figma property values
|
|
226
|
+
* @returns The resolved value for the code prop
|
|
227
|
+
*/
|
|
228
|
+
export function resolveFigmaMapping(
|
|
229
|
+
mapping: FigmaStringMapping | FigmaBooleanMapping | FigmaEnumMapping | FigmaInstanceMapping | FigmaChildrenMapping | FigmaTextContentMapping,
|
|
230
|
+
figmaValues: Record<string, unknown>
|
|
231
|
+
): unknown {
|
|
232
|
+
switch (mapping.__type) {
|
|
233
|
+
case 'figma-string':
|
|
234
|
+
return figmaValues[mapping.figmaProperty] ?? '';
|
|
235
|
+
|
|
236
|
+
case 'figma-boolean': {
|
|
237
|
+
const boolValue = figmaValues[mapping.figmaProperty] as boolean;
|
|
238
|
+
if (mapping.valueMapping) {
|
|
239
|
+
return boolValue ? mapping.valueMapping.true : mapping.valueMapping.false;
|
|
240
|
+
}
|
|
241
|
+
return boolValue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
case 'figma-enum': {
|
|
245
|
+
const enumKey = figmaValues[mapping.figmaProperty] as string;
|
|
246
|
+
return mapping.valueMapping[enumKey] ?? enumKey;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
case 'figma-instance':
|
|
250
|
+
// Instance mappings return the instance reference
|
|
251
|
+
return figmaValues[mapping.figmaProperty];
|
|
252
|
+
|
|
253
|
+
case 'figma-children':
|
|
254
|
+
// Children mappings return array of layer contents
|
|
255
|
+
return mapping.layers.map((layer) => figmaValues[layer]);
|
|
256
|
+
|
|
257
|
+
case 'figma-text-content':
|
|
258
|
+
return figmaValues[mapping.layer] ?? '';
|
|
259
|
+
|
|
260
|
+
default:
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript types for Fragment JSON files.
|
|
3
|
+
* These types correspond to the JSON schemas in ./schema/
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Figma design links and mappings
|
|
8
|
+
*/
|
|
9
|
+
export interface FragmentFigma {
|
|
10
|
+
/** Figma file URL */
|
|
11
|
+
file?: string;
|
|
12
|
+
/** Default Figma node ID for this component */
|
|
13
|
+
nodeId?: string;
|
|
14
|
+
/** Mapping of variant names to Figma node IDs */
|
|
15
|
+
variants?: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Anti-pattern with optional alternative
|
|
20
|
+
*/
|
|
21
|
+
export interface FragmentDoNotItem {
|
|
22
|
+
/** What not to do */
|
|
23
|
+
text: string;
|
|
24
|
+
/** Component name to use instead */
|
|
25
|
+
instead?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Usage pattern with code example
|
|
30
|
+
*/
|
|
31
|
+
export interface FragmentPattern {
|
|
32
|
+
/** Pattern name */
|
|
33
|
+
name: string;
|
|
34
|
+
/** Code example */
|
|
35
|
+
code: string;
|
|
36
|
+
/** When to use this pattern */
|
|
37
|
+
description?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Usage guidelines for AI agents and developers
|
|
42
|
+
*/
|
|
43
|
+
export interface FragmentUsage {
|
|
44
|
+
/** Scenarios when this component should be used */
|
|
45
|
+
when?: string[];
|
|
46
|
+
/** Anti-patterns and what to use instead */
|
|
47
|
+
doNot?: (string | FragmentDoNotItem)[];
|
|
48
|
+
/** Common usage patterns with code examples */
|
|
49
|
+
patterns?: FragmentPattern[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Accessibility requirements and guidelines
|
|
54
|
+
*/
|
|
55
|
+
export interface FragmentAccessibility {
|
|
56
|
+
/** ARIA role this component implements */
|
|
57
|
+
role?: string;
|
|
58
|
+
/** Accessibility requirements */
|
|
59
|
+
requirements?: string[];
|
|
60
|
+
/** Keyboard interaction patterns (key -> description) */
|
|
61
|
+
keyboard?: Record<string, string>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Relationships to other components
|
|
66
|
+
*/
|
|
67
|
+
export interface FragmentRelated {
|
|
68
|
+
/** Similar components that might be alternatives */
|
|
69
|
+
similar?: string[];
|
|
70
|
+
/** Components commonly used together with this one */
|
|
71
|
+
composedWith?: string[];
|
|
72
|
+
/** Parent components or patterns where this is commonly used */
|
|
73
|
+
usedIn?: string[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Administrative metadata
|
|
78
|
+
*/
|
|
79
|
+
export interface FragmentMeta {
|
|
80
|
+
/** Team or person responsible for this component */
|
|
81
|
+
owner?: string;
|
|
82
|
+
/** Component lifecycle status */
|
|
83
|
+
status?: "draft" | "experimental" | "beta" | "stable" | "deprecated";
|
|
84
|
+
/** Version when this component was introduced */
|
|
85
|
+
since?: string;
|
|
86
|
+
/** Version when this component was deprecated */
|
|
87
|
+
deprecatedSince?: string;
|
|
88
|
+
/** Why this component was deprecated and what to use instead */
|
|
89
|
+
deprecatedReason?: string;
|
|
90
|
+
/** Tags for categorization and search */
|
|
91
|
+
tags?: string[];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Fragment JSON file structure (.fragment.json)
|
|
96
|
+
* Contains enrichment metadata for a component
|
|
97
|
+
*/
|
|
98
|
+
export interface Fragment {
|
|
99
|
+
/** JSON Schema reference */
|
|
100
|
+
$schema?: string;
|
|
101
|
+
/** Component name (must match the component export name) */
|
|
102
|
+
name: string;
|
|
103
|
+
/** Brief description of the component's purpose */
|
|
104
|
+
description?: string;
|
|
105
|
+
/** Figma design links and mappings */
|
|
106
|
+
figma?: FragmentFigma;
|
|
107
|
+
/** Usage guidelines for AI agents and developers */
|
|
108
|
+
usage?: FragmentUsage;
|
|
109
|
+
/** Accessibility requirements and guidelines */
|
|
110
|
+
accessibility?: FragmentAccessibility;
|
|
111
|
+
/** Relationships to other components */
|
|
112
|
+
related?: FragmentRelated;
|
|
113
|
+
/** Administrative metadata */
|
|
114
|
+
meta?: FragmentMeta;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Prop entry in the registry
|
|
119
|
+
*/
|
|
120
|
+
export interface RegistryPropEntry {
|
|
121
|
+
/** TypeScript type (e.g., 'string', 'boolean', enum values) */
|
|
122
|
+
type?: string;
|
|
123
|
+
/** Simplified type category */
|
|
124
|
+
typeKind?: "string" | "number" | "boolean" | "enum" | "object" | "array" | "function" | "node" | "element" | "union" | "unknown";
|
|
125
|
+
/** For enum types, the allowed values */
|
|
126
|
+
options?: string[];
|
|
127
|
+
/** Default value if specified */
|
|
128
|
+
default?: unknown;
|
|
129
|
+
/** Whether this prop is required */
|
|
130
|
+
required?: boolean;
|
|
131
|
+
/** Prop description from JSDoc or TypeScript */
|
|
132
|
+
description?: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Component entry in the registry (simplified - focuses on paths and enrichment)
|
|
137
|
+
*/
|
|
138
|
+
export interface RegistryComponentEntry {
|
|
139
|
+
/** Relative path to the component source file */
|
|
140
|
+
path: string;
|
|
141
|
+
/** Relative path to the .fragment.json file (if exists) */
|
|
142
|
+
fragmentPath?: string;
|
|
143
|
+
/** Relative path to the .stories.tsx file (if exists) */
|
|
144
|
+
storyPath?: string;
|
|
145
|
+
/** Component category (inferred from directory or fragment) */
|
|
146
|
+
category?: string;
|
|
147
|
+
/** Component lifecycle status (from fragment) */
|
|
148
|
+
status?: "draft" | "experimental" | "beta" | "stable" | "deprecated";
|
|
149
|
+
/** Component description (from fragment or JSDoc) */
|
|
150
|
+
description?: string;
|
|
151
|
+
/** Has human-authored enrichment (fragment file exists with content beyond skeleton) */
|
|
152
|
+
hasEnrichment?: boolean;
|
|
153
|
+
/** Extracted prop definitions - only included if config.registry.includeProps is true */
|
|
154
|
+
props?: Record<string, RegistryPropEntry>;
|
|
155
|
+
/** Named exports from the component file */
|
|
156
|
+
exports?: string[];
|
|
157
|
+
/** Component dependencies (other components used) */
|
|
158
|
+
dependencies?: string[];
|
|
159
|
+
/** Merged fragment enrichment data - only included if config.registry.embedFragments is true */
|
|
160
|
+
fragment?: Fragment;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Minimal component index (.fragments/index.json)
|
|
165
|
+
* Ultra-light name → path mapping for quick lookups
|
|
166
|
+
*/
|
|
167
|
+
export interface FragmentIndex {
|
|
168
|
+
/** Schema version */
|
|
169
|
+
version: string;
|
|
170
|
+
/** When this index was generated */
|
|
171
|
+
generatedAt: string;
|
|
172
|
+
/** Simple name → path mapping */
|
|
173
|
+
components: Record<string, string>;
|
|
174
|
+
/** Categories for grouping */
|
|
175
|
+
categories?: Record<string, string[]>;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Registry file structure (.fragments/registry.json)
|
|
180
|
+
* Component index with resolved paths and optional metadata
|
|
181
|
+
*/
|
|
182
|
+
export interface FragmentRegistry {
|
|
183
|
+
/** JSON Schema reference */
|
|
184
|
+
$schema?: string;
|
|
185
|
+
/** Schema version */
|
|
186
|
+
version: string;
|
|
187
|
+
/** When this registry was generated */
|
|
188
|
+
generatedAt: string;
|
|
189
|
+
/** Component count for quick reference */
|
|
190
|
+
componentCount: number;
|
|
191
|
+
/** Component index keyed by component name */
|
|
192
|
+
components: Record<string, RegistryComponentEntry>;
|
|
193
|
+
/** Components grouped by category */
|
|
194
|
+
categories?: Record<string, string[]>;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Context file options for generation
|
|
199
|
+
*/
|
|
200
|
+
export interface FragmentContextOptions {
|
|
201
|
+
/** Output format */
|
|
202
|
+
format?: "markdown" | "json";
|
|
203
|
+
/** Compact mode - minimal output for token efficiency */
|
|
204
|
+
compact?: boolean;
|
|
205
|
+
/** What to include in the output */
|
|
206
|
+
include?: {
|
|
207
|
+
/** Include prop details (default: true) */
|
|
208
|
+
props?: boolean;
|
|
209
|
+
/** Include code examples (default: false) */
|
|
210
|
+
code?: boolean;
|
|
211
|
+
/** Include related components (default: true) */
|
|
212
|
+
relations?: boolean;
|
|
213
|
+
};
|
|
214
|
+
}
|