Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
375 lines
11 KiB
Python
375 lines
11 KiB
Python
"""
|
|
Token Format Exporters
|
|
|
|
Export design tokens extracted from Figma in multiple formats:
|
|
- CSS Variables
|
|
- JSON
|
|
- TypeScript
|
|
- SCSS
|
|
- JavaScript
|
|
"""
|
|
|
|
import json
|
|
from typing import Dict, Any, List
|
|
from pathlib import Path
|
|
|
|
|
|
class TokenExporter:
|
|
"""Base class for token exporters"""
|
|
|
|
def __init__(self, tokens: Dict[str, Any]):
|
|
"""Initialize exporter with tokens"""
|
|
self.tokens = tokens
|
|
self.output = ""
|
|
|
|
def export(self) -> str:
|
|
"""Export tokens in format-specific way"""
|
|
raise NotImplementedError
|
|
|
|
|
|
class CSSVariableExporter(TokenExporter):
|
|
"""Export tokens as CSS custom properties"""
|
|
|
|
def export(self) -> str:
|
|
"""Export as CSS variables"""
|
|
lines = [":root {"]
|
|
|
|
if "colors" in self.tokens:
|
|
for name, value in self.tokens["colors"].items():
|
|
lines.append(f" --color-{name}: {value};")
|
|
|
|
if "spacing" in self.tokens:
|
|
for name, value in self.tokens["spacing"].items():
|
|
lines.append(f" --spacing-{name}: {value}px;")
|
|
|
|
if "typography" in self.tokens:
|
|
for name, props in self.tokens["typography"].items():
|
|
if isinstance(props, dict):
|
|
for prop, val in props.items():
|
|
lines.append(f" --typography-{name}-{prop}: {val};")
|
|
else:
|
|
lines.append(f" --typography-{name}: {props};")
|
|
|
|
lines.append("}")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
class JSONExporter(TokenExporter):
|
|
"""Export tokens as JSON"""
|
|
|
|
def export(self) -> str:
|
|
"""Export as JSON"""
|
|
return json.dumps(self.tokens, indent=2)
|
|
|
|
|
|
class TypeScriptExporter(TokenExporter):
|
|
"""Export tokens as TypeScript constants"""
|
|
|
|
def export(self) -> str:
|
|
"""Export as TypeScript"""
|
|
lines = [
|
|
"/**",
|
|
" * Design System Tokens",
|
|
" * Auto-generated from Figma",
|
|
" */",
|
|
"",
|
|
"export const DSSTokens = {"
|
|
]
|
|
|
|
# Colors
|
|
if "colors" in self.tokens:
|
|
lines.append(" colors: {")
|
|
for name, value in self.tokens["colors"].items():
|
|
lines.append(f" {name}: '{value}',")
|
|
lines.append(" },")
|
|
|
|
# Spacing
|
|
if "spacing" in self.tokens:
|
|
lines.append(" spacing: {")
|
|
for name, value in self.tokens["spacing"].items():
|
|
lines.append(f" {name}: {value},")
|
|
lines.append(" },")
|
|
|
|
# Typography
|
|
if "typography" in self.tokens:
|
|
lines.append(" typography: {")
|
|
for name, props in self.tokens["typography"].items():
|
|
if isinstance(props, dict):
|
|
lines.append(f" {name}: {{")
|
|
for prop, val in props.items():
|
|
if isinstance(val, str):
|
|
lines.append(f" {prop}: '{val}',")
|
|
else:
|
|
lines.append(f" {prop}: {val},")
|
|
lines.append(" },")
|
|
else:
|
|
lines.append(f" {name}: '{props}',")
|
|
lines.append(" },")
|
|
|
|
lines.append("};")
|
|
lines.append("")
|
|
lines.append("export type TokenKey = keyof typeof DSSTokens;")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
class SCSSExporter(TokenExporter):
|
|
"""Export tokens as SCSS variables"""
|
|
|
|
def export(self) -> str:
|
|
"""Export as SCSS"""
|
|
lines = ["// Design System Tokens - SCSS Variables", ""]
|
|
|
|
# Colors
|
|
if "colors" in self.tokens:
|
|
lines.append("// Colors")
|
|
for name, value in self.tokens["colors"].items():
|
|
lines.append(f"$color-{name}: {value};")
|
|
lines.append("")
|
|
|
|
# Spacing
|
|
if "spacing" in self.tokens:
|
|
lines.append("// Spacing")
|
|
for name, value in self.tokens["spacing"].items():
|
|
lines.append(f"$spacing-{name}: {value}px;")
|
|
lines.append("")
|
|
|
|
# Typography
|
|
if "typography" in self.tokens:
|
|
lines.append("// Typography")
|
|
for name, props in self.tokens["typography"].items():
|
|
if isinstance(props, dict):
|
|
for prop, val in props.items():
|
|
lines.append(f"$typography-{name}-{prop}: {val};")
|
|
else:
|
|
lines.append(f"$typography-{name}: {props};")
|
|
lines.append("")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
class JavaScriptExporter(TokenExporter):
|
|
"""Export tokens as JavaScript object"""
|
|
|
|
def export(self) -> str:
|
|
"""Export as JavaScript"""
|
|
lines = [
|
|
"/**",
|
|
" * Design System Tokens",
|
|
" * Auto-generated from Figma",
|
|
" */",
|
|
"",
|
|
"const DSSTokens = {"
|
|
]
|
|
|
|
# Colors
|
|
if "colors" in self.tokens:
|
|
lines.append(" colors: {")
|
|
for name, value in self.tokens["colors"].items():
|
|
lines.append(f" {name}: '{value}',")
|
|
lines.append(" },")
|
|
|
|
# Spacing
|
|
if "spacing" in self.tokens:
|
|
lines.append(" spacing: {")
|
|
for name, value in self.tokens["spacing"].items():
|
|
lines.append(f" {name}: {value},")
|
|
lines.append(" },")
|
|
|
|
# Typography
|
|
if "typography" in self.tokens:
|
|
lines.append(" typography: {")
|
|
for name, props in self.tokens["typography"].items():
|
|
if isinstance(props, dict):
|
|
lines.append(f" {name}: {{")
|
|
for prop, val in props.items():
|
|
if isinstance(val, str):
|
|
lines.append(f" {prop}: '{val}',")
|
|
else:
|
|
lines.append(f" {prop}: {val},")
|
|
lines.append(" },")
|
|
else:
|
|
lines.append(f" {name}: '{props}',")
|
|
lines.append(" },")
|
|
|
|
lines.append("};")
|
|
lines.append("")
|
|
lines.append("module.exports = DSSTokens;")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
class FigmaExporter(TokenExporter):
|
|
"""Export tokens in Figma sync format"""
|
|
|
|
def export(self) -> str:
|
|
"""Export in Figma-compatible format"""
|
|
figma_tokens = {
|
|
"colors": [],
|
|
"typography": [],
|
|
"sizing": []
|
|
}
|
|
|
|
if "colors" in self.tokens:
|
|
for name, value in self.tokens["colors"].items():
|
|
figma_tokens["colors"].append({
|
|
"name": name,
|
|
"value": value,
|
|
"type": "color"
|
|
})
|
|
|
|
if "spacing" in self.tokens:
|
|
for name, value in self.tokens["spacing"].items():
|
|
figma_tokens["sizing"].append({
|
|
"name": name,
|
|
"value": f"{value}px",
|
|
"type": "size"
|
|
})
|
|
|
|
if "typography" in self.tokens:
|
|
for name, props in self.tokens["typography"].items():
|
|
figma_tokens["typography"].append({
|
|
"name": name,
|
|
"value": props,
|
|
"type": "typography"
|
|
})
|
|
|
|
return json.dumps(figma_tokens, indent=2)
|
|
|
|
|
|
class TailwindExporter(TokenExporter):
|
|
"""Export tokens as Tailwind configuration"""
|
|
|
|
def export(self) -> str:
|
|
"""Export as Tailwind config"""
|
|
lines = [
|
|
"/**",
|
|
" * Tailwind Configuration",
|
|
" * Auto-generated from Design System tokens",
|
|
" */",
|
|
"",
|
|
"module.exports = {",
|
|
" theme: {",
|
|
" extend: {"
|
|
]
|
|
|
|
# Colors
|
|
if "colors" in self.tokens:
|
|
lines.append(" colors: {")
|
|
for name, value in self.tokens["colors"].items():
|
|
lines.append(f" '{name}': '{value}',")
|
|
lines.append(" },")
|
|
|
|
# Spacing
|
|
if "spacing" in self.tokens:
|
|
lines.append(" spacing: {")
|
|
for name, value in self.tokens["spacing"].items():
|
|
lines.append(f" '{name}': '{value}px',")
|
|
lines.append(" },")
|
|
|
|
lines.append(" },")
|
|
lines.append(" },")
|
|
lines.append("};")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
class TokenExporterFactory:
|
|
"""Factory for creating exporters"""
|
|
|
|
exporters = {
|
|
"css": CSSVariableExporter,
|
|
"json": JSONExporter,
|
|
"typescript": TypeScriptExporter,
|
|
"ts": TypeScriptExporter,
|
|
"scss": SCSSExporter,
|
|
"javascript": JavaScriptExporter,
|
|
"js": JavaScriptExporter,
|
|
"figma": FigmaExporter,
|
|
"tailwind": TailwindExporter,
|
|
}
|
|
|
|
@classmethod
|
|
def create(cls, format: str, tokens: Dict[str, Any]) -> TokenExporter:
|
|
"""Create exporter for specified format"""
|
|
exporter_class = cls.exporters.get(format.lower())
|
|
|
|
if not exporter_class:
|
|
raise ValueError(f"Unknown export format: {format}")
|
|
|
|
return exporter_class(tokens)
|
|
|
|
@classmethod
|
|
def export(cls, format: str, tokens: Dict[str, Any]) -> str:
|
|
"""Export tokens directly"""
|
|
exporter = cls.create(format, tokens)
|
|
return exporter.export()
|
|
|
|
@classmethod
|
|
def export_all(cls, tokens: Dict[str, Any], output_dir: Path) -> Dict[str, Path]:
|
|
"""Export tokens in all formats to directory"""
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
results = {}
|
|
|
|
format_extensions = {
|
|
"css": ".css",
|
|
"json": ".json",
|
|
"typescript": ".ts",
|
|
"scss": ".scss",
|
|
"javascript": ".js",
|
|
"figma": ".figma.json",
|
|
"tailwind": ".config.js",
|
|
}
|
|
|
|
for format, ext in format_extensions.items():
|
|
try:
|
|
exported = cls.export(format, tokens)
|
|
filename = f"tokens{ext}"
|
|
filepath = output_dir / filename
|
|
|
|
with open(filepath, "w") as f:
|
|
f.write(exported)
|
|
|
|
results[format] = filepath
|
|
except Exception as e:
|
|
print(f"Error exporting {format}: {e}")
|
|
|
|
return results
|
|
|
|
|
|
# Convenience functions
|
|
def export_tokens_css(tokens: Dict[str, Any]) -> str:
|
|
"""Export tokens as CSS variables"""
|
|
return TokenExporterFactory.export("css", tokens)
|
|
|
|
|
|
def export_tokens_json(tokens: Dict[str, Any]) -> str:
|
|
"""Export tokens as JSON"""
|
|
return TokenExporterFactory.export("json", tokens)
|
|
|
|
|
|
def export_tokens_typescript(tokens: Dict[str, Any]) -> str:
|
|
"""Export tokens as TypeScript"""
|
|
return TokenExporterFactory.export("typescript", tokens)
|
|
|
|
|
|
def export_tokens_scss(tokens: Dict[str, Any]) -> str:
|
|
"""Export tokens as SCSS"""
|
|
return TokenExporterFactory.export("scss", tokens)
|
|
|
|
|
|
def export_tokens_javascript(tokens: Dict[str, Any]) -> str:
|
|
"""Export tokens as JavaScript"""
|
|
return TokenExporterFactory.export("javascript", tokens)
|
|
|
|
|
|
def export_tokens_tailwind(tokens: Dict[str, Any]) -> str:
|
|
"""Export tokens for Tailwind"""
|
|
return TokenExporterFactory.export("tailwind", tokens)
|
|
|
|
|
|
def export_all_formats(tokens: Dict[str, Any], output_dir: str) -> Dict[str, Path]:
|
|
"""Export tokens in all formats"""
|
|
return TokenExporterFactory.export_all(tokens, Path(output_dir))
|