@ryndesign/preview 0.1.5 → 0.2.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/client/src/App.tsx +49 -23
- package/client/src/components/ExamplePages.tsx +431 -0
- package/client/src/components/PreviewPanel.tsx +1010 -98
- package/client/src/utils/tokenHelpers.ts +70 -0
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Extract a value from variant tokens with fallback
|
|
2
|
+
export function getVT(vt: any, prop: string, fallback: string): string {
|
|
3
|
+
const val = vt?.[prop]?.$value;
|
|
4
|
+
if (!val) return fallback;
|
|
5
|
+
if (val.hex) return val.hex;
|
|
6
|
+
if (val.value !== undefined && val.unit) return `${val.value}${val.unit}`;
|
|
7
|
+
if (typeof val === 'number' || typeof val === 'string') return String(val);
|
|
8
|
+
return fallback;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Shadow token value to CSS box-shadow
|
|
12
|
+
export function shadowToCSS(val: any): string {
|
|
13
|
+
if (!val) return 'none';
|
|
14
|
+
if (val.type === 'shadow') {
|
|
15
|
+
return `${val.offsetX} ${val.offsetY} ${val.blur} ${val.spread ?? '0px'} ${val.color}`;
|
|
16
|
+
}
|
|
17
|
+
if (val.offsetX) {
|
|
18
|
+
return `${val.offsetX} ${val.offsetY} ${val.blur} ${val.spread ?? '0px'} ${val.color}`;
|
|
19
|
+
}
|
|
20
|
+
return 'none';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Format a resolved token value for display
|
|
24
|
+
export function formatTokenValue(token: any): string {
|
|
25
|
+
const val = token?.$value;
|
|
26
|
+
if (!val) return '';
|
|
27
|
+
switch (val.type) {
|
|
28
|
+
case 'color': return val.hex;
|
|
29
|
+
case 'dimension': return `${val.value}${val.unit}`;
|
|
30
|
+
case 'fontWeight': return String(val.value);
|
|
31
|
+
case 'duration': return `${val.value}${val.unit}`;
|
|
32
|
+
case 'number': return String(val.value);
|
|
33
|
+
default: return JSON.stringify(val);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Find a token by dot-separated path
|
|
38
|
+
export function getToken(tokens: any[], path: string): any {
|
|
39
|
+
const parts = path.split('.');
|
|
40
|
+
return tokens.find((t: any) => {
|
|
41
|
+
if (t.path.length !== parts.length) return false;
|
|
42
|
+
return t.path.every((p: string, i: number) => p === parts[i]);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get a color from tokens by path, with fallback
|
|
47
|
+
export function getTokenColor(tokens: any[], path: string, fallback: string): string {
|
|
48
|
+
const t = getToken(tokens, path);
|
|
49
|
+
return t?.$value?.hex ?? fallback;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// daisyUI-like color palette based on tokens
|
|
53
|
+
export function getThemeColors(tokens: any[]) {
|
|
54
|
+
return {
|
|
55
|
+
primary: getTokenColor(tokens, 'color.primary', '#570df8'),
|
|
56
|
+
secondary: getTokenColor(tokens, 'color.secondary', '#f000b8'),
|
|
57
|
+
accent: getTokenColor(tokens, 'color.success', '#37cdbe'),
|
|
58
|
+
neutral: getTokenColor(tokens, 'color.gray.700', '#2a323c'),
|
|
59
|
+
base100: getTokenColor(tokens, 'color.background.primary', '#ffffff'),
|
|
60
|
+
base200: getTokenColor(tokens, 'color.background.secondary', '#f2f2f2'),
|
|
61
|
+
base300: getTokenColor(tokens, 'color.background.tertiary', '#e5e6e6'),
|
|
62
|
+
baseContent: getTokenColor(tokens, 'color.text.primary', '#1f2937'),
|
|
63
|
+
info: getTokenColor(tokens, 'color.info', '#3abff8'),
|
|
64
|
+
success: getTokenColor(tokens, 'color.success', '#36d399'),
|
|
65
|
+
warning: getTokenColor(tokens, 'color.warning', '#fbbd23'),
|
|
66
|
+
error: getTokenColor(tokens, 'color.error', '#f87272'),
|
|
67
|
+
primaryContent: '#ffffff',
|
|
68
|
+
borderColor: getTokenColor(tokens, 'color.border.default', '#e5e7eb'),
|
|
69
|
+
};
|
|
70
|
+
}
|
package/dist/index.cjs
CHANGED
|
@@ -123,7 +123,9 @@ function setupWsHandler(wss, builder) {
|
|
|
123
123
|
broadcast(wss, {
|
|
124
124
|
type: "rebuild-complete",
|
|
125
125
|
changedTokens: [update.path],
|
|
126
|
-
timestamp: Date.now()
|
|
126
|
+
timestamp: Date.now(),
|
|
127
|
+
tokenSet: builder.getTokenSet(),
|
|
128
|
+
components: builder.getComponents()
|
|
127
129
|
});
|
|
128
130
|
break;
|
|
129
131
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/server/index.ts","../src/server/api-routes.ts","../src/server/ws-handler.ts","../src/server/watcher.ts","../src/server/incremental-build.ts"],"sourcesContent":["export { startPreviewServer } from './server/index.js';\nexport type { PreviewServerOptions } from './server/index.js';\n","import { createServer as createViteServer } from 'vite';\nimport { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport net from 'node:net';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { setupApiRoutes } from './api-routes.js';\nimport { setupWsHandler } from './ws-handler.js';\nimport { setupWatcher } from './watcher.js';\nimport { IncrementalBuilder } from './incremental-build.js';\n\nexport interface PreviewServerOptions {\n port?: number;\n open?: boolean;\n configPath?: string;\n generators?: unknown[];\n}\n\nfunction isPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const tester = net.createServer()\n .once('error', () => resolve(true))\n .once('listening', () => {\n tester.close();\n resolve(false);\n })\n .listen(port);\n });\n}\n\nfunction killProcessOnPort(port: number): boolean {\n try {\n if (process.platform === 'win32') {\n const result = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf-8' });\n const pid = result.trim().split(/\\s+/).pop();\n if (pid) {\n execSync(`taskkill /PID ${pid} /F`);\n return true;\n }\n } else {\n execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: 'pipe' });\n return true;\n }\n } catch {\n // No process found or kill failed\n }\n return false;\n}\n\nexport async function startPreviewServer(options: PreviewServerOptions = {}): Promise<void> {\n const port = options.port ?? 4400;\n const cwd = process.cwd();\n\n // Check if port is in use\n if (await isPortInUse(port)) {\n const isTTY = process.stdin.isTTY && process.stdout.isTTY;\n\n if (isTTY) {\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => {\n rl.question(`\\n Port ${port} is already in use. Kill the existing process and restart? (y/N) `, resolve);\n });\n rl.close();\n\n if (answer.toLowerCase() === 'y') {\n if (killProcessOnPort(port)) {\n console.log(` Killed process on port ${port}.`);\n await new Promise(r => setTimeout(r, 500));\n } else {\n console.error(` Could not kill process on port ${port}.`);\n process.exit(1);\n }\n } else {\n console.log(' Aborted.');\n process.exit(0);\n }\n } else {\n console.error(`\\n Port ${port} is already in use. Use --port to specify a different port.`);\n process.exit(1);\n }\n }\n\n // Initialize incremental builder\n const builder = new IncrementalBuilder(cwd, options.configPath);\n if (options.generators && options.generators.length > 0) {\n builder.setGenerators(options.generators as import('@ryndesign/plugin-api').GeneratorPlugin[]);\n }\n await builder.initialBuild();\n\n // Create HTTP server\n const server = http.createServer();\n\n // Setup preview WebSocket in noServer mode to avoid Vite HMR conflict\n const wss = new WebSocketServer({ noServer: true });\n setupWsHandler(wss, builder);\n\n // Create Vite dev server for client SPA\n let reactPlugin;\n try {\n const mod = await import('@vitejs/plugin-react');\n reactPlugin = (mod.default ?? mod)();\n } catch {\n // Plugin not available, proceed without it\n }\n\n const vite = await createViteServer({\n root: path.resolve(__dirname, '../client'),\n server: {\n middlewareMode: true,\n hmr: { server },\n },\n plugins: reactPlugin ? [reactPlugin] : [],\n appType: 'spa',\n });\n\n // Route WebSocket upgrades: /ws → preview, everything else → Vite HMR\n server.on('upgrade', (req, socket, head) => {\n if (req.url === '/ws') {\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit('connection', ws, req);\n });\n }\n // Other upgrade requests (Vite HMR) are handled by Vite automatically\n });\n\n // Setup API routes\n const apiHandler = setupApiRoutes(builder);\n\n // Handle requests\n server.on('request', (req, res) => {\n if (req.url?.startsWith('/api/')) {\n apiHandler(req, res);\n } else {\n vite.middlewares(req, res);\n }\n });\n\n // Setup file watcher\n setupWatcher(builder, wss, cwd);\n\n // Start server\n server.listen(port, () => {\n console.log(`\\n 🎨 RynDesign Preview`);\n console.log(` ➜ Local: http://localhost:${port}/`);\n console.log(` ➜ WS: ws://localhost:${port}/ws\\n`);\n\n if (options.open) {\n import('child_process').then(cp => {\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n cp.exec(`${cmd} http://localhost:${port}/`);\n }).catch(() => {});\n }\n });\n\n // Graceful shutdown\n process.on('SIGINT', () => {\n wss.close();\n vite.close();\n server.close();\n process.exit(0);\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\ntype RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;\n\nexport function setupApiRoutes(builder: IncrementalBuilder): RequestHandler {\n return (req, res) => {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const pathname = url.pathname;\n\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n if (pathname === '/api/tokens' && req.method === 'GET') {\n json(res, builder.getTokenSet());\n } else if (pathname === '/api/themes' && req.method === 'GET') {\n json(res, builder.getThemes());\n } else if (pathname === '/api/components' && req.method === 'GET') {\n json(res, builder.getComponents());\n } else if (pathname === '/api/snippets' && req.method === 'GET') {\n const platform = url.searchParams.get('platform') ?? 'react';\n const component = url.searchParams.get('component') ?? undefined;\n const type = url.searchParams.get('type') ?? undefined;\n builder.generateSnippets(platform, component, type).then(code => {\n json(res, { code });\n }).catch(err => {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n });\n return; // async handling\n } else if (pathname === '/api/tokens' && req.method === 'PUT') {\n let body = '';\n req.on('data', chunk => { body += chunk; });\n req.on('end', async () => {\n const { path, value, theme } = JSON.parse(body);\n await builder.updateToken(path, value, theme);\n json(res, { success: true });\n });\n } else if (pathname === '/api/generated' && req.method === 'GET') {\n const platform = url.searchParams.get('platform');\n json(res, builder.getGeneratedFiles(platform ?? undefined));\n } else {\n res.writeHead(404);\n json(res, { error: 'Not found' });\n }\n } catch (err) {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n }\n };\n}\n\nfunction json(res: ServerResponse, data: unknown): void {\n if (!res.headersSent) {\n res.setHeader('Content-Type', 'application/json');\n }\n res.end(JSON.stringify(data));\n}\n","import type { WebSocketServer, WebSocket } from 'ws';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport interface WsMessage {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface TokenUpdateMessage extends WsMessage {\n type: 'token-update';\n theme?: string;\n path: string;\n value: unknown;\n}\n\nexport interface ThemeChangeMessage extends WsMessage {\n type: 'theme-change';\n theme: string;\n}\n\nexport interface RebuildCompleteMessage extends WsMessage {\n type: 'rebuild-complete';\n changedTokens: string[];\n timestamp: number;\n}\n\nexport function setupWsHandler(wss: WebSocketServer, builder: IncrementalBuilder): void {\n wss.on('connection', (ws: WebSocket) => {\n console.log('Preview client connected');\n\n // Send initial state\n ws.send(JSON.stringify({\n type: 'init',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n\n ws.on('message', async (data: Buffer) => {\n try {\n const message = JSON.parse(data.toString()) as WsMessage;\n\n switch (message.type) {\n case 'token-update': {\n const update = message as TokenUpdateMessage;\n await builder.updateToken(update.path, update.value, update.theme);\n\n // Broadcast rebuild complete to all clients\n broadcast(wss, {\n type: 'rebuild-complete',\n changedTokens: [update.path],\n timestamp: Date.now(),\n });\n break;\n }\n\n case 'theme-change': {\n const themeMsg = message as ThemeChangeMessage;\n broadcast(wss, {\n type: 'theme-switched',\n theme: themeMsg.theme,\n tokens: builder.getThemeTokens(themeMsg.theme),\n });\n break;\n }\n\n case 'request-state': {\n ws.send(JSON.stringify({\n type: 'full-state',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n break;\n }\n }\n } catch (err) {\n ws.send(JSON.stringify({\n type: 'error',\n message: (err as Error).message,\n }));\n }\n });\n\n ws.on('close', () => {\n console.log('Preview client disconnected');\n });\n });\n}\n\nfunction broadcast(wss: WebSocketServer, message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n for (const client of wss.clients) {\n if (client.readyState === 1) { // WebSocket.OPEN\n client.send(data);\n }\n }\n}\n","import type { WebSocketServer } from 'ws';\nimport { watch } from 'chokidar';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport function setupWatcher(\n builder: IncrementalBuilder,\n wss: WebSocketServer,\n cwd: string\n): void {\n const watcher = watch(\n ['tokens/**/*.tokens.json', 'components/**/*.component.json'],\n {\n cwd,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 300,\n pollInterval: 50,\n },\n }\n );\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const handleChange = (changedPath: string) => {\n if (debounceTimer) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(async () => {\n console.log(`File changed: ${changedPath}`);\n\n try {\n await builder.rebuild();\n\n // Broadcast to all connected clients\n const data = JSON.stringify({\n type: 'rebuild-complete',\n changedTokens: [],\n timestamp: Date.now(),\n tokenSet: builder.getTokenSet(),\n components: builder.getComponents(),\n });\n\n for (const client of wss.clients) {\n if (client.readyState === 1) {\n client.send(data);\n }\n }\n } catch (err) {\n console.error('Rebuild failed:', (err as Error).message);\n }\n }, 300);\n };\n\n watcher.on('change', handleChange);\n watcher.on('add', handleChange);\n watcher.on('unlink', handleChange);\n}\n","import { buildTokenSet, loadComponents, resolveComponent, type RawTokenTree } from '@ryndesign/core';\nimport type { ResolvedTokenSet, GeneratedFile, ResolvedComponent, GeneratorPlugin } from '@ryndesign/plugin-api';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport class IncrementalBuilder {\n private tokenSet: ResolvedTokenSet | null = null;\n private components: ResolvedComponent[] = [];\n private generatedFiles: Map<string, GeneratedFile[]> = new Map();\n private generators: GeneratorPlugin[] = [];\n private cwd: string;\n private configPath?: string;\n\n constructor(cwd: string, configPath?: string) {\n this.cwd = cwd;\n this.configPath = configPath;\n }\n\n async initialBuild(): Promise<void> {\n await this.rebuild();\n }\n\n async rebuild(): Promise<void> {\n const configFile = this.configPath ?? 'ryndesign.config.ts';\n\n const tokens = ['tokens/**/*.tokens.json'];\n const componentPatterns = ['components/**/*.component.json'];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let themes: any = undefined;\n\n try {\n const configPath = path.resolve(this.cwd, configFile);\n const content = await fs.readFile(configPath, 'utf-8');\n if (content.includes('dark')) {\n themes = {\n default: 'light',\n dark: { file: path.resolve(this.cwd, 'tokens/dark.tokens.json') },\n };\n }\n } catch {\n // Use defaults\n }\n\n this.tokenSet = await buildTokenSet({\n tokens,\n basePath: this.cwd,\n themes,\n });\n\n // Load and resolve components\n try {\n const componentDefs = await loadComponents(componentPatterns, this.cwd);\n this.components = componentDefs.map(def => resolveComponent(def, this.tokenSet!));\n } catch {\n this.components = [];\n }\n }\n\n getTokenSet(): ResolvedTokenSet | null {\n return this.tokenSet;\n }\n\n getThemes(): Record<string, unknown> {\n if (!this.tokenSet) return {};\n return {\n default: this.tokenSet.themes.default,\n available: Object.keys(this.tokenSet.themes.themes),\n themes: this.tokenSet.themes.themes,\n };\n }\n\n getThemeTokens(theme: string): Record<string, unknown> {\n if (!this.tokenSet) return {};\n const themeData = this.tokenSet.themes.themes[theme];\n if (!themeData) return {};\n return {\n name: themeData.name,\n tokens: themeData.tokens,\n };\n }\n\n getComponents(): ResolvedComponent[] {\n return this.components;\n }\n\n setGenerators(generators: GeneratorPlugin[]): void {\n this.generators = generators;\n }\n\n async generateSnippets(platform: string, componentName?: string, type?: string): Promise<string> {\n if (!this.tokenSet) return '';\n\n const generator = this.generators.find(g => g.name === platform);\n if (!generator) return `// Generator for \"${platform}\" not available`;\n\n const { createGeneratorHelpers } = await import('@ryndesign/core');\n const ctx = {\n tokenSet: this.tokenSet,\n config: { outDir: 'generated' },\n outputDir: path.resolve(this.cwd, 'generated'),\n helpers: createGeneratorHelpers(),\n components: this.components,\n };\n\n try {\n if (type === 'tokens') {\n const files = await generator.generateTokens(ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n\n if (componentName) {\n const comp = this.components.find(c => c.definition.name === componentName);\n if (comp) {\n const files = await generator.generateComponent(comp, ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n return `// Component \"${componentName}\" not found`;\n }\n\n return '// Specify a component or type=tokens';\n } catch (err) {\n return `// Error: ${(err as Error).message}`;\n }\n }\n\n getGeneratedFiles(platform?: string): GeneratedFile[] {\n if (!platform) {\n return Array.from(this.generatedFiles.values()).flat();\n }\n return this.generatedFiles.get(platform) ?? [];\n }\n\n async updateToken(tokenPath: string, value: unknown, theme?: string): Promise<void> {\n const filePath = theme\n ? path.resolve(this.cwd, `tokens/${theme}.tokens.json`)\n : path.resolve(this.cwd, 'tokens/semantic.tokens.json');\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const tree = JSON.parse(content) as RawTokenTree;\n\n const parts = tokenPath.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]];\n }\n\n const lastKey = parts[parts.length - 1];\n if (current[lastKey] && typeof current[lastKey] === 'object' && '$value' in current[lastKey]) {\n current[lastKey].$value = value;\n } else {\n current[lastKey] = { $type: 'color', $value: value };\n }\n\n await fs.writeFile(filePath, JSON.stringify(tree, null, 2), 'utf-8');\n await this.rebuild();\n } catch (err) {\n console.error(`Failed to update token: ${(err as Error).message}`);\n throw err;\n }\n }\n}\n"],"mappings":"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","names":["import_node_path","path","path","fs","net","http","createViteServer","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/server/index.ts","../src/server/api-routes.ts","../src/server/ws-handler.ts","../src/server/watcher.ts","../src/server/incremental-build.ts"],"sourcesContent":["export { startPreviewServer } from './server/index.js';\nexport type { PreviewServerOptions } from './server/index.js';\n","import { createServer as createViteServer } from 'vite';\nimport { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport net from 'node:net';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { setupApiRoutes } from './api-routes.js';\nimport { setupWsHandler } from './ws-handler.js';\nimport { setupWatcher } from './watcher.js';\nimport { IncrementalBuilder } from './incremental-build.js';\n\nexport interface PreviewServerOptions {\n port?: number;\n open?: boolean;\n configPath?: string;\n generators?: unknown[];\n}\n\nfunction isPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const tester = net.createServer()\n .once('error', () => resolve(true))\n .once('listening', () => {\n tester.close();\n resolve(false);\n })\n .listen(port);\n });\n}\n\nfunction killProcessOnPort(port: number): boolean {\n try {\n if (process.platform === 'win32') {\n const result = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf-8' });\n const pid = result.trim().split(/\\s+/).pop();\n if (pid) {\n execSync(`taskkill /PID ${pid} /F`);\n return true;\n }\n } else {\n execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: 'pipe' });\n return true;\n }\n } catch {\n // No process found or kill failed\n }\n return false;\n}\n\nexport async function startPreviewServer(options: PreviewServerOptions = {}): Promise<void> {\n const port = options.port ?? 4400;\n const cwd = process.cwd();\n\n // Check if port is in use\n if (await isPortInUse(port)) {\n const isTTY = process.stdin.isTTY && process.stdout.isTTY;\n\n if (isTTY) {\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => {\n rl.question(`\\n Port ${port} is already in use. Kill the existing process and restart? (y/N) `, resolve);\n });\n rl.close();\n\n if (answer.toLowerCase() === 'y') {\n if (killProcessOnPort(port)) {\n console.log(` Killed process on port ${port}.`);\n await new Promise(r => setTimeout(r, 500));\n } else {\n console.error(` Could not kill process on port ${port}.`);\n process.exit(1);\n }\n } else {\n console.log(' Aborted.');\n process.exit(0);\n }\n } else {\n console.error(`\\n Port ${port} is already in use. Use --port to specify a different port.`);\n process.exit(1);\n }\n }\n\n // Initialize incremental builder\n const builder = new IncrementalBuilder(cwd, options.configPath);\n if (options.generators && options.generators.length > 0) {\n builder.setGenerators(options.generators as import('@ryndesign/plugin-api').GeneratorPlugin[]);\n }\n await builder.initialBuild();\n\n // Create HTTP server\n const server = http.createServer();\n\n // Setup preview WebSocket in noServer mode to avoid Vite HMR conflict\n const wss = new WebSocketServer({ noServer: true });\n setupWsHandler(wss, builder);\n\n // Create Vite dev server for client SPA\n let reactPlugin;\n try {\n const mod = await import('@vitejs/plugin-react');\n reactPlugin = (mod.default ?? mod)();\n } catch {\n // Plugin not available, proceed without it\n }\n\n const vite = await createViteServer({\n root: path.resolve(__dirname, '../client'),\n server: {\n middlewareMode: true,\n hmr: { server },\n },\n plugins: reactPlugin ? [reactPlugin] : [],\n appType: 'spa',\n });\n\n // Route WebSocket upgrades: /ws → preview, everything else → Vite HMR\n server.on('upgrade', (req, socket, head) => {\n if (req.url === '/ws') {\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit('connection', ws, req);\n });\n }\n // Other upgrade requests (Vite HMR) are handled by Vite automatically\n });\n\n // Setup API routes\n const apiHandler = setupApiRoutes(builder);\n\n // Handle requests\n server.on('request', (req, res) => {\n if (req.url?.startsWith('/api/')) {\n apiHandler(req, res);\n } else {\n vite.middlewares(req, res);\n }\n });\n\n // Setup file watcher\n setupWatcher(builder, wss, cwd);\n\n // Start server\n server.listen(port, () => {\n console.log(`\\n 🎨 RynDesign Preview`);\n console.log(` ➜ Local: http://localhost:${port}/`);\n console.log(` ➜ WS: ws://localhost:${port}/ws\\n`);\n\n if (options.open) {\n import('child_process').then(cp => {\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n cp.exec(`${cmd} http://localhost:${port}/`);\n }).catch(() => {});\n }\n });\n\n // Graceful shutdown\n process.on('SIGINT', () => {\n wss.close();\n vite.close();\n server.close();\n process.exit(0);\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\ntype RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;\n\nexport function setupApiRoutes(builder: IncrementalBuilder): RequestHandler {\n return (req, res) => {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const pathname = url.pathname;\n\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n if (pathname === '/api/tokens' && req.method === 'GET') {\n json(res, builder.getTokenSet());\n } else if (pathname === '/api/themes' && req.method === 'GET') {\n json(res, builder.getThemes());\n } else if (pathname === '/api/components' && req.method === 'GET') {\n json(res, builder.getComponents());\n } else if (pathname === '/api/snippets' && req.method === 'GET') {\n const platform = url.searchParams.get('platform') ?? 'react';\n const component = url.searchParams.get('component') ?? undefined;\n const type = url.searchParams.get('type') ?? undefined;\n builder.generateSnippets(platform, component, type).then(code => {\n json(res, { code });\n }).catch(err => {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n });\n return; // async handling\n } else if (pathname === '/api/tokens' && req.method === 'PUT') {\n let body = '';\n req.on('data', chunk => { body += chunk; });\n req.on('end', async () => {\n const { path, value, theme } = JSON.parse(body);\n await builder.updateToken(path, value, theme);\n json(res, { success: true });\n });\n } else if (pathname === '/api/generated' && req.method === 'GET') {\n const platform = url.searchParams.get('platform');\n json(res, builder.getGeneratedFiles(platform ?? undefined));\n } else {\n res.writeHead(404);\n json(res, { error: 'Not found' });\n }\n } catch (err) {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n }\n };\n}\n\nfunction json(res: ServerResponse, data: unknown): void {\n if (!res.headersSent) {\n res.setHeader('Content-Type', 'application/json');\n }\n res.end(JSON.stringify(data));\n}\n","import type { WebSocketServer, WebSocket } from 'ws';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport interface WsMessage {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface TokenUpdateMessage extends WsMessage {\n type: 'token-update';\n theme?: string;\n path: string;\n value: unknown;\n}\n\nexport interface ThemeChangeMessage extends WsMessage {\n type: 'theme-change';\n theme: string;\n}\n\nexport interface RebuildCompleteMessage extends WsMessage {\n type: 'rebuild-complete';\n changedTokens: string[];\n timestamp: number;\n}\n\nexport function setupWsHandler(wss: WebSocketServer, builder: IncrementalBuilder): void {\n wss.on('connection', (ws: WebSocket) => {\n console.log('Preview client connected');\n\n // Send initial state\n ws.send(JSON.stringify({\n type: 'init',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n\n ws.on('message', async (data: Buffer) => {\n try {\n const message = JSON.parse(data.toString()) as WsMessage;\n\n switch (message.type) {\n case 'token-update': {\n const update = message as TokenUpdateMessage;\n await builder.updateToken(update.path, update.value, update.theme);\n\n // Broadcast rebuild complete to all clients\n broadcast(wss, {\n type: 'rebuild-complete',\n changedTokens: [update.path],\n timestamp: Date.now(),\n tokenSet: builder.getTokenSet(),\n components: builder.getComponents(),\n });\n break;\n }\n\n case 'theme-change': {\n const themeMsg = message as ThemeChangeMessage;\n broadcast(wss, {\n type: 'theme-switched',\n theme: themeMsg.theme,\n tokens: builder.getThemeTokens(themeMsg.theme),\n });\n break;\n }\n\n case 'request-state': {\n ws.send(JSON.stringify({\n type: 'full-state',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n break;\n }\n }\n } catch (err) {\n ws.send(JSON.stringify({\n type: 'error',\n message: (err as Error).message,\n }));\n }\n });\n\n ws.on('close', () => {\n console.log('Preview client disconnected');\n });\n });\n}\n\nfunction broadcast(wss: WebSocketServer, message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n for (const client of wss.clients) {\n if (client.readyState === 1) { // WebSocket.OPEN\n client.send(data);\n }\n }\n}\n","import type { WebSocketServer } from 'ws';\nimport { watch } from 'chokidar';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport function setupWatcher(\n builder: IncrementalBuilder,\n wss: WebSocketServer,\n cwd: string\n): void {\n const watcher = watch(\n ['tokens/**/*.tokens.json', 'components/**/*.component.json'],\n {\n cwd,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 300,\n pollInterval: 50,\n },\n }\n );\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const handleChange = (changedPath: string) => {\n if (debounceTimer) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(async () => {\n console.log(`File changed: ${changedPath}`);\n\n try {\n await builder.rebuild();\n\n // Broadcast to all connected clients\n const data = JSON.stringify({\n type: 'rebuild-complete',\n changedTokens: [],\n timestamp: Date.now(),\n tokenSet: builder.getTokenSet(),\n components: builder.getComponents(),\n });\n\n for (const client of wss.clients) {\n if (client.readyState === 1) {\n client.send(data);\n }\n }\n } catch (err) {\n console.error('Rebuild failed:', (err as Error).message);\n }\n }, 300);\n };\n\n watcher.on('change', handleChange);\n watcher.on('add', handleChange);\n watcher.on('unlink', handleChange);\n}\n","import { buildTokenSet, loadComponents, resolveComponent, type RawTokenTree } from '@ryndesign/core';\nimport type { ResolvedTokenSet, GeneratedFile, ResolvedComponent, GeneratorPlugin } from '@ryndesign/plugin-api';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport class IncrementalBuilder {\n private tokenSet: ResolvedTokenSet | null = null;\n private components: ResolvedComponent[] = [];\n private generatedFiles: Map<string, GeneratedFile[]> = new Map();\n private generators: GeneratorPlugin[] = [];\n private cwd: string;\n private configPath?: string;\n\n constructor(cwd: string, configPath?: string) {\n this.cwd = cwd;\n this.configPath = configPath;\n }\n\n async initialBuild(): Promise<void> {\n await this.rebuild();\n }\n\n async rebuild(): Promise<void> {\n const configFile = this.configPath ?? 'ryndesign.config.ts';\n\n const tokens = ['tokens/**/*.tokens.json'];\n const componentPatterns = ['components/**/*.component.json'];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let themes: any = undefined;\n\n try {\n const configPath = path.resolve(this.cwd, configFile);\n const content = await fs.readFile(configPath, 'utf-8');\n if (content.includes('dark')) {\n themes = {\n default: 'light',\n dark: { file: path.resolve(this.cwd, 'tokens/dark.tokens.json') },\n };\n }\n } catch {\n // Use defaults\n }\n\n this.tokenSet = await buildTokenSet({\n tokens,\n basePath: this.cwd,\n themes,\n });\n\n // Load and resolve components\n try {\n const componentDefs = await loadComponents(componentPatterns, this.cwd);\n this.components = componentDefs.map(def => resolveComponent(def, this.tokenSet!));\n } catch {\n this.components = [];\n }\n }\n\n getTokenSet(): ResolvedTokenSet | null {\n return this.tokenSet;\n }\n\n getThemes(): Record<string, unknown> {\n if (!this.tokenSet) return {};\n return {\n default: this.tokenSet.themes.default,\n available: Object.keys(this.tokenSet.themes.themes),\n themes: this.tokenSet.themes.themes,\n };\n }\n\n getThemeTokens(theme: string): Record<string, unknown> {\n if (!this.tokenSet) return {};\n const themeData = this.tokenSet.themes.themes[theme];\n if (!themeData) return {};\n return {\n name: themeData.name,\n tokens: themeData.tokens,\n };\n }\n\n getComponents(): ResolvedComponent[] {\n return this.components;\n }\n\n setGenerators(generators: GeneratorPlugin[]): void {\n this.generators = generators;\n }\n\n async generateSnippets(platform: string, componentName?: string, type?: string): Promise<string> {\n if (!this.tokenSet) return '';\n\n const generator = this.generators.find(g => g.name === platform);\n if (!generator) return `// Generator for \"${platform}\" not available`;\n\n const { createGeneratorHelpers } = await import('@ryndesign/core');\n const ctx = {\n tokenSet: this.tokenSet,\n config: { outDir: 'generated' },\n outputDir: path.resolve(this.cwd, 'generated'),\n helpers: createGeneratorHelpers(),\n components: this.components,\n };\n\n try {\n if (type === 'tokens') {\n const files = await generator.generateTokens(ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n\n if (componentName) {\n const comp = this.components.find(c => c.definition.name === componentName);\n if (comp) {\n const files = await generator.generateComponent(comp, ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n return `// Component \"${componentName}\" not found`;\n }\n\n return '// Specify a component or type=tokens';\n } catch (err) {\n return `// Error: ${(err as Error).message}`;\n }\n }\n\n getGeneratedFiles(platform?: string): GeneratedFile[] {\n if (!platform) {\n return Array.from(this.generatedFiles.values()).flat();\n }\n return this.generatedFiles.get(platform) ?? [];\n }\n\n async updateToken(tokenPath: string, value: unknown, theme?: string): Promise<void> {\n const filePath = theme\n ? path.resolve(this.cwd, `tokens/${theme}.tokens.json`)\n : path.resolve(this.cwd, 'tokens/semantic.tokens.json');\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const tree = JSON.parse(content) as RawTokenTree;\n\n const parts = tokenPath.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]];\n }\n\n const lastKey = parts[parts.length - 1];\n if (current[lastKey] && typeof current[lastKey] === 'object' && '$value' in current[lastKey]) {\n current[lastKey].$value = value;\n } else {\n current[lastKey] = { $type: 'color', $value: value };\n }\n\n await fs.writeFile(filePath, JSON.stringify(tree, null, 2), 'utf-8');\n await this.rebuild();\n } catch (err) {\n console.error(`Failed to update token: ${(err as Error).message}`);\n throw err;\n }\n }\n}\n"],"mappings":"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","names":["import_node_path","path","path","fs","net","http","createViteServer","path"]}
|
package/dist/index.js
CHANGED
|
@@ -94,7 +94,9 @@ function setupWsHandler(wss, builder) {
|
|
|
94
94
|
broadcast(wss, {
|
|
95
95
|
type: "rebuild-complete",
|
|
96
96
|
changedTokens: [update.path],
|
|
97
|
-
timestamp: Date.now()
|
|
97
|
+
timestamp: Date.now(),
|
|
98
|
+
tokenSet: builder.getTokenSet(),
|
|
99
|
+
components: builder.getComponents()
|
|
98
100
|
});
|
|
99
101
|
break;
|
|
100
102
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.5.4/node_modules/tsup/assets/esm_shims.js","../src/server/index.ts","../src/server/api-routes.ts","../src/server/ws-handler.ts","../src/server/watcher.ts","../src/server/incremental-build.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import { createServer as createViteServer } from 'vite';\nimport { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport net from 'node:net';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { setupApiRoutes } from './api-routes.js';\nimport { setupWsHandler } from './ws-handler.js';\nimport { setupWatcher } from './watcher.js';\nimport { IncrementalBuilder } from './incremental-build.js';\n\nexport interface PreviewServerOptions {\n port?: number;\n open?: boolean;\n configPath?: string;\n generators?: unknown[];\n}\n\nfunction isPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const tester = net.createServer()\n .once('error', () => resolve(true))\n .once('listening', () => {\n tester.close();\n resolve(false);\n })\n .listen(port);\n });\n}\n\nfunction killProcessOnPort(port: number): boolean {\n try {\n if (process.platform === 'win32') {\n const result = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf-8' });\n const pid = result.trim().split(/\\s+/).pop();\n if (pid) {\n execSync(`taskkill /PID ${pid} /F`);\n return true;\n }\n } else {\n execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: 'pipe' });\n return true;\n }\n } catch {\n // No process found or kill failed\n }\n return false;\n}\n\nexport async function startPreviewServer(options: PreviewServerOptions = {}): Promise<void> {\n const port = options.port ?? 4400;\n const cwd = process.cwd();\n\n // Check if port is in use\n if (await isPortInUse(port)) {\n const isTTY = process.stdin.isTTY && process.stdout.isTTY;\n\n if (isTTY) {\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => {\n rl.question(`\\n Port ${port} is already in use. Kill the existing process and restart? (y/N) `, resolve);\n });\n rl.close();\n\n if (answer.toLowerCase() === 'y') {\n if (killProcessOnPort(port)) {\n console.log(` Killed process on port ${port}.`);\n await new Promise(r => setTimeout(r, 500));\n } else {\n console.error(` Could not kill process on port ${port}.`);\n process.exit(1);\n }\n } else {\n console.log(' Aborted.');\n process.exit(0);\n }\n } else {\n console.error(`\\n Port ${port} is already in use. Use --port to specify a different port.`);\n process.exit(1);\n }\n }\n\n // Initialize incremental builder\n const builder = new IncrementalBuilder(cwd, options.configPath);\n if (options.generators && options.generators.length > 0) {\n builder.setGenerators(options.generators as import('@ryndesign/plugin-api').GeneratorPlugin[]);\n }\n await builder.initialBuild();\n\n // Create HTTP server\n const server = http.createServer();\n\n // Setup preview WebSocket in noServer mode to avoid Vite HMR conflict\n const wss = new WebSocketServer({ noServer: true });\n setupWsHandler(wss, builder);\n\n // Create Vite dev server for client SPA\n let reactPlugin;\n try {\n const mod = await import('@vitejs/plugin-react');\n reactPlugin = (mod.default ?? mod)();\n } catch {\n // Plugin not available, proceed without it\n }\n\n const vite = await createViteServer({\n root: path.resolve(__dirname, '../client'),\n server: {\n middlewareMode: true,\n hmr: { server },\n },\n plugins: reactPlugin ? [reactPlugin] : [],\n appType: 'spa',\n });\n\n // Route WebSocket upgrades: /ws → preview, everything else → Vite HMR\n server.on('upgrade', (req, socket, head) => {\n if (req.url === '/ws') {\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit('connection', ws, req);\n });\n }\n // Other upgrade requests (Vite HMR) are handled by Vite automatically\n });\n\n // Setup API routes\n const apiHandler = setupApiRoutes(builder);\n\n // Handle requests\n server.on('request', (req, res) => {\n if (req.url?.startsWith('/api/')) {\n apiHandler(req, res);\n } else {\n vite.middlewares(req, res);\n }\n });\n\n // Setup file watcher\n setupWatcher(builder, wss, cwd);\n\n // Start server\n server.listen(port, () => {\n console.log(`\\n 🎨 RynDesign Preview`);\n console.log(` ➜ Local: http://localhost:${port}/`);\n console.log(` ➜ WS: ws://localhost:${port}/ws\\n`);\n\n if (options.open) {\n import('child_process').then(cp => {\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n cp.exec(`${cmd} http://localhost:${port}/`);\n }).catch(() => {});\n }\n });\n\n // Graceful shutdown\n process.on('SIGINT', () => {\n wss.close();\n vite.close();\n server.close();\n process.exit(0);\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\ntype RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;\n\nexport function setupApiRoutes(builder: IncrementalBuilder): RequestHandler {\n return (req, res) => {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const pathname = url.pathname;\n\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n if (pathname === '/api/tokens' && req.method === 'GET') {\n json(res, builder.getTokenSet());\n } else if (pathname === '/api/themes' && req.method === 'GET') {\n json(res, builder.getThemes());\n } else if (pathname === '/api/components' && req.method === 'GET') {\n json(res, builder.getComponents());\n } else if (pathname === '/api/snippets' && req.method === 'GET') {\n const platform = url.searchParams.get('platform') ?? 'react';\n const component = url.searchParams.get('component') ?? undefined;\n const type = url.searchParams.get('type') ?? undefined;\n builder.generateSnippets(platform, component, type).then(code => {\n json(res, { code });\n }).catch(err => {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n });\n return; // async handling\n } else if (pathname === '/api/tokens' && req.method === 'PUT') {\n let body = '';\n req.on('data', chunk => { body += chunk; });\n req.on('end', async () => {\n const { path, value, theme } = JSON.parse(body);\n await builder.updateToken(path, value, theme);\n json(res, { success: true });\n });\n } else if (pathname === '/api/generated' && req.method === 'GET') {\n const platform = url.searchParams.get('platform');\n json(res, builder.getGeneratedFiles(platform ?? undefined));\n } else {\n res.writeHead(404);\n json(res, { error: 'Not found' });\n }\n } catch (err) {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n }\n };\n}\n\nfunction json(res: ServerResponse, data: unknown): void {\n if (!res.headersSent) {\n res.setHeader('Content-Type', 'application/json');\n }\n res.end(JSON.stringify(data));\n}\n","import type { WebSocketServer, WebSocket } from 'ws';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport interface WsMessage {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface TokenUpdateMessage extends WsMessage {\n type: 'token-update';\n theme?: string;\n path: string;\n value: unknown;\n}\n\nexport interface ThemeChangeMessage extends WsMessage {\n type: 'theme-change';\n theme: string;\n}\n\nexport interface RebuildCompleteMessage extends WsMessage {\n type: 'rebuild-complete';\n changedTokens: string[];\n timestamp: number;\n}\n\nexport function setupWsHandler(wss: WebSocketServer, builder: IncrementalBuilder): void {\n wss.on('connection', (ws: WebSocket) => {\n console.log('Preview client connected');\n\n // Send initial state\n ws.send(JSON.stringify({\n type: 'init',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n\n ws.on('message', async (data: Buffer) => {\n try {\n const message = JSON.parse(data.toString()) as WsMessage;\n\n switch (message.type) {\n case 'token-update': {\n const update = message as TokenUpdateMessage;\n await builder.updateToken(update.path, update.value, update.theme);\n\n // Broadcast rebuild complete to all clients\n broadcast(wss, {\n type: 'rebuild-complete',\n changedTokens: [update.path],\n timestamp: Date.now(),\n });\n break;\n }\n\n case 'theme-change': {\n const themeMsg = message as ThemeChangeMessage;\n broadcast(wss, {\n type: 'theme-switched',\n theme: themeMsg.theme,\n tokens: builder.getThemeTokens(themeMsg.theme),\n });\n break;\n }\n\n case 'request-state': {\n ws.send(JSON.stringify({\n type: 'full-state',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n break;\n }\n }\n } catch (err) {\n ws.send(JSON.stringify({\n type: 'error',\n message: (err as Error).message,\n }));\n }\n });\n\n ws.on('close', () => {\n console.log('Preview client disconnected');\n });\n });\n}\n\nfunction broadcast(wss: WebSocketServer, message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n for (const client of wss.clients) {\n if (client.readyState === 1) { // WebSocket.OPEN\n client.send(data);\n }\n }\n}\n","import type { WebSocketServer } from 'ws';\nimport { watch } from 'chokidar';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport function setupWatcher(\n builder: IncrementalBuilder,\n wss: WebSocketServer,\n cwd: string\n): void {\n const watcher = watch(\n ['tokens/**/*.tokens.json', 'components/**/*.component.json'],\n {\n cwd,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 300,\n pollInterval: 50,\n },\n }\n );\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const handleChange = (changedPath: string) => {\n if (debounceTimer) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(async () => {\n console.log(`File changed: ${changedPath}`);\n\n try {\n await builder.rebuild();\n\n // Broadcast to all connected clients\n const data = JSON.stringify({\n type: 'rebuild-complete',\n changedTokens: [],\n timestamp: Date.now(),\n tokenSet: builder.getTokenSet(),\n components: builder.getComponents(),\n });\n\n for (const client of wss.clients) {\n if (client.readyState === 1) {\n client.send(data);\n }\n }\n } catch (err) {\n console.error('Rebuild failed:', (err as Error).message);\n }\n }, 300);\n };\n\n watcher.on('change', handleChange);\n watcher.on('add', handleChange);\n watcher.on('unlink', handleChange);\n}\n","import { buildTokenSet, loadComponents, resolveComponent, type RawTokenTree } from '@ryndesign/core';\nimport type { ResolvedTokenSet, GeneratedFile, ResolvedComponent, GeneratorPlugin } from '@ryndesign/plugin-api';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport class IncrementalBuilder {\n private tokenSet: ResolvedTokenSet | null = null;\n private components: ResolvedComponent[] = [];\n private generatedFiles: Map<string, GeneratedFile[]> = new Map();\n private generators: GeneratorPlugin[] = [];\n private cwd: string;\n private configPath?: string;\n\n constructor(cwd: string, configPath?: string) {\n this.cwd = cwd;\n this.configPath = configPath;\n }\n\n async initialBuild(): Promise<void> {\n await this.rebuild();\n }\n\n async rebuild(): Promise<void> {\n const configFile = this.configPath ?? 'ryndesign.config.ts';\n\n const tokens = ['tokens/**/*.tokens.json'];\n const componentPatterns = ['components/**/*.component.json'];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let themes: any = undefined;\n\n try {\n const configPath = path.resolve(this.cwd, configFile);\n const content = await fs.readFile(configPath, 'utf-8');\n if (content.includes('dark')) {\n themes = {\n default: 'light',\n dark: { file: path.resolve(this.cwd, 'tokens/dark.tokens.json') },\n };\n }\n } catch {\n // Use defaults\n }\n\n this.tokenSet = await buildTokenSet({\n tokens,\n basePath: this.cwd,\n themes,\n });\n\n // Load and resolve components\n try {\n const componentDefs = await loadComponents(componentPatterns, this.cwd);\n this.components = componentDefs.map(def => resolveComponent(def, this.tokenSet!));\n } catch {\n this.components = [];\n }\n }\n\n getTokenSet(): ResolvedTokenSet | null {\n return this.tokenSet;\n }\n\n getThemes(): Record<string, unknown> {\n if (!this.tokenSet) return {};\n return {\n default: this.tokenSet.themes.default,\n available: Object.keys(this.tokenSet.themes.themes),\n themes: this.tokenSet.themes.themes,\n };\n }\n\n getThemeTokens(theme: string): Record<string, unknown> {\n if (!this.tokenSet) return {};\n const themeData = this.tokenSet.themes.themes[theme];\n if (!themeData) return {};\n return {\n name: themeData.name,\n tokens: themeData.tokens,\n };\n }\n\n getComponents(): ResolvedComponent[] {\n return this.components;\n }\n\n setGenerators(generators: GeneratorPlugin[]): void {\n this.generators = generators;\n }\n\n async generateSnippets(platform: string, componentName?: string, type?: string): Promise<string> {\n if (!this.tokenSet) return '';\n\n const generator = this.generators.find(g => g.name === platform);\n if (!generator) return `// Generator for \"${platform}\" not available`;\n\n const { createGeneratorHelpers } = await import('@ryndesign/core');\n const ctx = {\n tokenSet: this.tokenSet,\n config: { outDir: 'generated' },\n outputDir: path.resolve(this.cwd, 'generated'),\n helpers: createGeneratorHelpers(),\n components: this.components,\n };\n\n try {\n if (type === 'tokens') {\n const files = await generator.generateTokens(ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n\n if (componentName) {\n const comp = this.components.find(c => c.definition.name === componentName);\n if (comp) {\n const files = await generator.generateComponent(comp, ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n return `// Component \"${componentName}\" not found`;\n }\n\n return '// Specify a component or type=tokens';\n } catch (err) {\n return `// Error: ${(err as Error).message}`;\n }\n }\n\n getGeneratedFiles(platform?: string): GeneratedFile[] {\n if (!platform) {\n return Array.from(this.generatedFiles.values()).flat();\n }\n return this.generatedFiles.get(platform) ?? [];\n }\n\n async updateToken(tokenPath: string, value: unknown, theme?: string): Promise<void> {\n const filePath = theme\n ? path.resolve(this.cwd, `tokens/${theme}.tokens.json`)\n : path.resolve(this.cwd, 'tokens/semantic.tokens.json');\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const tree = JSON.parse(content) as RawTokenTree;\n\n const parts = tokenPath.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]];\n }\n\n const lastKey = parts[parts.length - 1];\n if (current[lastKey] && typeof current[lastKey] === 'object' && '$value' in current[lastKey]) {\n current[lastKey].$value = value;\n } else {\n current[lastKey] = { $type: 'color', $value: value };\n }\n\n await fs.writeFile(filePath, JSON.stringify(tree, null, 2), 'utf-8');\n await this.rebuild();\n } catch (err) {\n console.error(`Failed to update token: ${(err as Error).message}`);\n throw err;\n }\n }\n}\n"],"mappings":"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","names":["path","path","path","path"]}
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.5.4/node_modules/tsup/assets/esm_shims.js","../src/server/index.ts","../src/server/api-routes.ts","../src/server/ws-handler.ts","../src/server/watcher.ts","../src/server/incremental-build.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import { createServer as createViteServer } from 'vite';\nimport { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport net from 'node:net';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { setupApiRoutes } from './api-routes.js';\nimport { setupWsHandler } from './ws-handler.js';\nimport { setupWatcher } from './watcher.js';\nimport { IncrementalBuilder } from './incremental-build.js';\n\nexport interface PreviewServerOptions {\n port?: number;\n open?: boolean;\n configPath?: string;\n generators?: unknown[];\n}\n\nfunction isPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const tester = net.createServer()\n .once('error', () => resolve(true))\n .once('listening', () => {\n tester.close();\n resolve(false);\n })\n .listen(port);\n });\n}\n\nfunction killProcessOnPort(port: number): boolean {\n try {\n if (process.platform === 'win32') {\n const result = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf-8' });\n const pid = result.trim().split(/\\s+/).pop();\n if (pid) {\n execSync(`taskkill /PID ${pid} /F`);\n return true;\n }\n } else {\n execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: 'pipe' });\n return true;\n }\n } catch {\n // No process found or kill failed\n }\n return false;\n}\n\nexport async function startPreviewServer(options: PreviewServerOptions = {}): Promise<void> {\n const port = options.port ?? 4400;\n const cwd = process.cwd();\n\n // Check if port is in use\n if (await isPortInUse(port)) {\n const isTTY = process.stdin.isTTY && process.stdout.isTTY;\n\n if (isTTY) {\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => {\n rl.question(`\\n Port ${port} is already in use. Kill the existing process and restart? (y/N) `, resolve);\n });\n rl.close();\n\n if (answer.toLowerCase() === 'y') {\n if (killProcessOnPort(port)) {\n console.log(` Killed process on port ${port}.`);\n await new Promise(r => setTimeout(r, 500));\n } else {\n console.error(` Could not kill process on port ${port}.`);\n process.exit(1);\n }\n } else {\n console.log(' Aborted.');\n process.exit(0);\n }\n } else {\n console.error(`\\n Port ${port} is already in use. Use --port to specify a different port.`);\n process.exit(1);\n }\n }\n\n // Initialize incremental builder\n const builder = new IncrementalBuilder(cwd, options.configPath);\n if (options.generators && options.generators.length > 0) {\n builder.setGenerators(options.generators as import('@ryndesign/plugin-api').GeneratorPlugin[]);\n }\n await builder.initialBuild();\n\n // Create HTTP server\n const server = http.createServer();\n\n // Setup preview WebSocket in noServer mode to avoid Vite HMR conflict\n const wss = new WebSocketServer({ noServer: true });\n setupWsHandler(wss, builder);\n\n // Create Vite dev server for client SPA\n let reactPlugin;\n try {\n const mod = await import('@vitejs/plugin-react');\n reactPlugin = (mod.default ?? mod)();\n } catch {\n // Plugin not available, proceed without it\n }\n\n const vite = await createViteServer({\n root: path.resolve(__dirname, '../client'),\n server: {\n middlewareMode: true,\n hmr: { server },\n },\n plugins: reactPlugin ? [reactPlugin] : [],\n appType: 'spa',\n });\n\n // Route WebSocket upgrades: /ws → preview, everything else → Vite HMR\n server.on('upgrade', (req, socket, head) => {\n if (req.url === '/ws') {\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit('connection', ws, req);\n });\n }\n // Other upgrade requests (Vite HMR) are handled by Vite automatically\n });\n\n // Setup API routes\n const apiHandler = setupApiRoutes(builder);\n\n // Handle requests\n server.on('request', (req, res) => {\n if (req.url?.startsWith('/api/')) {\n apiHandler(req, res);\n } else {\n vite.middlewares(req, res);\n }\n });\n\n // Setup file watcher\n setupWatcher(builder, wss, cwd);\n\n // Start server\n server.listen(port, () => {\n console.log(`\\n 🎨 RynDesign Preview`);\n console.log(` ➜ Local: http://localhost:${port}/`);\n console.log(` ➜ WS: ws://localhost:${port}/ws\\n`);\n\n if (options.open) {\n import('child_process').then(cp => {\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n cp.exec(`${cmd} http://localhost:${port}/`);\n }).catch(() => {});\n }\n });\n\n // Graceful shutdown\n process.on('SIGINT', () => {\n wss.close();\n vite.close();\n server.close();\n process.exit(0);\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\ntype RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;\n\nexport function setupApiRoutes(builder: IncrementalBuilder): RequestHandler {\n return (req, res) => {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const pathname = url.pathname;\n\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n if (pathname === '/api/tokens' && req.method === 'GET') {\n json(res, builder.getTokenSet());\n } else if (pathname === '/api/themes' && req.method === 'GET') {\n json(res, builder.getThemes());\n } else if (pathname === '/api/components' && req.method === 'GET') {\n json(res, builder.getComponents());\n } else if (pathname === '/api/snippets' && req.method === 'GET') {\n const platform = url.searchParams.get('platform') ?? 'react';\n const component = url.searchParams.get('component') ?? undefined;\n const type = url.searchParams.get('type') ?? undefined;\n builder.generateSnippets(platform, component, type).then(code => {\n json(res, { code });\n }).catch(err => {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n });\n return; // async handling\n } else if (pathname === '/api/tokens' && req.method === 'PUT') {\n let body = '';\n req.on('data', chunk => { body += chunk; });\n req.on('end', async () => {\n const { path, value, theme } = JSON.parse(body);\n await builder.updateToken(path, value, theme);\n json(res, { success: true });\n });\n } else if (pathname === '/api/generated' && req.method === 'GET') {\n const platform = url.searchParams.get('platform');\n json(res, builder.getGeneratedFiles(platform ?? undefined));\n } else {\n res.writeHead(404);\n json(res, { error: 'Not found' });\n }\n } catch (err) {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n }\n };\n}\n\nfunction json(res: ServerResponse, data: unknown): void {\n if (!res.headersSent) {\n res.setHeader('Content-Type', 'application/json');\n }\n res.end(JSON.stringify(data));\n}\n","import type { WebSocketServer, WebSocket } from 'ws';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport interface WsMessage {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface TokenUpdateMessage extends WsMessage {\n type: 'token-update';\n theme?: string;\n path: string;\n value: unknown;\n}\n\nexport interface ThemeChangeMessage extends WsMessage {\n type: 'theme-change';\n theme: string;\n}\n\nexport interface RebuildCompleteMessage extends WsMessage {\n type: 'rebuild-complete';\n changedTokens: string[];\n timestamp: number;\n}\n\nexport function setupWsHandler(wss: WebSocketServer, builder: IncrementalBuilder): void {\n wss.on('connection', (ws: WebSocket) => {\n console.log('Preview client connected');\n\n // Send initial state\n ws.send(JSON.stringify({\n type: 'init',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n\n ws.on('message', async (data: Buffer) => {\n try {\n const message = JSON.parse(data.toString()) as WsMessage;\n\n switch (message.type) {\n case 'token-update': {\n const update = message as TokenUpdateMessage;\n await builder.updateToken(update.path, update.value, update.theme);\n\n // Broadcast rebuild complete to all clients\n broadcast(wss, {\n type: 'rebuild-complete',\n changedTokens: [update.path],\n timestamp: Date.now(),\n tokenSet: builder.getTokenSet(),\n components: builder.getComponents(),\n });\n break;\n }\n\n case 'theme-change': {\n const themeMsg = message as ThemeChangeMessage;\n broadcast(wss, {\n type: 'theme-switched',\n theme: themeMsg.theme,\n tokens: builder.getThemeTokens(themeMsg.theme),\n });\n break;\n }\n\n case 'request-state': {\n ws.send(JSON.stringify({\n type: 'full-state',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n break;\n }\n }\n } catch (err) {\n ws.send(JSON.stringify({\n type: 'error',\n message: (err as Error).message,\n }));\n }\n });\n\n ws.on('close', () => {\n console.log('Preview client disconnected');\n });\n });\n}\n\nfunction broadcast(wss: WebSocketServer, message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n for (const client of wss.clients) {\n if (client.readyState === 1) { // WebSocket.OPEN\n client.send(data);\n }\n }\n}\n","import type { WebSocketServer } from 'ws';\nimport { watch } from 'chokidar';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport function setupWatcher(\n builder: IncrementalBuilder,\n wss: WebSocketServer,\n cwd: string\n): void {\n const watcher = watch(\n ['tokens/**/*.tokens.json', 'components/**/*.component.json'],\n {\n cwd,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 300,\n pollInterval: 50,\n },\n }\n );\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const handleChange = (changedPath: string) => {\n if (debounceTimer) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(async () => {\n console.log(`File changed: ${changedPath}`);\n\n try {\n await builder.rebuild();\n\n // Broadcast to all connected clients\n const data = JSON.stringify({\n type: 'rebuild-complete',\n changedTokens: [],\n timestamp: Date.now(),\n tokenSet: builder.getTokenSet(),\n components: builder.getComponents(),\n });\n\n for (const client of wss.clients) {\n if (client.readyState === 1) {\n client.send(data);\n }\n }\n } catch (err) {\n console.error('Rebuild failed:', (err as Error).message);\n }\n }, 300);\n };\n\n watcher.on('change', handleChange);\n watcher.on('add', handleChange);\n watcher.on('unlink', handleChange);\n}\n","import { buildTokenSet, loadComponents, resolveComponent, type RawTokenTree } from '@ryndesign/core';\nimport type { ResolvedTokenSet, GeneratedFile, ResolvedComponent, GeneratorPlugin } from '@ryndesign/plugin-api';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport class IncrementalBuilder {\n private tokenSet: ResolvedTokenSet | null = null;\n private components: ResolvedComponent[] = [];\n private generatedFiles: Map<string, GeneratedFile[]> = new Map();\n private generators: GeneratorPlugin[] = [];\n private cwd: string;\n private configPath?: string;\n\n constructor(cwd: string, configPath?: string) {\n this.cwd = cwd;\n this.configPath = configPath;\n }\n\n async initialBuild(): Promise<void> {\n await this.rebuild();\n }\n\n async rebuild(): Promise<void> {\n const configFile = this.configPath ?? 'ryndesign.config.ts';\n\n const tokens = ['tokens/**/*.tokens.json'];\n const componentPatterns = ['components/**/*.component.json'];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let themes: any = undefined;\n\n try {\n const configPath = path.resolve(this.cwd, configFile);\n const content = await fs.readFile(configPath, 'utf-8');\n if (content.includes('dark')) {\n themes = {\n default: 'light',\n dark: { file: path.resolve(this.cwd, 'tokens/dark.tokens.json') },\n };\n }\n } catch {\n // Use defaults\n }\n\n this.tokenSet = await buildTokenSet({\n tokens,\n basePath: this.cwd,\n themes,\n });\n\n // Load and resolve components\n try {\n const componentDefs = await loadComponents(componentPatterns, this.cwd);\n this.components = componentDefs.map(def => resolveComponent(def, this.tokenSet!));\n } catch {\n this.components = [];\n }\n }\n\n getTokenSet(): ResolvedTokenSet | null {\n return this.tokenSet;\n }\n\n getThemes(): Record<string, unknown> {\n if (!this.tokenSet) return {};\n return {\n default: this.tokenSet.themes.default,\n available: Object.keys(this.tokenSet.themes.themes),\n themes: this.tokenSet.themes.themes,\n };\n }\n\n getThemeTokens(theme: string): Record<string, unknown> {\n if (!this.tokenSet) return {};\n const themeData = this.tokenSet.themes.themes[theme];\n if (!themeData) return {};\n return {\n name: themeData.name,\n tokens: themeData.tokens,\n };\n }\n\n getComponents(): ResolvedComponent[] {\n return this.components;\n }\n\n setGenerators(generators: GeneratorPlugin[]): void {\n this.generators = generators;\n }\n\n async generateSnippets(platform: string, componentName?: string, type?: string): Promise<string> {\n if (!this.tokenSet) return '';\n\n const generator = this.generators.find(g => g.name === platform);\n if (!generator) return `// Generator for \"${platform}\" not available`;\n\n const { createGeneratorHelpers } = await import('@ryndesign/core');\n const ctx = {\n tokenSet: this.tokenSet,\n config: { outDir: 'generated' },\n outputDir: path.resolve(this.cwd, 'generated'),\n helpers: createGeneratorHelpers(),\n components: this.components,\n };\n\n try {\n if (type === 'tokens') {\n const files = await generator.generateTokens(ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n\n if (componentName) {\n const comp = this.components.find(c => c.definition.name === componentName);\n if (comp) {\n const files = await generator.generateComponent(comp, ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n return `// Component \"${componentName}\" not found`;\n }\n\n return '// Specify a component or type=tokens';\n } catch (err) {\n return `// Error: ${(err as Error).message}`;\n }\n }\n\n getGeneratedFiles(platform?: string): GeneratedFile[] {\n if (!platform) {\n return Array.from(this.generatedFiles.values()).flat();\n }\n return this.generatedFiles.get(platform) ?? [];\n }\n\n async updateToken(tokenPath: string, value: unknown, theme?: string): Promise<void> {\n const filePath = theme\n ? path.resolve(this.cwd, `tokens/${theme}.tokens.json`)\n : path.resolve(this.cwd, 'tokens/semantic.tokens.json');\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const tree = JSON.parse(content) as RawTokenTree;\n\n const parts = tokenPath.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]];\n }\n\n const lastKey = parts[parts.length - 1];\n if (current[lastKey] && typeof current[lastKey] === 'object' && '$value' in current[lastKey]) {\n current[lastKey].$value = value;\n } else {\n current[lastKey] = { $type: 'color', $value: value };\n }\n\n await fs.writeFile(filePath, JSON.stringify(tree, null, 2), 'utf-8');\n await this.rebuild();\n } catch (err) {\n console.error(`Failed to update token: ${(err as Error).message}`);\n throw err;\n }\n }\n}\n"],"mappings":"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","names":["path","path","path","path"]}
|