@ryndesign/preview 0.1.2 → 0.1.4
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/hooks/useWebSocket.ts +1 -1
- package/dist/index.cjs +64 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +80 -11
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -48,7 +48,7 @@ export function useWebSocket() {
|
|
|
48
48
|
useEffect(() => {
|
|
49
49
|
function connect() {
|
|
50
50
|
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
51
|
-
const ws = new WebSocket(`${protocol}//${location.host}`);
|
|
51
|
+
const ws = new WebSocket(`${protocol}//${location.host}/ws`);
|
|
52
52
|
wsRef.current = ws;
|
|
53
53
|
|
|
54
54
|
ws.onopen = () => {
|
package/dist/index.cjs
CHANGED
|
@@ -38,7 +38,9 @@ module.exports = __toCommonJS(index_exports);
|
|
|
38
38
|
var import_vite = require("vite");
|
|
39
39
|
var import_ws = require("ws");
|
|
40
40
|
var import_node_http = __toESM(require("http"), 1);
|
|
41
|
+
var import_node_net = __toESM(require("net"), 1);
|
|
41
42
|
var import_node_path2 = __toESM(require("path"), 1);
|
|
43
|
+
var import_node_child_process = require("child_process");
|
|
42
44
|
|
|
43
45
|
// src/server/api-routes.ts
|
|
44
46
|
function setupApiRoutes(builder) {
|
|
@@ -345,13 +347,66 @@ ${f.content}`).join("\n\n");
|
|
|
345
347
|
};
|
|
346
348
|
|
|
347
349
|
// src/server/index.ts
|
|
350
|
+
function isPortInUse(port) {
|
|
351
|
+
return new Promise((resolve) => {
|
|
352
|
+
const tester = import_node_net.default.createServer().once("error", () => resolve(true)).once("listening", () => {
|
|
353
|
+
tester.close();
|
|
354
|
+
resolve(false);
|
|
355
|
+
}).listen(port);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
function killProcessOnPort(port) {
|
|
359
|
+
try {
|
|
360
|
+
if (process.platform === "win32") {
|
|
361
|
+
const result = (0, import_node_child_process.execSync)(`netstat -ano | findstr :${port}`, { encoding: "utf-8" });
|
|
362
|
+
const pid = result.trim().split(/\s+/).pop();
|
|
363
|
+
if (pid) {
|
|
364
|
+
(0, import_node_child_process.execSync)(`taskkill /PID ${pid} /F`);
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
(0, import_node_child_process.execSync)(`lsof -ti:${port} | xargs kill -9`, { stdio: "pipe" });
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
} catch {
|
|
372
|
+
}
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
348
375
|
async function startPreviewServer(options = {}) {
|
|
349
376
|
const port = options.port ?? 4400;
|
|
350
377
|
const cwd = process.cwd();
|
|
378
|
+
if (await isPortInUse(port)) {
|
|
379
|
+
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
380
|
+
if (isTTY) {
|
|
381
|
+
const readline = await import("readline");
|
|
382
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
383
|
+
const answer = await new Promise((resolve) => {
|
|
384
|
+
rl.question(`
|
|
385
|
+
Port ${port} is already in use. Kill the existing process and restart? (y/N) `, resolve);
|
|
386
|
+
});
|
|
387
|
+
rl.close();
|
|
388
|
+
if (answer.toLowerCase() === "y") {
|
|
389
|
+
if (killProcessOnPort(port)) {
|
|
390
|
+
console.log(` Killed process on port ${port}.`);
|
|
391
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
392
|
+
} else {
|
|
393
|
+
console.error(` Could not kill process on port ${port}.`);
|
|
394
|
+
process.exit(1);
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
console.log(" Aborted.");
|
|
398
|
+
process.exit(0);
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
console.error(`
|
|
402
|
+
Port ${port} is already in use. Use --port to specify a different port.`);
|
|
403
|
+
process.exit(1);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
351
406
|
const builder = new IncrementalBuilder(cwd, options.configPath);
|
|
352
407
|
await builder.initialBuild();
|
|
353
408
|
const server = import_node_http.default.createServer();
|
|
354
|
-
const wss = new import_ws.WebSocketServer({
|
|
409
|
+
const wss = new import_ws.WebSocketServer({ noServer: true });
|
|
355
410
|
setupWsHandler(wss, builder);
|
|
356
411
|
let reactPlugin;
|
|
357
412
|
try {
|
|
@@ -368,6 +423,13 @@ async function startPreviewServer(options = {}) {
|
|
|
368
423
|
plugins: reactPlugin ? [reactPlugin] : [],
|
|
369
424
|
appType: "spa"
|
|
370
425
|
});
|
|
426
|
+
server.on("upgrade", (req, socket, head) => {
|
|
427
|
+
if (req.url === "/ws") {
|
|
428
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
429
|
+
wss.emit("connection", ws, req);
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
});
|
|
371
433
|
const apiHandler = setupApiRoutes(builder);
|
|
372
434
|
server.on("request", (req, res) => {
|
|
373
435
|
if (req.url?.startsWith("/api/")) {
|
|
@@ -381,7 +443,7 @@ async function startPreviewServer(options = {}) {
|
|
|
381
443
|
console.log(`
|
|
382
444
|
\u{1F3A8} RynDesign Preview`);
|
|
383
445
|
console.log(` \u279C Local: http://localhost:${port}/`);
|
|
384
|
-
console.log(` \u279C WS: ws://localhost:${port}/
|
|
446
|
+
console.log(` \u279C WS: ws://localhost:${port}/ws
|
|
385
447
|
`);
|
|
386
448
|
if (options.open) {
|
|
387
449
|
import("child_process").then((cp) => {
|
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 path from 'node:path';\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}\n\nexport async function startPreviewServer(options: PreviewServerOptions = {}): Promise<void> {\n const port = options.port ?? 4400;\n const cwd = process.cwd();\n\n // Initialize incremental builder\n const builder = new IncrementalBuilder(cwd, options.configPath);\n await builder.initialBuild();\n\n // Create HTTP server\n const server = http.createServer();\n\n // Setup WebSocket\n const wss = new WebSocketServer({ server });\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 // 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}/\\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","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}\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 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"]}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
// ../../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
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
var getFilename = () => fileURLToPath(import.meta.url);
|
|
5
|
+
var getDirname = () => path.dirname(getFilename());
|
|
6
|
+
var __dirname = /* @__PURE__ */ getDirname();
|
|
7
|
+
|
|
1
8
|
// src/server/index.ts
|
|
2
9
|
import { createServer as createViteServer } from "vite";
|
|
3
10
|
import { WebSocketServer } from "ws";
|
|
4
11
|
import http from "http";
|
|
5
|
-
import
|
|
12
|
+
import net from "net";
|
|
13
|
+
import path3 from "path";
|
|
14
|
+
import { execSync } from "child_process";
|
|
6
15
|
|
|
7
16
|
// src/server/api-routes.ts
|
|
8
17
|
function setupApiRoutes(builder) {
|
|
@@ -41,8 +50,8 @@ function setupApiRoutes(builder) {
|
|
|
41
50
|
body += chunk;
|
|
42
51
|
});
|
|
43
52
|
req.on("end", async () => {
|
|
44
|
-
const { path:
|
|
45
|
-
await builder.updateToken(
|
|
53
|
+
const { path: path4, value, theme } = JSON.parse(body);
|
|
54
|
+
await builder.updateToken(path4, value, theme);
|
|
46
55
|
json(res, { success: true });
|
|
47
56
|
});
|
|
48
57
|
} else if (pathname === "/api/generated" && req.method === "GET") {
|
|
@@ -175,7 +184,7 @@ function setupWatcher(builder, wss, cwd) {
|
|
|
175
184
|
// src/server/incremental-build.ts
|
|
176
185
|
import { buildTokenSet, loadComponents, resolveComponent } from "@ryndesign/core";
|
|
177
186
|
import fs from "fs/promises";
|
|
178
|
-
import
|
|
187
|
+
import path2 from "path";
|
|
179
188
|
var IncrementalBuilder = class {
|
|
180
189
|
tokenSet = null;
|
|
181
190
|
components = [];
|
|
@@ -196,12 +205,12 @@ var IncrementalBuilder = class {
|
|
|
196
205
|
const componentPatterns = ["components/**/*.component.json"];
|
|
197
206
|
let themes = void 0;
|
|
198
207
|
try {
|
|
199
|
-
const configPath =
|
|
208
|
+
const configPath = path2.resolve(this.cwd, configFile);
|
|
200
209
|
const content = await fs.readFile(configPath, "utf-8");
|
|
201
210
|
if (content.includes("dark")) {
|
|
202
211
|
themes = {
|
|
203
212
|
default: "light",
|
|
204
|
-
dark: { file:
|
|
213
|
+
dark: { file: path2.resolve(this.cwd, "tokens/dark.tokens.json") }
|
|
205
214
|
};
|
|
206
215
|
}
|
|
207
216
|
} catch {
|
|
@@ -252,7 +261,7 @@ var IncrementalBuilder = class {
|
|
|
252
261
|
const ctx = {
|
|
253
262
|
tokenSet: this.tokenSet,
|
|
254
263
|
config: { outDir: "generated" },
|
|
255
|
-
outputDir:
|
|
264
|
+
outputDir: path2.resolve(this.cwd, "generated"),
|
|
256
265
|
helpers: createGeneratorHelpers(),
|
|
257
266
|
components: this.components
|
|
258
267
|
};
|
|
@@ -283,7 +292,7 @@ ${f.content}`).join("\n\n");
|
|
|
283
292
|
return this.generatedFiles.get(platform) ?? [];
|
|
284
293
|
}
|
|
285
294
|
async updateToken(tokenPath, value, theme) {
|
|
286
|
-
const filePath = theme ?
|
|
295
|
+
const filePath = theme ? path2.resolve(this.cwd, `tokens/${theme}.tokens.json`) : path2.resolve(this.cwd, "tokens/semantic.tokens.json");
|
|
287
296
|
try {
|
|
288
297
|
const content = await fs.readFile(filePath, "utf-8");
|
|
289
298
|
const tree = JSON.parse(content);
|
|
@@ -309,13 +318,66 @@ ${f.content}`).join("\n\n");
|
|
|
309
318
|
};
|
|
310
319
|
|
|
311
320
|
// src/server/index.ts
|
|
321
|
+
function isPortInUse(port) {
|
|
322
|
+
return new Promise((resolve) => {
|
|
323
|
+
const tester = net.createServer().once("error", () => resolve(true)).once("listening", () => {
|
|
324
|
+
tester.close();
|
|
325
|
+
resolve(false);
|
|
326
|
+
}).listen(port);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
function killProcessOnPort(port) {
|
|
330
|
+
try {
|
|
331
|
+
if (process.platform === "win32") {
|
|
332
|
+
const result = execSync(`netstat -ano | findstr :${port}`, { encoding: "utf-8" });
|
|
333
|
+
const pid = result.trim().split(/\s+/).pop();
|
|
334
|
+
if (pid) {
|
|
335
|
+
execSync(`taskkill /PID ${pid} /F`);
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: "pipe" });
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
} catch {
|
|
343
|
+
}
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
312
346
|
async function startPreviewServer(options = {}) {
|
|
313
347
|
const port = options.port ?? 4400;
|
|
314
348
|
const cwd = process.cwd();
|
|
349
|
+
if (await isPortInUse(port)) {
|
|
350
|
+
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
351
|
+
if (isTTY) {
|
|
352
|
+
const readline = await import("readline");
|
|
353
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
354
|
+
const answer = await new Promise((resolve) => {
|
|
355
|
+
rl.question(`
|
|
356
|
+
Port ${port} is already in use. Kill the existing process and restart? (y/N) `, resolve);
|
|
357
|
+
});
|
|
358
|
+
rl.close();
|
|
359
|
+
if (answer.toLowerCase() === "y") {
|
|
360
|
+
if (killProcessOnPort(port)) {
|
|
361
|
+
console.log(` Killed process on port ${port}.`);
|
|
362
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
363
|
+
} else {
|
|
364
|
+
console.error(` Could not kill process on port ${port}.`);
|
|
365
|
+
process.exit(1);
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
console.log(" Aborted.");
|
|
369
|
+
process.exit(0);
|
|
370
|
+
}
|
|
371
|
+
} else {
|
|
372
|
+
console.error(`
|
|
373
|
+
Port ${port} is already in use. Use --port to specify a different port.`);
|
|
374
|
+
process.exit(1);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
315
377
|
const builder = new IncrementalBuilder(cwd, options.configPath);
|
|
316
378
|
await builder.initialBuild();
|
|
317
379
|
const server = http.createServer();
|
|
318
|
-
const wss = new WebSocketServer({
|
|
380
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
319
381
|
setupWsHandler(wss, builder);
|
|
320
382
|
let reactPlugin;
|
|
321
383
|
try {
|
|
@@ -324,7 +386,7 @@ async function startPreviewServer(options = {}) {
|
|
|
324
386
|
} catch {
|
|
325
387
|
}
|
|
326
388
|
const vite = await createViteServer({
|
|
327
|
-
root:
|
|
389
|
+
root: path3.resolve(__dirname, "../client"),
|
|
328
390
|
server: {
|
|
329
391
|
middlewareMode: true,
|
|
330
392
|
hmr: { server }
|
|
@@ -332,6 +394,13 @@ async function startPreviewServer(options = {}) {
|
|
|
332
394
|
plugins: reactPlugin ? [reactPlugin] : [],
|
|
333
395
|
appType: "spa"
|
|
334
396
|
});
|
|
397
|
+
server.on("upgrade", (req, socket, head) => {
|
|
398
|
+
if (req.url === "/ws") {
|
|
399
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
400
|
+
wss.emit("connection", ws, req);
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
});
|
|
335
404
|
const apiHandler = setupApiRoutes(builder);
|
|
336
405
|
server.on("request", (req, res) => {
|
|
337
406
|
if (req.url?.startsWith("/api/")) {
|
|
@@ -345,7 +414,7 @@ async function startPreviewServer(options = {}) {
|
|
|
345
414
|
console.log(`
|
|
346
415
|
\u{1F3A8} RynDesign Preview`);
|
|
347
416
|
console.log(` \u279C Local: http://localhost:${port}/`);
|
|
348
|
-
console.log(` \u279C WS: ws://localhost:${port}/
|
|
417
|
+
console.log(` \u279C WS: ws://localhost:${port}/ws
|
|
349
418
|
`);
|
|
350
419
|
if (options.open) {
|
|
351
420
|
import("child_process").then((cp) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/index.ts","../src/server/api-routes.ts","../src/server/ws-handler.ts","../src/server/watcher.ts","../src/server/incremental-build.ts"],"sourcesContent":["import { createServer as createViteServer } from 'vite';\nimport { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport path from 'node:path';\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}\n\nexport async function startPreviewServer(options: PreviewServerOptions = {}): Promise<void> {\n const port = options.port ?? 4400;\n const cwd = process.cwd();\n\n // Initialize incremental builder\n const builder = new IncrementalBuilder(cwd, options.configPath);\n await builder.initialBuild();\n\n // Create HTTP server\n const server = http.createServer();\n\n // Setup WebSocket\n const wss = new WebSocketServer({ server });\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 // 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}/\\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"]}
|
|
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}\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 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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryndesign/preview",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Preview server for RynDesign design system",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"react-dom": "^19.2.4",
|
|
37
37
|
"vite": "^8.0.0",
|
|
38
38
|
"ws": "^8.18.0",
|
|
39
|
-
"@ryndesign/
|
|
40
|
-
"@ryndesign/
|
|
39
|
+
"@ryndesign/core": "0.1.1",
|
|
40
|
+
"@ryndesign/plugin-api": "0.1.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/react": "^19.2.14",
|