repo_description: Extract any website's complete design system with one command. DTCG tokens, semantic+primitive+composite, MCP server for Claude Code/Cursor/Windsurf, multi-platform emitters (iOS SwiftUI, Android Compose, Flutter, WordPress), Tailwind v4, Figma variables, shadcn/ui, CSS health audit, WCAG remediation, Chrome extension. MIT, Playwright, Node 20+.
repo_topics: accessibility agent-skill ai chrome-extension claude-code-plugin cli css cursor design-system design-to-code design-tokens dtcg figma mcp-server npx playwright shadcn-ui skills-sh tailwind web-scraping
code: // iOS SwiftUI emitter — consumes a DTCG token object and produces a single
  // Swift file exposing semantic Colors, primitive spacing/radius as CGFloat, and
  // primitive palette colors.
  
  import { resolveRef } from './_token-ref.js';
  
  const HEADER_VERSION = '7.0.0';
  
  // Convert a dotted DTCG path to camelCase identifier.
  // e.g. "semantic.color.action.primary" → "actionPrimary"
  //      "primitive.color.brand.primary" → "brandPrimary"
  //      "primitive.spacing.s0" → "spacingS0"
  //      "primitive.radius.r0" → "radiusR0"
  function camelFromPath(path) {
    const parts = path.split('.');
    // Drop leading "primitive"/"semantic" and the type bucket.
    // We keep meaningful parts.
    const trimmed = parts.slice(1); // drop primitive/semantic
    // Drop the type segment for semantic colors ("color.action.primary" → "action.primary")
    // For primitive colors ("color.brand.primary" → keep "brand.primary")
    // For primitive spacing ("spacing.s0") we want "spacingS0" — keep all.
    let segments;
    if (trimmed[0] === 'color' && trimmed.length >= 3) {
      segments = trimmed.slice(1);
    } else {
      segments = trimmed;
    }
    return segments
      .map((s, i) => (i === 0 ? s : s.charAt(0).toUpperCase() + s.slice(1)))
      .join('')
      .replace(/[^a-zA-Z0-9]/g, '');
  }
  
  // Convert "#rrggbb" or "#rgb" to "0xRRGGBB" for SwiftUI Color(hex:).
  function hexToSwiftHex(hex) {
    if (typeof hex !== 'string') return null;
    let h = hex.trim().replace(/^#/, '');
    if (h.length === 3) {
      h = h.split('').map((c) => c + c).join('');
    }
    if (h.length === 6 && /^[0-9a-fA-F]{6}$/.test(h)) {
      return `0x${h.toUpperCase()}`;
    }
    if (h.length === 8 && /^[0-9a-fA-F]{8}$/.test(h)) {
      // drop alpha
      return `0x${h.slice(2).toUpperCase()}`;
    }
    return null;
  }
  
  function dimensionToNumber(value) {
    if (typeof value === 'number') return value;
    if (typeof value !== 'string') return null;
    const m = value.match(/^(-?\d+(?:\.\d+)?)(px|pt|rem|em)?$/);
    if (!m) return null;
    const n = parseFloat(m[1]);
    const unit = m[2];
    if (unit === 'rem' || unit === 'em') return n * 16;
    return n;
  }
  
  // Walk leaves of a subtree producing { path, token } pairs.
  function* walkLeaves(node, prefix) {
    if (node == null || typeof node !== 'object') return;
    if ('$value' in node && '$type' in node) {
      yield { path: prefix, token: node };
      return;
    }
    for (const key of Object.keys(node)) {
      yield* walkLeaves(node[key], prefix ? `${prefix}.${key}` : key);
    }
  }
  
  export function formatIosSwiftUI(tokens) {
    const lines = [];
    const source = tokens?.$metadata?.source || '';
    lines.push(`// Generated by designlang v${HEADER_VERSION} — https://github.com/Manavarya09/design-extract`);
    if (source) lines.push(`// Source: ${source}`);
    lines.push('import SwiftUI');
    lines.push('');
    lines.push('extension Color {');
    lines.push('  init(hex: UInt32) {');
    lines.push('    let r = Double((hex >> 16) & 0xFF) / 255');
    lines.push('    let g = Double((hex >> 8) & 0xFF) / 255');
    lines.push('    let b = Double(hex & 0xFF) / 255');
    lines.push('    self.init(red: r, green: g, blue: b)');
    lines.push('  }');
    lines.push('');
    lines.push('  // MARK: Semantic');
  
    // Semantic colors
    const semanticColor = tokens?.semantic?.color;
    if (semanticColor) {
      for (const leaf of walkLeaves(semanticColor, 'semantic.color')) {
        if (leaf.token.$type !== 'color') continue;
        const resolved = resolveRef(tokens, leaf.path);
        const swiftHex = hexToSwiftHex(resolved);
        if (!swiftHex) continue;
        lines.push(`  static let ${camelFromPath(leaf.path)} = Color(hex: ${swiftHex})`);
      }
    }
    lines.push('}');
    lines.push('');
  
    // CGFloat spacing + radius
    lines.push('extension CGFloat {');
    lines.push('  // MARK: Primitive spacing');
    const spacing = tokens?.primitive?.spacing || {};
    for (const key of Object.keys(spacing)) {
      const tok = spacing[key];
      if (!tok || tok.$type !== 'dimension') continue;
      const n = dimensionToNumber(resolveRef(tokens, `primitive.spacing.${key}`));
      if (n == null) continue;
      const name = camelFromPath(`primitive.spacing.${key}`);
      lines.push(`  static let ${name}: CGFloat = ${n}`);
    }
    lines.push('');
    lines.push('  // MARK: Primitive radius');
    const radius = tokens?.primitive?.radius || {};
    for (const key of Object.keys(radius)) {
      const tok = radius[key];
      if (!tok || tok.$type !== 'dimension') continue;
      const n = dimensionToNumber(resolveRef(tokens, `primitive.radius.${key}`));
      if (n == null) continue;
      const name = camelFromPath(`primitive.radius.${key}`);
      lines.push(`  static let ${name}: CGFloat = ${n}`);
    }
    lines.push('}');
    lines.push('');
  
    // Primitive palette colors for direct use
    lines.push('// MARK: Primitive palette (for direct use)');
    lines.push('extension Color {');
    const primColor = tokens?.primitive?.color;
    if (primColor) {
      for (const leaf of walkLeaves(primColor, 'primitive.color')) {
        if (leaf.token.$type !== 'color') continue;
        const resolved = resolveRef(tokens, leaf.path);
        const swiftHex = hexToSwiftHex(resolved);
        if (!swiftHex) continue;
        lines.push(`  static let ${camelFromPath(leaf.path)} = Color(hex: ${swiftHex})`);
      }
    }
    lines.push('}');
    lines.push('');
  
    // Typography hint comments (composite typography tokens)
    const typography = tokens?.semantic?.typography;
    if (typography) {
      for (const key of Object.keys(typography)) {
        const tok = typography[key];
        if (!tok || tok.$type !== 'typography') continue;
        const v = tok.$value || {};
        lines.push(
          `// typography.${key}: family=${v.fontFamily ?? ''} size=${v.fontSize ?? ''} weight=${v.fontWeight ?? ''} lineHeight=${v.lineHeight ?? ''}`,
        );
      }
    }
  
    return lines.join('\n') + '\n';
  }
  