Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
AI-powered design system generator that produces complete, tailored design systems from project requirements.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/generate-tokens.cjs
1#!/usr/bin/env node2/**3* Generate CSS variables from design tokens JSON4*5* Usage:6* node generate-tokens.cjs --config tokens.json -o tokens.css7* node generate-tokens.cjs --config tokens.json --format tailwind8*/910const fs = require('fs');11const path = require('path');1213/**14* Parse command line arguments15*/16function parseArgs() {17const args = process.argv.slice(2);18const options = {19config: null,20output: null,21format: 'css' // css | tailwind22};2324for (let i = 0; i < args.length; i++) {25if (args[i] === '--config' || args[i] === '-c') {26options.config = args[++i];27} else if (args[i] === '--output' || args[i] === '-o') {28options.output = args[++i];29} else if (args[i] === '--format' || args[i] === '-f') {30options.format = args[++i];31} else if (args[i] === '--help' || args[i] === '-h') {32console.log(`33Usage: node generate-tokens.cjs [options]3435Options:36-c, --config <file> Input JSON token file (required)37-o, --output <file> Output file (default: stdout)38-f, --format <type> Output format: css | tailwind (default: css)39-h, --help Show this help40`);41process.exit(0);42}43}4445return options;46}4748/**49* Resolve token references like {primitive.color.blue.600}50*/51function resolveReference(value, tokens) {52if (typeof value !== 'string' || !value.startsWith('{')) {53return value;54}5556const path = value.slice(1, -1).split('.');57let result = tokens;5859for (const key of path) {60result = result?.[key];61}6263if (result?.$value) {64return resolveReference(result.$value, tokens);65}6667return result || value;68}6970/**71* Convert token name to CSS variable name72*/73function toCssVarName(path) {74return '--' + path.join('-').replace(/\./g, '-');75}7677/**78* Flatten tokens into CSS variables79*/80function flattenTokens(obj, tokens, prefix = [], result = {}) {81for (const [key, value] of Object.entries(obj)) {82const currentPath = [...prefix, key];8384if (value && typeof value === 'object') {85if (value.$value !== undefined) {86// This is a token87const cssVar = toCssVarName(currentPath);88const resolvedValue = resolveReference(value.$value, tokens);89result[cssVar] = resolvedValue;90} else {91// Recurse into nested object92flattenTokens(value, tokens, currentPath, result);93}94}95}9697return result;98}99100/**101* Generate CSS output102*/103function generateCSS(tokens) {104const primitive = flattenTokens(tokens.primitive || {}, tokens, ['primitive']);105const semantic = flattenTokens(tokens.semantic || {}, tokens, []);106const component = flattenTokens(tokens.component || {}, tokens, []);107const darkSemantic = flattenTokens(tokens.dark?.semantic || {}, tokens, []);108109let css = `/* Design Tokens - Auto-generated */110/* Do not edit directly - modify tokens.json instead */111112/* === PRIMITIVES === */113:root {114${Object.entries(primitive).map(([k, v]) => ` ${k}: ${v};`).join('\n')}115}116117/* === SEMANTIC === */118:root {119${Object.entries(semantic).map(([k, v]) => ` ${k}: ${v};`).join('\n')}120}121122/* === COMPONENTS === */123:root {124${Object.entries(component).map(([k, v]) => ` ${k}: ${v};`).join('\n')}125}126`;127128if (Object.keys(darkSemantic).length > 0) {129css += `130/* === DARK MODE === */131.dark {132${Object.entries(darkSemantic).map(([k, v]) => ` ${k}: ${v};`).join('\n')}133}134`;135}136137return css;138}139140/**141* Generate Tailwind config output142*/143function generateTailwind(tokens) {144const semantic = flattenTokens(tokens.semantic || {}, tokens, []);145146// Extract colors for Tailwind147const colors = {};148for (const [key, value] of Object.entries(semantic)) {149if (key.includes('color')) {150const name = key.replace('--color-', '').replace(/-/g, '.');151colors[name] = `var(${key})`;152}153}154155return `// Tailwind color config - Auto-generated156// Add to tailwind.config.ts theme.extend.colors157158module.exports = {159colors: ${JSON.stringify(colors, null, 2).replace(/"/g, "'")}160};161`;162}163164/**165* Main166*/167function main() {168const options = parseArgs();169170if (!options.config) {171console.error('Error: --config is required');172process.exit(1);173}174175// Resolve config path176const configPath = path.resolve(process.cwd(), options.config);177178if (!fs.existsSync(configPath)) {179console.error(`Error: Config file not found: ${configPath}`);180process.exit(1);181}182183// Read and parse tokens184const tokens = JSON.parse(fs.readFileSync(configPath, 'utf-8'));185186// Generate output187let output;188if (options.format === 'tailwind') {189output = generateTailwind(tokens);190} else {191output = generateCSS(tokens);192}193194// Write output195if (options.output) {196const outputPath = path.resolve(process.cwd(), options.output);197fs.mkdirSync(path.dirname(outputPath), { recursive: true });198fs.writeFileSync(outputPath, output);199console.log(`Generated: ${outputPath}`);200} else {201console.log(output);202}203}204205main();206