Initial commit: Clean DSS implementation
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
This commit is contained in:
374
tools/api/tokens/exporters.py
Normal file
374
tools/api/tokens/exporters.py
Normal file
@@ -0,0 +1,374 @@
|
||||
"""
|
||||
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))
|
||||
Reference in New Issue
Block a user