/ scripts / update-brand-book.js
update-brand-book.js
  1  #!/usr/bin/env node
  2  /**
  3   * Update Brand Book
  4   *
  5   * Automatically updates the brand-book/index.html with current token values
  6   * from src/tokens/index.ts
  7   *
  8   * Run: node scripts/update-brand-book.js
  9   */
 10  
 11  import { readFileSync, writeFileSync } from 'fs';
 12  import { resolve, dirname } from 'path';
 13  import { fileURLToPath } from 'url';
 14  
 15  const __dirname = dirname(fileURLToPath(import.meta.url));
 16  const ROOT = resolve(__dirname, '..');
 17  
 18  // Read tokens from TypeScript file
 19  const tokensPath = resolve(ROOT, 'src/tokens/index.ts');
 20  const tokensContent = readFileSync(tokensPath, 'utf-8');
 21  
 22  // Extract color values using regex
 23  function extractColors(content) {
 24    const colors = { alpha: {}, delta: {} };
 25  
 26    // Match alpha colors
 27    const alphaMatch = content.match(/alpha:\s*\{([^}]+)\}/s);
 28    if (alphaMatch) {
 29      const colorMatches = alphaMatch[1].matchAll(/(\d+):\s*['"]([#\w]+)['"]/g);
 30      for (const match of colorMatches) {
 31        colors.alpha[match[1]] = match[2];
 32      }
 33    }
 34  
 35    // Match delta colors
 36    const deltaMatch = content.match(/delta:\s*\{([^}]+)\}/s);
 37    if (deltaMatch) {
 38      const colorMatches = deltaMatch[1].matchAll(/(\d+):\s*['"]([#\w]+)['"]/g);
 39      for (const match of colorMatches) {
 40        colors.delta[match[1]] = match[2];
 41      }
 42    }
 43  
 44    // Match semantic colors
 45    const semanticMatch = content.match(/semantic:\s*\{([^}]+)\}/s);
 46    if (semanticMatch) {
 47      colors.semantic = {};
 48      const colorMatches = semanticMatch[1].matchAll(/(\w+):\s*['"]([#\w]+)['"]/g);
 49      for (const match of colorMatches) {
 50        colors.semantic[match[1]] = match[2];
 51      }
 52    }
 53  
 54    return colors;
 55  }
 56  
 57  const colors = extractColors(tokensContent);
 58  
 59  // Generate CSS variables block
 60  function generateCSSVariables(colors) {
 61    let css = '';
 62  
 63    // Alpha colors
 64    css += '      /* Alpha Chain - Trust, Technology, Security */\n';
 65    for (const [shade, value] of Object.entries(colors.alpha)) {
 66      css += `      --alpha-${shade}: ${value};\n`;
 67    }
 68  
 69    css += '\n      /* Delta Chain - Energy, Exchange, Commerce (Orange scale) */\n';
 70    for (const [shade, value] of Object.entries(colors.delta)) {
 71      css += `      --delta-${shade}: ${value};\n`;
 72    }
 73  
 74    if (colors.semantic) {
 75      css += '\n      /* Semantic */\n';
 76      for (const [name, value] of Object.entries(colors.semantic)) {
 77        css += `      --${name}: ${value};\n`;
 78      }
 79    }
 80  
 81    return css;
 82  }
 83  
 84  // Read brand book
 85  const brandBookPath = resolve(ROOT, 'brand-book/index.html');
 86  let brandBook = readFileSync(brandBookPath, 'utf-8');
 87  
 88  // Update CSS variables in :root
 89  const cssVarsRegex = /(\/\* Alpha Chain[^]*?--delta-900:[^;]+;)/;
 90  const newCSSVars = `/* Alpha Chain - Trust, Technology, Security */
 91        --alpha-50: ${colors.alpha['50']};
 92        --alpha-100: ${colors.alpha['100']};
 93        --alpha-200: ${colors.alpha['200']};
 94        --alpha-300: ${colors.alpha['300']};
 95        --alpha-400: ${colors.alpha['400']};
 96        --alpha-500: ${colors.alpha['500']};
 97        --alpha-600: ${colors.alpha['600']};
 98        --alpha-700: ${colors.alpha['700']};
 99        --alpha-800: ${colors.alpha['800']};
100        --alpha-900: ${colors.alpha['900']};
101  
102        /* Delta Chain - Energy, Exchange, Commerce (Orange scale) */
103        --delta-50: ${colors.delta['50']};
104        --delta-100: ${colors.delta['100']};
105        --delta-200: ${colors.delta['200']};
106        --delta-300: ${colors.delta['300']};
107        --delta-400: ${colors.delta['400']};
108        --delta-500: ${colors.delta['500']};
109        --delta-600: ${colors.delta['600']};
110        --delta-700: ${colors.delta['700']};
111        --delta-800: ${colors.delta['800']};
112        --delta-900: ${colors.delta['900']}`;
113  
114  brandBook = brandBook.replace(cssVarsRegex, newCSSVars);
115  
116  // Update color documentation text
117  const alphaHexRegex = /<strong>Primary:<\/strong> <code>#[A-Fa-f0-9]+<\/code> \(500\) · <strong>Hover:<\/strong> <code>#[A-Fa-f0-9]+<\/code> \(600\)<\/p>\s*<h2>Delta/;
118  brandBook = brandBook.replace(
119    alphaHexRegex,
120    `<strong>Primary:</strong> <code>${colors.alpha['500']}</code> (500) · <strong>Hover:</strong> <code>${colors.alpha['600']}</code> (600)</p>\n\n    <h2>Delta`
121  );
122  
123  const deltaHexRegex = /<strong>Primary:<\/strong> <code>#[A-Fa-f0-9]+<\/code> \(500\) · <strong>Hover:<\/strong> <code>#[A-Fa-f0-9]+<\/code> \(600\)<\/p>\s*<h2>Semantic/;
124  brandBook = brandBook.replace(
125    deltaHexRegex,
126    `<strong>Primary:</strong> <code>${colors.delta['500']}</code> (500) · <strong>Hover:</strong> <code>${colors.delta['600']}</code> (600)</p>\n\n    <h2>Semantic`
127  );
128  
129  // Write updated brand book
130  writeFileSync(brandBookPath, brandBook);
131  
132  console.log('✓ Brand book updated with current token values');
133  console.log('  Alpha 500:', colors.alpha['500']);
134  console.log('  Delta 500:', colors.delta['500']);
135  console.log('  Delta 50:', colors.delta['50'], '(light shade)');