Files
dss/scripts/figma-sync.py
2025-12-11 07:13:06 -03:00

173 lines
6.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""
DSS Figma Sync CLI.
This script is a lightweight CLI wrapper around the FigmaTokenSource from the
dss.ingest module. It fetches tokens and components from Figma and saves them
to the project's .dss directory.
The core extraction and processing logic resides in:
dss.ingest.sources.figma.FigmaTokenSource
"""
import argparse
import asyncio
import json
import os
import sys
from pathlib import Path
from dss.ingest.base import TokenCollection
from dss.ingest.sources.figma import FigmaTokenSource
# Ensure the project root is in the Python path
DSS_ROOT = Path(__file__).parent.parent
if str(DSS_ROOT) not in sys.path:
sys.path.insert(0, str(DSS_ROOT))
# =============================================================================
# CONFIGURATION
# =============================================================================
CACHE_DIR = DSS_ROOT / ".dss/cache"
TOKENS_DIR = DSS_ROOT / ".dss/data/_system/tokens"
COMPONENTS_DIR = DSS_ROOT / ".dss/components"
# =============================================================================
# OUTPUT WRITER
# =============================================================================
class OutputWriter:
"""Writes extraction results to the DSS file structure."""
def __init__(self, verbose: bool = False):
self.verbose = verbose
def write_token_collection(self, collection: TokenCollection, output_dir: Path = TOKENS_DIR):
"""Write TokenCollection to a structured JSON file."""
output_dir.mkdir(parents=True, exist_ok=True)
tokens_file = output_dir / "figma-tokens.json"
if self.verbose:
print(f" [OUT] Writing {len(collection)} tokens to {tokens_file}")
with open(tokens_file, "w") as f:
json.dump(json.loads(collection.to_json()), f, indent=2)
print(f" [OUT] Tokens: {tokens_file}")
def write_components(self, components: Dict, output_dir: Path = COMPONENTS_DIR):
"""Write component registry."""
output_dir.mkdir(parents=True, exist_ok=True)
comp_file = output_dir / "figma-registry.json"
if self.verbose:
print(
f" [OUT] Writing {components.get('component_count', 0)} components to {comp_file}"
)
with open(comp_file, "w") as f:
json.dump(components, f, indent=2)
print(f" [OUT] Components: {comp_file}")
# =============================================================================
# MAIN ORCHESTRATOR
# =============================================================================
async def main():
"""Main CLI orchestration function."""
parser = argparse.ArgumentParser(description="DSS Intelligent Figma Sync")
parser.add_argument("--file-key", help="Figma file key to sync")
parser.add_argument("--force", action="store_true", help="Force sync, ignoring cache")
parser.add_argument("--verbose", "-v", action="store_true", help="Enable verbose output")
args = parser.parse_args()
# --- Configuration Loading ---
config = load_config()
file_key = args.file_key or config.get("uikit_reference", {}).get("file_key")
token = os.environ.get("FIGMA_TOKEN") or config.get("token")
if not file_key:
print("[ERROR] No Figma file key provided.", file=sys.stderr)
print(" Provide it with --file-key or in .dss/config/figma.json", file=sys.stderr)
sys.exit(1)
if not token:
print("[ERROR] No Figma token found.", file=sys.stderr)
print(" Set FIGMA_TOKEN env var or add 'token' to .dss/config/figma.json", file=sys.stderr)
sys.exit(1)
print_header(file_key, token, args.force)
# --- Extraction ---
try:
source = FigmaTokenSource(figma_token=token, verbose=args.verbose)
token_collection, component_registry = await source.extract(file_key)
except Exception as e:
print(f"\n[ERROR] An error occurred during extraction: {e}", file=sys.stderr)
# In verbose mode, print more details
if args.verbose:
import traceback
traceback.print_exc()
sys.exit(1)
# --- Writing Output ---
print("\n[3/3] Writing output...")
writer = OutputWriter(verbose=args.verbose)
writer.write_token_collection(token_collection)
writer.write_components(component_registry)
# --- Summary ---
print_summary(
file_name=component_registry.get("file_name", "Unknown"),
token_count=len(token_collection),
component_count=component_registry.get("component_count", 0),
)
print("\n[OK] Sync successful!")
print(" Next: Run the translation and theming pipeline.")
sys.exit(0)
def load_config() -> Dict:
"""Load Figma config from .dss/config/figma.json."""
config_path = DSS_ROOT / ".dss/config/figma.json"
if config_path.exists():
try:
with open(config_path) as f:
return json.load(f)
except (json.JSONDecodeError, IOError) as e:
print(
f"[WARN] Could not read or parse config file: {config_path}\n{e}", file=sys.stderr
)
return {}
def print_header(file_key: str, token: str, force: bool):
"""Prints the CLI header."""
print("╔══════════════════════════════════════════════════════════════╗")
print("║ DSS FIGMA SYNC (INGESTION CLI) v3.0 ║")
print("╚══════════════════════════════════════════════════════════════╝")
print(f" File: {file_key}")
print(f" Token: {token[:10]}...")
print(f" Force: {force}")
print("\n[1/3] Initializing Figma Ingestion Source...")
def print_summary(file_name: str, token_count: int, component_count: int):
"""Prints the final summary."""
print("\n" + "=" * 60)
print("SYNC COMPLETE")
print("=" * 60)
print(f" File: {file_name}")
print(f" Tokens: {token_count}")
print(f" Components: {component_count}")
if __name__ == "__main__":
asyncio.run(main())