@fragments-sdk/cli 0.4.4 → 0.5.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/README.md +1 -1
- package/dist/bin.js +12 -12
- package/dist/{chunk-NOTYONHY.js → chunk-2DJH4F4P.js} +2 -2
- package/dist/{chunk-5CKYLCJH.js → chunk-2H2JAA3U.js} +35 -7
- package/dist/chunk-2H2JAA3U.js.map +1 -0
- package/dist/{chunk-G3M3MPQ6.js → chunk-B2TQKOLW.js} +157 -30
- package/dist/chunk-B2TQKOLW.js.map +1 -0
- package/dist/{chunk-AW7MWOUH.js → chunk-ICAIQ57V.js} +9 -5
- package/dist/chunk-ICAIQ57V.js.map +1 -0
- package/dist/{chunk-5ZYEOHYK.js → chunk-IOJE35DZ.js} +2 -2
- package/dist/{chunk-ZFKGX3QK.js → chunk-UXRGD3DM.js} +47 -14
- package/dist/chunk-UXRGD3DM.js.map +1 -0
- package/dist/{chunk-J4SI5RIH.js → chunk-XNWDI6UT.js} +4 -4
- package/dist/{core-LNXDLXDP.js → core-NJVKKLJ4.js} +11 -3
- package/dist/{generate-OIXXHOWR.js → generate-OVGMDKCJ.js} +4 -4
- package/dist/index.d.ts +30 -4
- package/dist/index.js +6 -6
- package/dist/{init-EVPXIDW4.js → init-EOA7TTOR.js} +4 -4
- package/dist/mcp-bin.js +266 -36
- package/dist/mcp-bin.js.map +1 -1
- package/dist/scan-YN4LUDKY.js +12 -0
- package/dist/{service-K52ORLCJ.js → service-2T26CBWE.js} +4 -4
- package/dist/{static-viewer-JNQIHA4B.js → static-viewer-CLJJRYHK.js} +4 -4
- package/dist/{test-USARUEFW.js → test-ECPEXFDN.js} +3 -3
- package/dist/{tokens-C6YHBOQE.js → tokens-FHA2DO22.js} +5 -5
- package/dist/{viewer-H7TVFT4E.js → viewer-XDPD52L7.js} +13 -13
- package/package.json +1 -1
- package/src/build.ts +53 -13
- package/src/core/constants.ts +4 -1
- package/src/core/context.ts +28 -28
- package/src/core/defineSegment.ts +21 -11
- package/src/core/discovery.ts +52 -4
- package/src/core/index.ts +14 -4
- package/src/core/loader.ts +3 -0
- package/src/core/node.ts +3 -1
- package/src/core/parser.ts +1 -1
- package/src/core/schema.ts +7 -2
- package/src/core/token-parser.ts +211 -0
- package/src/core/types.ts +46 -6
- package/src/mcp/server.ts +321 -39
- package/dist/chunk-5CKYLCJH.js.map +0 -1
- package/dist/chunk-AW7MWOUH.js.map +0 -1
- package/dist/chunk-G3M3MPQ6.js.map +0 -1
- package/dist/chunk-ZFKGX3QK.js.map +0 -1
- package/dist/scan-YVYD64GD.js +0 -12
- /package/dist/{chunk-NOTYONHY.js.map → chunk-2DJH4F4P.js.map} +0 -0
- /package/dist/{chunk-5ZYEOHYK.js.map → chunk-IOJE35DZ.js.map} +0 -0
- /package/dist/{chunk-J4SI5RIH.js.map → chunk-XNWDI6UT.js.map} +0 -0
- /package/dist/{core-LNXDLXDP.js.map → core-NJVKKLJ4.js.map} +0 -0
- /package/dist/{generate-OIXXHOWR.js.map → generate-OVGMDKCJ.js.map} +0 -0
- /package/dist/{init-EVPXIDW4.js.map → init-EOA7TTOR.js.map} +0 -0
- /package/dist/{scan-YVYD64GD.js.map → scan-YN4LUDKY.js.map} +0 -0
- /package/dist/{service-K52ORLCJ.js.map → service-2T26CBWE.js.map} +0 -0
- /package/dist/{static-viewer-JNQIHA4B.js.map → static-viewer-CLJJRYHK.js.map} +0 -0
- /package/dist/{test-USARUEFW.js.map → test-ECPEXFDN.js.map} +0 -0
- /package/dist/{tokens-C6YHBOQE.js.map → tokens-FHA2DO22.js.map} +0 -0
- /package/dist/{viewer-H7TVFT4E.js.map → viewer-XDPD52L7.js.map} +0 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Parser — extracts CSS custom property declarations from SCSS/CSS files.
|
|
3
|
+
*
|
|
4
|
+
* Parses files for `--prefix-*: value;` declarations and groups them
|
|
5
|
+
* by SCSS comment sections (e.g., `// Typography`, `// Colors`).
|
|
6
|
+
* Falls back to naming-convention-based categorization when comments
|
|
7
|
+
* are absent.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface ParsedToken {
|
|
11
|
+
/** Full CSS variable name (e.g., "--fui-color-accent") */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Category inferred from SCSS comment or naming convention */
|
|
14
|
+
category: string;
|
|
15
|
+
/** Description from inline comment, if any */
|
|
16
|
+
description?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TokenParseOutput {
|
|
20
|
+
/** Detected prefix (e.g., "--fui-") */
|
|
21
|
+
prefix: string;
|
|
22
|
+
/** Tokens grouped by category */
|
|
23
|
+
categories: Record<string, ParsedToken[]>;
|
|
24
|
+
/** Total number of tokens found */
|
|
25
|
+
total: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Category inference from naming conventions.
|
|
30
|
+
* Order matters — first match wins.
|
|
31
|
+
*/
|
|
32
|
+
const NAMING_RULES: Array<{ pattern: RegExp; category: string }> = [
|
|
33
|
+
{ pattern: /--\w+-font-/, category: 'typography' },
|
|
34
|
+
{ pattern: /--\w+-line-height-/, category: 'typography' },
|
|
35
|
+
{ pattern: /--\w+-space-/, category: 'spacing' },
|
|
36
|
+
{ pattern: /--\w+-padding-/, category: 'spacing' },
|
|
37
|
+
{ pattern: /--\w+-radius-/, category: 'radius' },
|
|
38
|
+
{ pattern: /--\w+-color-/, category: 'colors' },
|
|
39
|
+
{ pattern: /--\w+-bg-/, category: 'surfaces' },
|
|
40
|
+
{ pattern: /--\w+-text-/, category: 'text' },
|
|
41
|
+
{ pattern: /--\w+-border/, category: 'borders' },
|
|
42
|
+
{ pattern: /--\w+-shadow-/, category: 'shadows' },
|
|
43
|
+
{ pattern: /--\w+-focus-/, category: 'focus' },
|
|
44
|
+
{ pattern: /--\w+-transition-/, category: 'transitions' },
|
|
45
|
+
{ pattern: /--\w+-scrollbar-/, category: 'scrollbar' },
|
|
46
|
+
{ pattern: /--\w+-z-index/, category: 'z-index' },
|
|
47
|
+
{ pattern: /--\w+-(button|input|touch)-/, category: 'component-sizing' },
|
|
48
|
+
{ pattern: /--\w+-appshell-/, category: 'layout' },
|
|
49
|
+
{ pattern: /--\w+-header-/, category: 'layout' },
|
|
50
|
+
{ pattern: /--\w+-code-/, category: 'code' },
|
|
51
|
+
{ pattern: /--\w+-tooltip-/, category: 'tooltip' },
|
|
52
|
+
{ pattern: /--\w+-hero-/, category: 'marketing' },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Infer category from a CSS variable name using naming conventions.
|
|
57
|
+
*/
|
|
58
|
+
function inferCategory(name: string): string {
|
|
59
|
+
for (const rule of NAMING_RULES) {
|
|
60
|
+
if (rule.pattern.test(name)) {
|
|
61
|
+
return rule.category;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return 'other';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Detect the most common prefix from a list of CSS variable names.
|
|
69
|
+
* E.g., given ["--fui-color-accent", "--fui-bg-primary"] → "--fui-"
|
|
70
|
+
*/
|
|
71
|
+
function detectPrefix(names: string[]): string {
|
|
72
|
+
if (names.length === 0) return '--';
|
|
73
|
+
|
|
74
|
+
// Find common prefix after "--"
|
|
75
|
+
const stripped = names.map((n) => n.slice(2)); // remove "--"
|
|
76
|
+
let prefix = '';
|
|
77
|
+
const first = stripped[0];
|
|
78
|
+
|
|
79
|
+
for (let i = 0; i < first.length; i++) {
|
|
80
|
+
const ch = first[i];
|
|
81
|
+
if (stripped.every((s) => s[i] === ch)) {
|
|
82
|
+
prefix += ch;
|
|
83
|
+
} else {
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Trim to last hyphen to get clean prefix
|
|
89
|
+
const lastHyphen = prefix.lastIndexOf('-');
|
|
90
|
+
if (lastHyphen > 0) {
|
|
91
|
+
prefix = prefix.slice(0, lastHyphen + 1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return `--${prefix}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Normalize a SCSS comment into a category name.
|
|
99
|
+
* "// Typography" → "typography"
|
|
100
|
+
* "// Component heights" → "component-sizing"
|
|
101
|
+
* "// Hero/Marketing gradient" → "marketing"
|
|
102
|
+
*/
|
|
103
|
+
function normalizeCategory(comment: string): string {
|
|
104
|
+
const text = comment
|
|
105
|
+
.trim()
|
|
106
|
+
.replace(/^\/\/\s*/, '')
|
|
107
|
+
.replace(/^\/\*+\s*/, '')
|
|
108
|
+
.replace(/\s*\*+\/$/, '')
|
|
109
|
+
.trim()
|
|
110
|
+
.toLowerCase();
|
|
111
|
+
|
|
112
|
+
// Map common comment headings to clean category names
|
|
113
|
+
const mappings: Record<string, string> = {
|
|
114
|
+
'base configuration': 'base',
|
|
115
|
+
'typography': 'typography',
|
|
116
|
+
'spacing (micro)': 'spacing',
|
|
117
|
+
'spacing': 'spacing',
|
|
118
|
+
'density padding': 'spacing',
|
|
119
|
+
'border radius': 'radius',
|
|
120
|
+
'transitions': 'transitions',
|
|
121
|
+
'colors': 'colors',
|
|
122
|
+
'surfaces': 'surfaces',
|
|
123
|
+
'text': 'text',
|
|
124
|
+
'borders': 'borders',
|
|
125
|
+
'shadows': 'shadows',
|
|
126
|
+
'focus': 'focus',
|
|
127
|
+
'scrollbar': 'scrollbar',
|
|
128
|
+
'component heights': 'component-sizing',
|
|
129
|
+
'appshell layout': 'layout',
|
|
130
|
+
'codeblock': 'code',
|
|
131
|
+
'tooltip': 'tooltip',
|
|
132
|
+
'hero/marketing gradient': 'marketing',
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return mappings[text] ?? text.replace(/\s+/g, '-');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Parse a SCSS or CSS file and extract CSS custom property declarations.
|
|
140
|
+
*
|
|
141
|
+
* Handles two grouping strategies:
|
|
142
|
+
* 1. Comment-based: Uses `// Category` comments above groups of declarations
|
|
143
|
+
* 2. Naming-based: Falls back to inferring category from variable name patterns
|
|
144
|
+
*/
|
|
145
|
+
export function parseTokenFile(content: string, filePath: string): TokenParseOutput {
|
|
146
|
+
const lines = content.split('\n');
|
|
147
|
+
const tokens: ParsedToken[] = [];
|
|
148
|
+
const seenNames = new Set<string>();
|
|
149
|
+
let currentCategory = 'other';
|
|
150
|
+
let hasCommentCategories = false;
|
|
151
|
+
|
|
152
|
+
// Regex for CSS custom property declarations
|
|
153
|
+
// Matches: --name: value; (with optional SCSS interpolation)
|
|
154
|
+
const varDeclRegex = /^\s*(--[\w-]+)\s*:/;
|
|
155
|
+
// Regex for section comments (// Category or /* Category */)
|
|
156
|
+
// Allow any characters after uppercase start (including / for "Hero/Marketing")
|
|
157
|
+
const sectionCommentRegex = /^\s*\/\/\s+([A-Z].+)$/;
|
|
158
|
+
|
|
159
|
+
for (const line of lines) {
|
|
160
|
+
// Check for section comment
|
|
161
|
+
const commentMatch = line.match(sectionCommentRegex);
|
|
162
|
+
if (commentMatch) {
|
|
163
|
+
const normalized = normalizeCategory(commentMatch[0]);
|
|
164
|
+
if (normalized) {
|
|
165
|
+
currentCategory = normalized;
|
|
166
|
+
hasCommentCategories = true;
|
|
167
|
+
}
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Check for CSS variable declaration
|
|
172
|
+
const varMatch = line.match(varDeclRegex);
|
|
173
|
+
if (varMatch) {
|
|
174
|
+
const name = varMatch[1];
|
|
175
|
+
|
|
176
|
+
// Deduplicate: keep only the first occurrence of each variable.
|
|
177
|
+
// Dark mode and high contrast blocks redefine the same variables
|
|
178
|
+
// with different values — we only want the canonical list.
|
|
179
|
+
if (seenNames.has(name)) continue;
|
|
180
|
+
seenNames.add(name);
|
|
181
|
+
|
|
182
|
+
// Extract inline comment if present
|
|
183
|
+
const inlineComment = line.match(/\/\/\s*(.+)$/);
|
|
184
|
+
const description = inlineComment ? inlineComment[1].trim() : undefined;
|
|
185
|
+
|
|
186
|
+
tokens.push({
|
|
187
|
+
name,
|
|
188
|
+
category: hasCommentCategories ? currentCategory : inferCategory(name),
|
|
189
|
+
description,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Group by category
|
|
195
|
+
const categories: Record<string, ParsedToken[]> = {};
|
|
196
|
+
for (const token of tokens) {
|
|
197
|
+
if (!categories[token.category]) {
|
|
198
|
+
categories[token.category] = [];
|
|
199
|
+
}
|
|
200
|
+
categories[token.category].push(token);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Detect prefix
|
|
204
|
+
const prefix = detectPrefix(tokens.map((t) => t.name));
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
prefix,
|
|
208
|
+
categories,
|
|
209
|
+
total: tokens.length,
|
|
210
|
+
};
|
|
211
|
+
}
|
package/src/core/types.ts
CHANGED
|
@@ -735,10 +735,10 @@ export interface CompiledSegment {
|
|
|
735
735
|
}
|
|
736
736
|
|
|
737
737
|
/**
|
|
738
|
-
*
|
|
738
|
+
* Block definition — a named composition pattern showing how
|
|
739
739
|
* design system components wire together for a common use case.
|
|
740
740
|
*/
|
|
741
|
-
export interface
|
|
741
|
+
export interface BlockDefinition {
|
|
742
742
|
name: string;
|
|
743
743
|
description: string;
|
|
744
744
|
category: string;
|
|
@@ -748,9 +748,14 @@ export interface RecipeDefinition {
|
|
|
748
748
|
}
|
|
749
749
|
|
|
750
750
|
/**
|
|
751
|
-
*
|
|
751
|
+
* @deprecated Use BlockDefinition instead
|
|
752
752
|
*/
|
|
753
|
-
export
|
|
753
|
+
export type RecipeDefinition = BlockDefinition;
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Compiled block data (JSON-serializable for AI consumption)
|
|
757
|
+
*/
|
|
758
|
+
export interface CompiledBlock {
|
|
754
759
|
filePath: string;
|
|
755
760
|
name: string;
|
|
756
761
|
description: string;
|
|
@@ -760,6 +765,33 @@ export interface CompiledRecipe {
|
|
|
760
765
|
tags?: string[];
|
|
761
766
|
}
|
|
762
767
|
|
|
768
|
+
/**
|
|
769
|
+
* @deprecated Use CompiledBlock instead
|
|
770
|
+
*/
|
|
771
|
+
export type CompiledRecipe = CompiledBlock;
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* A single token entry in the compiled output
|
|
775
|
+
*/
|
|
776
|
+
export interface CompiledTokenEntry {
|
|
777
|
+
/** CSS variable name (e.g., "--fui-color-accent") */
|
|
778
|
+
name: string;
|
|
779
|
+
/** Description from inline comment */
|
|
780
|
+
description?: string;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Compiled token data stored in fragments.json
|
|
785
|
+
*/
|
|
786
|
+
export interface CompiledTokenData {
|
|
787
|
+
/** Detected variable prefix (e.g., "--fui-") */
|
|
788
|
+
prefix: string;
|
|
789
|
+
/** Total number of tokens */
|
|
790
|
+
total: number;
|
|
791
|
+
/** Tokens grouped by category */
|
|
792
|
+
categories: Record<string, CompiledTokenEntry[]>;
|
|
793
|
+
}
|
|
794
|
+
|
|
763
795
|
/**
|
|
764
796
|
* The compiled segments.json structure
|
|
765
797
|
*/
|
|
@@ -776,6 +808,14 @@ export interface CompiledSegmentsFile {
|
|
|
776
808
|
/** All compiled segments indexed by component name */
|
|
777
809
|
segments: Record<string, CompiledSegment>;
|
|
778
810
|
|
|
779
|
-
/** All compiled
|
|
780
|
-
|
|
811
|
+
/** All compiled blocks indexed by block name */
|
|
812
|
+
blocks?: Record<string, CompiledBlock>;
|
|
813
|
+
|
|
814
|
+
/** Design tokens (CSS custom properties) extracted from style files */
|
|
815
|
+
tokens?: CompiledTokenData;
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* @deprecated Use blocks instead
|
|
819
|
+
*/
|
|
820
|
+
recipes?: Record<string, CompiledBlock>;
|
|
781
821
|
}
|