@spaced-out/ui-design-system 0.5.18 ā 0.5.20
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/.cspell/custom-words.txt +2 -0
- package/.github/workflows/publish-mcp.yml +81 -0
- package/CHANGELOG.md +16 -0
- package/COMPONENT_PROMPT_TEMPLATE.md +223 -0
- package/lib/components/Input/Input.d.ts +2 -0
- package/lib/components/Input/Input.d.ts.map +1 -1
- package/lib/components/Input/Input.js +37 -16
- package/lib/components/Input/Input.module.css +19 -0
- package/lib/components/PromptChip/PromptChip.d.ts +1 -0
- package/lib/components/PromptChip/PromptChip.d.ts.map +1 -1
- package/lib/components/PromptChip/PromptChip.js +14 -12
- package/lib/components/PromptChip/PromptChip.module.css +69 -37
- package/lib/components/TemplateCard/TemplateCard.d.ts +29 -0
- package/lib/components/TemplateCard/TemplateCard.d.ts.map +1 -0
- package/lib/components/TemplateCard/TemplateCard.js +92 -0
- package/lib/components/TemplateCard/TemplateCard.module.css +170 -0
- package/lib/components/TemplateCard/index.d.ts +2 -0
- package/lib/components/TemplateCard/index.d.ts.map +1 -0
- package/lib/components/TemplateCard/index.js +16 -0
- package/lib/components/index.d.ts +1 -0
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/index.js +11 -0
- package/mcp/README.md +306 -0
- package/mcp/build-mcp-data.js +247 -0
- package/mcp/index.js +1239 -0
- package/mcp/package.json +43 -0
- package/mcp/test-server.js +65 -0
- package/package.json +1 -1
package/mcp/README.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# Genesis UI Design System MCP Server
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server that provides AI assistants (Claude, Cursor, etc.) with access to the Genesis UI Design System.
|
|
4
|
+
|
|
5
|
+
## ⨠Features
|
|
6
|
+
|
|
7
|
+
- š¦ **Component Discovery**: List and search all available components
|
|
8
|
+
- šØ **Design Tokens**: Access colors, spacing, typography, shadows, and more
|
|
9
|
+
- š **Documentation**: Browse component stories and TypeScript definitions
|
|
10
|
+
- š **Dependency Analysis**: Understand component dependencies
|
|
11
|
+
- š **Onboarding Templates**: Get starter templates for new components
|
|
12
|
+
- šŖ **Hooks Information**: Query available React hooks
|
|
13
|
+
|
|
14
|
+
## šÆ No Local Dependencies Required!
|
|
15
|
+
|
|
16
|
+
Unlike traditional MCP servers that require a local copy of the design system, this server **bundles all data at build time**. Users only need to run `npx` - no cloning, no environment variables!
|
|
17
|
+
|
|
18
|
+
## š¦ Installation for Users
|
|
19
|
+
|
|
20
|
+
### With Cursor
|
|
21
|
+
|
|
22
|
+
Add to your Cursor MCP settings:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"genesis-design-system": {
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["-y", "@spaced-out/genesis-mcp-server@latest"]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### With Claude Desktop
|
|
36
|
+
|
|
37
|
+
Add to your Claude config file:
|
|
38
|
+
|
|
39
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
40
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
41
|
+
**Linux**: `~/.config/Claude/claude_desktop_config.json`
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"genesis-design-system": {
|
|
47
|
+
"command": "npx",
|
|
48
|
+
"args": ["-y", "@spaced-out/genesis-mcp-server@latest"]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then restart Cursor or Claude Desktop.
|
|
55
|
+
|
|
56
|
+
## š¬ Usage Examples
|
|
57
|
+
|
|
58
|
+
Once configured, you can ask:
|
|
59
|
+
|
|
60
|
+
**Component Discovery:**
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
"List all components in Genesis"
|
|
64
|
+
"Search for dropdown components"
|
|
65
|
+
"Show me the Button component implementation"
|
|
66
|
+
"What types does the Icon component export?"
|
|
67
|
+
"Show me the Icon component with its exported types"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Design Tokens:**
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
"Show me all color tokens"
|
|
74
|
+
"What spacing tokens are available?"
|
|
75
|
+
"List all shadow/elevation tokens"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Component Onboarding:**
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
"I want to create a new Toast component, show me the template"
|
|
82
|
+
"Help me onboard an Alert component"
|
|
83
|
+
"What's the standard structure for a Genesis component?"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Design Token Imports:**
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
"How do I import design tokens in CSS Module files?"
|
|
90
|
+
"Show me the correct way to import color and spacing tokens"
|
|
91
|
+
"What token files are available and how do I import them?"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**CSS Module Guidelines:**
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
"Show me CSS Module styling guidelines for Genesis"
|
|
98
|
+
"What are the class naming conventions for CSS Modules?"
|
|
99
|
+
"How should I style child elements in CSS Modules?"
|
|
100
|
+
"What's the correct pattern for state-based styling in CSS?"
|
|
101
|
+
"Show me common CSS mistakes to avoid"
|
|
102
|
+
"How do I apply colors to child elements like text, icons, or buttons?"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Dependencies:**
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
"What components does Modal depend on?"
|
|
109
|
+
"Show me the dependencies of Dropdown"
|
|
110
|
+
"What hooks does the Table component use?"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## š§ Development
|
|
114
|
+
|
|
115
|
+
### Building the Data
|
|
116
|
+
|
|
117
|
+
This server extracts design system metadata at build time. To build:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Install dependencies
|
|
121
|
+
yarn install
|
|
122
|
+
|
|
123
|
+
# Build the data bundle
|
|
124
|
+
yarn build
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This creates `data/design-system.json` with all component, hook, and token information.
|
|
128
|
+
|
|
129
|
+
### Testing Locally
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# After building, test the server
|
|
133
|
+
node index.js
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Or test with MCP Inspector:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npx @modelcontextprotocol/inspector node index.js
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Publishing
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# The prepublishOnly script runs yarn build automatically
|
|
146
|
+
yarn publish
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## š How It Works
|
|
150
|
+
|
|
151
|
+
### Build Time (CI/CD)
|
|
152
|
+
|
|
153
|
+
1. `build-mcp-data.js` scans the design system:
|
|
154
|
+
|
|
155
|
+
- Reads all components from `src/components/`
|
|
156
|
+
- Reads all hooks from `src/hooks/`
|
|
157
|
+
- Reads all design tokens from `design-tokens/`
|
|
158
|
+
|
|
159
|
+
2. Extracts file contents and metadata
|
|
160
|
+
|
|
161
|
+
3. Bundles everything into `data/design-system.json`
|
|
162
|
+
|
|
163
|
+
4. Package is published to npm with bundled data
|
|
164
|
+
|
|
165
|
+
### Runtime (User's Machine)
|
|
166
|
+
|
|
167
|
+
1. User runs `npx @spaced-out/genesis-mcp-server`
|
|
168
|
+
|
|
169
|
+
2. Server loads pre-bundled `data/design-system.json`
|
|
170
|
+
|
|
171
|
+
3. Serves data via MCP protocol (stdio)
|
|
172
|
+
|
|
173
|
+
4. AI assistant queries the server for design system info
|
|
174
|
+
|
|
175
|
+
**Result:** No local design system needed! āØ
|
|
176
|
+
|
|
177
|
+
## šļø Architecture
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
ui-design-system/
|
|
181
|
+
āāā src/
|
|
182
|
+
ā āāā components/ # Source components
|
|
183
|
+
ā āāā hooks/ # Source hooks
|
|
184
|
+
āāā design-tokens/ # Source tokens
|
|
185
|
+
āāā mcp/ # š MCP Server
|
|
186
|
+
āāā index.js # MCP server (reads from data/)
|
|
187
|
+
āāā build-mcp-data.js # Build script (extracts from ../)
|
|
188
|
+
āāā data/
|
|
189
|
+
ā āāā design-system.json # Bundled data (git-ignored)
|
|
190
|
+
āāā package.json
|
|
191
|
+
āāā README.md
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## š Available Tools
|
|
195
|
+
|
|
196
|
+
The MCP server provides these tools to AI assistants:
|
|
197
|
+
|
|
198
|
+
- `list_components` - List all available components
|
|
199
|
+
- `get_component` - Get detailed component information **including exported types** (e.g., IconType, IconSize from Icon component)
|
|
200
|
+
- `search_components` - Search components by name
|
|
201
|
+
- `list_hooks` - List all available hooks
|
|
202
|
+
- `get_hook` - Get detailed hook information
|
|
203
|
+
- `get_design_tokens` - Get all or filtered design tokens
|
|
204
|
+
- `get_component_template` - Get template for new components
|
|
205
|
+
- `get_design_token_import_guidelines` - Get guidelines for importing design tokens in CSS Module files with correct paths and examples
|
|
206
|
+
- `get_css_module_guidelines` - **NEW!** Get comprehensive CSS Module styling guidelines including class naming conventions (BEM patterns), token usage, icon color patterns, and common mistakes to avoid
|
|
207
|
+
- `analyze_component_dependencies` - Analyze component dependencies
|
|
208
|
+
|
|
209
|
+
## š CI/CD Integration
|
|
210
|
+
|
|
211
|
+
### Automatic Publishing
|
|
212
|
+
|
|
213
|
+
The MCP server is automatically published to npm via GitHub Actions (`.github/workflows/publish-mcp.yml`).
|
|
214
|
+
|
|
215
|
+
**Triggers:**
|
|
216
|
+
|
|
217
|
+
- Push to `master` branch when files change in:
|
|
218
|
+
- `src/**` (component/hook changes)
|
|
219
|
+
- `design-tokens/**` (token changes)
|
|
220
|
+
- `mcp/**` (MCP server changes)
|
|
221
|
+
- Manual workflow dispatch
|
|
222
|
+
|
|
223
|
+
**Process:**
|
|
224
|
+
|
|
225
|
+
1. **Auto-version bump**: If `src/` or `design-tokens/` changed, automatically bumps patch version
|
|
226
|
+
2. **Build**: Generates fresh MCP data bundle with latest design system changes
|
|
227
|
+
3. **Commit**: Pushes version bump back to master (with `[skip ci]` to avoid loops)
|
|
228
|
+
4. **Publish**: Publishes new version to npm
|
|
229
|
+
|
|
230
|
+
**What this means for you:**
|
|
231
|
+
|
|
232
|
+
ā
Update a component ā Merge to master ā New MCP version automatically published!
|
|
233
|
+
|
|
234
|
+
No need to manually bump versions when changing design system files. The workflow handles it for you.
|
|
235
|
+
|
|
236
|
+
### Version Management
|
|
237
|
+
|
|
238
|
+
**Automatic (recommended):**
|
|
239
|
+
|
|
240
|
+
- Changes to `src/` or `design-tokens/` ā patch version bumped automatically
|
|
241
|
+
- E.g., `1.0.5` ā `1.0.6`
|
|
242
|
+
|
|
243
|
+
**Manual (for major/minor releases):**
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
cd mcp
|
|
247
|
+
yarn version --minor # or --major
|
|
248
|
+
git push --follow-tags
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Manual MCP-only changes:**
|
|
252
|
+
|
|
253
|
+
- If you only change files in `mcp/`, manually bump the version to publish
|
|
254
|
+
|
|
255
|
+
## š Data Size
|
|
256
|
+
|
|
257
|
+
The bundled JSON includes:
|
|
258
|
+
|
|
259
|
+
- Full TypeScript component implementations
|
|
260
|
+
- Storybook stories
|
|
261
|
+
- CSS modules
|
|
262
|
+
- Design tokens
|
|
263
|
+
- Hook implementations
|
|
264
|
+
|
|
265
|
+
Typical size: 5-15 MB (cached by npm, so only downloaded once)
|
|
266
|
+
|
|
267
|
+
## š Private Packages
|
|
268
|
+
|
|
269
|
+
If publishing to a private npm registry:
|
|
270
|
+
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"publishConfig": {
|
|
274
|
+
"registry": "https://your-private-registry.com"
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Users configure their registry:
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
npm config set @spaced-out:registry https://your-private-registry.com
|
|
283
|
+
# or with yarn
|
|
284
|
+
yarn config set registry https://your-private-registry.com
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## š¤ Contributing
|
|
288
|
+
|
|
289
|
+
When updating the design system:
|
|
290
|
+
|
|
291
|
+
1. Changes to components/hooks/tokens are automatically detected
|
|
292
|
+
2. CI/CD runs `npm run build` to regenerate data
|
|
293
|
+
3. New version is published to npm
|
|
294
|
+
4. Users get updates on next `npx` run (or immediately with `@latest`)
|
|
295
|
+
|
|
296
|
+
## š Additional Resources
|
|
297
|
+
|
|
298
|
+
- [MCP Documentation](https://modelcontextprotocol.io)
|
|
299
|
+
|
|
300
|
+
## š License
|
|
301
|
+
|
|
302
|
+
UNLICENSED - Internal use only
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
**Built with ā¤ļø by the Central UI team**
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build script to extract design system metadata into JSON
|
|
5
|
+
* This runs before publishing to npm to bundle all component/token data
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readFileSync, writeFileSync, readdirSync, statSync, existsSync, mkdirSync } from 'fs';
|
|
9
|
+
import { join, resolve, dirname } from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
|
|
15
|
+
// Design system is parent directory
|
|
16
|
+
const DESIGN_SYSTEM_PATH = resolve(__dirname, '..');
|
|
17
|
+
const OUTPUT_DIR = join(__dirname, 'data');
|
|
18
|
+
const OUTPUT_FILE = join(OUTPUT_DIR, 'design-system.json');
|
|
19
|
+
|
|
20
|
+
console.log('Building Genesis MCP data...\n');
|
|
21
|
+
console.log(`Design System: ${DESIGN_SYSTEM_PATH}`);
|
|
22
|
+
console.log(`Output: ${OUTPUT_FILE}\n`);
|
|
23
|
+
|
|
24
|
+
function safeReadFile(filePath) {
|
|
25
|
+
try {
|
|
26
|
+
return readFileSync(filePath, 'utf-8');
|
|
27
|
+
} catch (error) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getDirectories(path) {
|
|
33
|
+
try {
|
|
34
|
+
return readdirSync(path).filter(f => {
|
|
35
|
+
const fullPath = join(path, f);
|
|
36
|
+
return statSync(fullPath).isDirectory() && !f.startsWith('.');
|
|
37
|
+
});
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error(`ā Error reading directories in ${path}:`, error.message);
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Extract all components with their files
|
|
46
|
+
*/
|
|
47
|
+
function buildComponentsData() {
|
|
48
|
+
console.log('š¦ Extracting components...');
|
|
49
|
+
const componentsPath = join(DESIGN_SYSTEM_PATH, 'src/components');
|
|
50
|
+
const components = {};
|
|
51
|
+
|
|
52
|
+
if (!existsSync(componentsPath)) {
|
|
53
|
+
console.warn('ā ļø Components path not found');
|
|
54
|
+
return components;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const componentDirs = getDirectories(componentsPath).filter(name => name !== 'index.ts');
|
|
58
|
+
|
|
59
|
+
for (const componentName of componentDirs) {
|
|
60
|
+
const componentDir = join(componentsPath, componentName);
|
|
61
|
+
|
|
62
|
+
const mainTsx = join(componentDir, `${componentName}.tsx`);
|
|
63
|
+
const mainTs = join(componentDir, `${componentName}.ts`);
|
|
64
|
+
|
|
65
|
+
const storyTsx = join(componentDir, `${componentName}.stories.tsx`);
|
|
66
|
+
const storyTs = join(componentDir, `${componentName}.stories.ts`);
|
|
67
|
+
|
|
68
|
+
const cssFile = join(componentDir, `${componentName}.module.css`);
|
|
69
|
+
|
|
70
|
+
const indexFile = join(componentDir, 'index.ts');
|
|
71
|
+
|
|
72
|
+
const mainContent = safeReadFile(mainTsx) || safeReadFile(mainTs);
|
|
73
|
+
const storyContent = safeReadFile(storyTsx) || safeReadFile(storyTs);
|
|
74
|
+
const cssContent = safeReadFile(cssFile);
|
|
75
|
+
const indexContent = safeReadFile(indexFile);
|
|
76
|
+
|
|
77
|
+
const allFiles = existsSync(componentDir)
|
|
78
|
+
? readdirSync(componentDir).filter(f => !f.startsWith('.'))
|
|
79
|
+
: [];
|
|
80
|
+
|
|
81
|
+
components[componentName] = {
|
|
82
|
+
name: componentName,
|
|
83
|
+
path: `src/components/${componentName}`,
|
|
84
|
+
files: {
|
|
85
|
+
main: mainContent ? { path: `${componentName}.tsx`, content: mainContent } : null,
|
|
86
|
+
story: storyContent ? { path: `${componentName}.stories.tsx`, content: storyContent } : null,
|
|
87
|
+
css: cssContent ? { path: `${componentName}.module.css`, content: cssContent } : null,
|
|
88
|
+
index: indexContent ? { path: 'index.ts', content: indexContent } : null,
|
|
89
|
+
},
|
|
90
|
+
allFiles,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log(` ā
Extracted ${Object.keys(components).length} components`);
|
|
95
|
+
return components;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Extract all hooks
|
|
100
|
+
*/
|
|
101
|
+
function buildHooksData() {
|
|
102
|
+
console.log('šŖ Extracting hooks...');
|
|
103
|
+
const hooksPath = join(DESIGN_SYSTEM_PATH, 'src/hooks');
|
|
104
|
+
const hooks = {};
|
|
105
|
+
|
|
106
|
+
if (!existsSync(hooksPath)) {
|
|
107
|
+
console.warn('ā ļø Hooks path not found');
|
|
108
|
+
return hooks;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const hookDirs = getDirectories(hooksPath).filter(name => name !== 'index.ts');
|
|
112
|
+
|
|
113
|
+
for (const hookName of hookDirs) {
|
|
114
|
+
const hookDir = join(hooksPath, hookName);
|
|
115
|
+
|
|
116
|
+
// Read main hook file
|
|
117
|
+
const mainTs = join(hookDir, `${hookName}.ts`);
|
|
118
|
+
const mainTsx = join(hookDir, `${hookName}.tsx`);
|
|
119
|
+
|
|
120
|
+
// Read story file
|
|
121
|
+
const storyTsx = join(hookDir, `${hookName}.stories.tsx`);
|
|
122
|
+
const storyTs = join(hookDir, `${hookName}.stories.ts`);
|
|
123
|
+
|
|
124
|
+
// Read index file
|
|
125
|
+
const indexFile = join(hookDir, 'index.ts');
|
|
126
|
+
|
|
127
|
+
const mainContent = safeReadFile(mainTs) || safeReadFile(mainTsx);
|
|
128
|
+
const storyContent = safeReadFile(storyTsx) || safeReadFile(storyTs);
|
|
129
|
+
const indexContent = safeReadFile(indexFile);
|
|
130
|
+
|
|
131
|
+
const allFiles = existsSync(hookDir)
|
|
132
|
+
? readdirSync(hookDir).filter(f => !f.startsWith('.'))
|
|
133
|
+
: [];
|
|
134
|
+
|
|
135
|
+
hooks[hookName] = {
|
|
136
|
+
name: hookName,
|
|
137
|
+
path: `src/hooks/${hookName}`,
|
|
138
|
+
files: {
|
|
139
|
+
main: mainContent ? { path: `${hookName}.ts`, content: mainContent } : null,
|
|
140
|
+
story: storyContent ? { path: `${hookName}.stories.tsx`, content: storyContent } : null,
|
|
141
|
+
index: indexContent ? { path: 'index.ts', content: indexContent } : null,
|
|
142
|
+
},
|
|
143
|
+
allFiles,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log(` ā
Extracted ${Object.keys(hooks).length} hooks`);
|
|
148
|
+
return hooks;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Extract all design tokens
|
|
153
|
+
*/
|
|
154
|
+
function buildTokensData() {
|
|
155
|
+
console.log('šØ Extracting design tokens...');
|
|
156
|
+
const tokensPath = join(DESIGN_SYSTEM_PATH, 'design-tokens');
|
|
157
|
+
const tokens = {};
|
|
158
|
+
|
|
159
|
+
if (!existsSync(tokensPath)) {
|
|
160
|
+
console.warn('ā ļø Design tokens path not found');
|
|
161
|
+
return tokens;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const categories = getDirectories(tokensPath);
|
|
165
|
+
|
|
166
|
+
for (const category of categories) {
|
|
167
|
+
tokens[category] = {};
|
|
168
|
+
const categoryPath = join(tokensPath, category);
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const files = readdirSync(categoryPath).filter(f => f.endsWith('.json'));
|
|
172
|
+
|
|
173
|
+
for (const file of files) {
|
|
174
|
+
const filePath = join(categoryPath, file);
|
|
175
|
+
try {
|
|
176
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
177
|
+
const tokenData = JSON.parse(content);
|
|
178
|
+
tokens[category][file.replace('.json', '')] = tokenData;
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.warn(` ā ļø Error parsing ${file}:`, error.message);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.warn(` ā ļø Error reading category ${category}:`, error.message);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const tokenCount = Object.values(tokens).reduce((sum, cat) => sum + Object.keys(cat).length, 0);
|
|
189
|
+
console.log(` ā
Extracted ${tokenCount} token files across ${Object.keys(tokens).length} categories`);
|
|
190
|
+
return tokens;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get package version
|
|
195
|
+
*/
|
|
196
|
+
function getVersion() {
|
|
197
|
+
try {
|
|
198
|
+
const pkgPath = join(DESIGN_SYSTEM_PATH, 'package.json');
|
|
199
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
200
|
+
return pkg.version || '0.0.0';
|
|
201
|
+
} catch (error) {
|
|
202
|
+
return '0.0.0';
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Main build function
|
|
208
|
+
*/
|
|
209
|
+
function build() {
|
|
210
|
+
try {
|
|
211
|
+
const data = {
|
|
212
|
+
metadata: {
|
|
213
|
+
buildDate: new Date().toISOString(),
|
|
214
|
+
version: getVersion(),
|
|
215
|
+
designSystemPath: DESIGN_SYSTEM_PATH,
|
|
216
|
+
},
|
|
217
|
+
components: buildComponentsData(),
|
|
218
|
+
hooks: buildHooksData(),
|
|
219
|
+
tokens: buildTokensData(),
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Create output directory if it doesn't exist
|
|
223
|
+
if (!existsSync(OUTPUT_DIR)) {
|
|
224
|
+
mkdirSync(OUTPUT_DIR, { recursive: true });
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Write to JSON file
|
|
228
|
+
writeFileSync(OUTPUT_FILE, JSON.stringify(data, null, 2));
|
|
229
|
+
|
|
230
|
+
console.log('\n⨠Build complete!');
|
|
231
|
+
console.log(`š Summary:`);
|
|
232
|
+
console.log(` - Components: ${Object.keys(data.components).length}`);
|
|
233
|
+
console.log(` - Hooks: ${Object.keys(data.hooks).length}`);
|
|
234
|
+
console.log(` - Token categories: ${Object.keys(data.tokens).length}`);
|
|
235
|
+
console.log(` - Version: ${data.metadata.version}`);
|
|
236
|
+
console.log(` - Output: ${OUTPUT_FILE}`);
|
|
237
|
+
console.log(` - Size: ${(Buffer.byteLength(JSON.stringify(data)) / 1024 / 1024).toFixed(2)} MB\n`);
|
|
238
|
+
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error('ā Build failed:', error);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Run the build
|
|
246
|
+
build();
|
|
247
|
+
|