""" DSS Merge Case Examples Demonstrates how DSS handles multi-source token ingestion and translation to the canonical DSS structure. Uses HeroUI and shadcn as examples. Key Principle: DSS is MONOLITHIC. External systems translate TO us. """ import asyncio import json from pathlib import Path # Add parent to path for imports import sys sys.path.insert(0, str(Path(__file__).parent.parent / "tools")) from ingest import ( DesignToken, TokenCollection, TokenMerger, MergeStrategy, CSSTokenSource, JSONTokenSource ) from ingest.base import TokenType, TokenCategory # ============================================================================= # CASE 1: HeroUI Token Structure # ============================================================================= # HeroUI uses: --heroui-{category}-{scale} # Example: --heroui-primary-500, --heroui-content1, --heroui-radius-medium HEROUI_TOKENS = """ :root { /* HeroUI Color Scale System */ --heroui-primary-50: #e6f1fe; --heroui-primary-100: #cce3fd; --heroui-primary-200: #99c7fb; --heroui-primary-300: #66aaf9; --heroui-primary-400: #338ef7; --heroui-primary-500: #006FEE; --heroui-primary-600: #005bc4; --heroui-primary-700: #004493; --heroui-primary-800: #002e62; --heroui-primary-900: #001731; --heroui-secondary-500: #7828c8; --heroui-success-500: #17c964; --heroui-warning-500: #f5a524; --heroui-danger-500: #f31260; /* HeroUI Content Layers */ --heroui-content1: #ffffff; --heroui-content2: #f4f4f5; --heroui-content3: #e4e4e7; --heroui-content4: #d4d4d8; /* HeroUI Layout Tokens */ --heroui-radius-small: 8px; --heroui-radius-medium: 12px; --heroui-radius-large: 14px; --heroui-shadow-small: 0px 0px 5px 0px rgba(0,0,0,0.02); --heroui-shadow-medium: 0px 0px 15px 0px rgba(0,0,0,0.03); --heroui-shadow-large: 0px 0px 30px 0px rgba(0,0,0,0.04); --heroui-font-size-tiny: 0.75rem; --heroui-font-size-small: 0.875rem; --heroui-font-size-medium: 1rem; --heroui-font-size-large: 1.125rem; --heroui-spacing-unit: 4px; } """ # ============================================================================= # CASE 2: shadcn Token Structure # ============================================================================= # shadcn uses: --{semantic-name} with background/foreground pattern # Example: --primary, --primary-foreground, --card, --card-foreground SHADCN_TOKENS = """ :root { /* shadcn Semantic Colors (OKLCH format) */ --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; --card: 0 0% 100%; --card-foreground: 222.2 84% 4.9%; --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; --primary: 222.2 47.4% 11.2%; --primary-foreground: 210 40% 98%; --secondary: 210 40% 96.1%; --secondary-foreground: 222.2 47.4% 11.2%; --muted: 210 40% 96.1%; --muted-foreground: 215.4 16.3% 46.9%; --accent: 210 40% 96.1%; --accent-foreground: 222.2 47.4% 11.2%; --destructive: 0 84.2% 60.2%; --border: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%; --ring: 222.2 84% 4.9%; --radius: 0.5rem; /* shadcn Chart Colors */ --chart-1: 12 76% 61%; --chart-2: 173 58% 39%; --chart-3: 197 37% 24%; --chart-4: 43 74% 66%; --chart-5: 27 87% 67%; } """ # ============================================================================= # CASE 3: Legacy Corporate CSS (typical client scenario) # ============================================================================= # Legacy uses: various naming conventions, inconsistent structure LEGACY_CORPORATE_TOKENS = """ :root { /* Old brand colors - inconsistent naming */ --brand-blue: #1E40AF; --brand-dark-blue: #1E3A8A; --brand-light: #DBEAFE; --brandAccent: #F59E0B; /* camelCase mixed in */ /* Old button colors */ --btn-primary-bg: #1E40AF; --btn-primary-text: #FFFFFF; --btn-secondary-bg: #F3F4F6; /* Inconsistent spacing */ --space-xs: 4px; --space-sm: 8px; --spacing-md: 16px; /* Different prefix! */ --SPACING_LG: 24px; /* SCREAMING_CASE! */ /* Typography chaos */ --font-base: 16px; --fontSize-lg: 18px; --text-xl: 24px; /* Random radius values */ --rounded: 4px; --border-radius-md: 8px; --corners-lg: 12px; } """ # ============================================================================= # DSS CANONICAL STRUCTURE (The Target) # ============================================================================= # This is what ALL external systems translate TO. Never changes. DSS_CANONICAL = { "colors": { "primary": {"50": None, "100": None, "200": None, "300": None, "400": None, "500": None, "600": None, "700": None, "800": None, "900": None}, "secondary": {"500": None}, "success": {"500": None}, "warning": {"500": None}, "danger": {"500": None}, "neutral": {"50": None, "100": None, "200": None, "300": None, "400": None, "500": None, "600": None, "700": None, "800": None, "900": None}, }, "spacing": { "xs": None, "sm": None, "md": None, "lg": None, "xl": None, "2xl": None }, "radius": { "sm": None, "md": None, "lg": None, "xl": None, "full": None }, "shadows": { "sm": None, "md": None, "lg": None, "xl": None }, "typography": { "fontSize": {"xs": None, "sm": None, "base": None, "lg": None, "xl": None} } } # ============================================================================= # TRANSLATION DICTIONARIES # ============================================================================= def create_heroui_translation(): """ Translation dictionary: HeroUI → DSS Canonical HeroUI uses numeric color scales (like DSS) but different naming. Mapping is mostly 1:1 with prefix removal. """ return { "$schema": "dss-translation-v1", "project": "heroui-integration", "source": "heroui", "mappings": { "tokens": { # Colors - direct scale mapping "--heroui-primary-50": "color.primary.50", "--heroui-primary-100": "color.primary.100", "--heroui-primary-200": "color.primary.200", "--heroui-primary-300": "color.primary.300", "--heroui-primary-400": "color.primary.400", "--heroui-primary-500": "color.primary.500", "--heroui-primary-600": "color.primary.600", "--heroui-primary-700": "color.primary.700", "--heroui-primary-800": "color.primary.800", "--heroui-primary-900": "color.primary.900", "--heroui-secondary-500": "color.secondary.500", "--heroui-success-500": "color.success.500", "--heroui-warning-500": "color.warning.500", "--heroui-danger-500": "color.danger.500", # Content layers → Neutral scale "--heroui-content1": "color.neutral.50", "--heroui-content2": "color.neutral.100", "--heroui-content3": "color.neutral.200", "--heroui-content4": "color.neutral.300", # Layout tokens "--heroui-radius-small": "radius.sm", "--heroui-radius-medium": "radius.md", "--heroui-radius-large": "radius.lg", "--heroui-shadow-small": "shadow.sm", "--heroui-shadow-medium": "shadow.md", "--heroui-shadow-large": "shadow.lg", # Typography "--heroui-font-size-tiny": "typography.fontSize.xs", "--heroui-font-size-small": "typography.fontSize.sm", "--heroui-font-size-medium": "typography.fontSize.base", "--heroui-font-size-large": "typography.fontSize.lg", # Spacing "--heroui-spacing-unit": "spacing.unit", }, "components": { "Button": "Button", # HeroUI Button → DSS Button "Card": "Card", "Input": "Input", } }, "custom_props": { # HeroUI-specific that don't map to DSS core # These go in isolated namespace }, "notes": [ "HeroUI uses numeric scales similar to DSS - easy mapping", "Content layers (1-4) map to neutral scale", "Component mapping is mostly 1:1" ] } def create_shadcn_translation(): """ Translation dictionary: shadcn → DSS Canonical shadcn uses semantic naming (primary, secondary, muted) without scales. We map to the 500 (default) value in DSS scales. KEY DIFFERENCE: shadcn is HEADLESS - no numeric scales! """ return { "$schema": "dss-translation-v1", "project": "shadcn-integration", "source": "shadcn", "mappings": { "tokens": { # Semantic colors → DSS scale defaults "--background": "color.neutral.50", "--foreground": "color.neutral.900", "--primary": "color.primary.500", "--primary-foreground": "color.primary.50", "--secondary": "color.secondary.500", "--secondary-foreground": "color.secondary.50", "--muted": "color.neutral.200", "--muted-foreground": "color.neutral.600", "--accent": "color.accent.500", "--accent-foreground": "color.accent.50", "--destructive": "color.danger.500", "--card": "color.neutral.50", "--card-foreground": "color.neutral.900", "--popover": "color.neutral.50", "--popover-foreground": "color.neutral.900", "--border": "color.neutral.200", "--input": "color.neutral.200", "--ring": "color.primary.500", # Layout "--radius": "radius.md", }, "components": { # shadcn components → DSS components "Button": "Button", "Card": "Card", "Input": "Input", "Dialog": "Modal", "Popover": "Popover", } }, "custom_props": { # shadcn-specific that don't exist in DSS "color.chart.1": "var(--chart-1)", "color.chart.2": "var(--chart-2)", "color.chart.3": "var(--chart-3)", "color.chart.4": "var(--chart-4)", "color.chart.5": "var(--chart-5)", "color.sidebar.primary": "var(--sidebar-primary)", }, "notes": [ "shadcn is HEADLESS - no numeric color scales", "Semantic names map to 500 (default) DSS values", "foreground variants map to contrast colors (50)", "Chart colors are shadcn-specific custom props" ] } def create_legacy_translation(): """ Translation dictionary: Legacy Corporate → DSS Canonical Messy legacy code with inconsistent naming needs careful mapping. """ return { "$schema": "dss-translation-v1", "project": "acme-corp-legacy", "source": "legacy-css", "mappings": { "tokens": { # Brand colors (inconsistent naming) "--brand-blue": "color.primary.500", "--brand-dark-blue": "color.primary.700", "--brand-light": "color.primary.100", "--brandAccent": "color.warning.500", # camelCase → DSS # Button colors → Component tokens "--btn-primary-bg": "color.primary.500", "--btn-primary-text": "color.neutral.50", "--btn-secondary-bg": "color.neutral.100", # Spacing chaos → DSS order "--space-xs": "spacing.xs", "--space-sm": "spacing.sm", "--spacing-md": "spacing.md", "--SPACING_LG": "spacing.lg", # Typography normalization "--font-base": "typography.fontSize.base", "--fontSize-lg": "typography.fontSize.lg", "--text-xl": "typography.fontSize.xl", # Radius normalization "--rounded": "radius.sm", "--border-radius-md": "radius.md", "--corners-lg": "radius.lg", }, "components": { ".btn-primary": "Button[variant=primary]", ".btn-secondary": "Button[variant=secondary]", ".card-wrapper": "Card", ".input-field": "Input", } }, "custom_props": { # ACME-specific branding that extends DSS "color.brand.acme.primary": "#1E40AF", "color.brand.acme.accent": "#F59E0B", }, "validation_warnings": [ "Inconsistent spacing prefixes detected", "Mixed case conventions found", "Some values may need manual review" ], "notes": [ "Legacy system had 4 different naming conventions", "All mapped to DSS canonical structure", "Brand-specific colors isolated in custom_props" ] } # ============================================================================= # MERGE DEMONSTRATIONS # ============================================================================= async def demonstrate_merge_heroui_shadcn(): """ CASE: Merge HeroUI and shadcn tokens into DSS canonical structure. This demonstrates how two different atomic structures become one. """ print("\n" + "="*70) print("MERGE CASE: HeroUI + shadcn → DSS Canonical") print("="*70) css_source = CSSTokenSource() # Ingest both sources heroui_collection = await css_source.extract(HEROUI_TOKENS) shadcn_collection = await css_source.extract(SHADCN_TOKENS) print(f"\n📥 HeroUI tokens extracted: {len(heroui_collection.tokens)}") print(f"📥 shadcn tokens extracted: {len(shadcn_collection.tokens)}") # Merge with PREFER_SPECIFIC strategy # This prefers concrete values (hex) over references merger = TokenMerger(strategy=MergeStrategy.PREFER_SPECIFIC) result = merger.merge([heroui_collection, shadcn_collection]) print(f"\n🔀 Merged result: {result.stats['total_tokens']} tokens") print(f" New tokens: {result.stats['new_tokens']}") print(f" Conflicts resolved: {result.stats['conflicts_resolved']}") # Show conflicts if result.conflicts: print(f"\n⚠️ Conflicts detected ({len(result.conflicts)}):") for conflict in result.conflicts[:5]: print(f" • {conflict.token_name}") print(f" HeroUI: {conflict.existing.value}") print(f" shadcn: {conflict.incoming.value}") print(f" Resolution: {conflict.resolution}") # Demonstrate atomic structure difference print("\n" + "-"*70) print("ATOMIC STRUCTURE COMPARISON:") print("-"*70) print("\n🎨 HeroUI (Numeric Scale System):") print(" Uses: --heroui-primary-{50-900}") print(" Pattern: Full color scales with 10 values each") print(" Granularity: HIGH - precise control over each shade") print("\n🔲 shadcn (Semantic System):") print(" Uses: --primary, --primary-foreground") print(" Pattern: Semantic pairs (color + contrast)") print(" Granularity: LOW - headless, no scales") print("\n📐 DSS Canonical (Target):") print(" Uses: color.primary.{50-900}") print(" Result: Unified scale with both sources merged") return result async def demonstrate_merge_with_legacy(): """ CASE: Merge legacy corporate tokens with modern DSS structure. Shows how messy legacy code gets normalized. """ print("\n" + "="*70) print("MERGE CASE: Legacy Corporate → DSS Canonical") print("="*70) css_source = CSSTokenSource() # Ingest legacy tokens legacy_collection = await css_source.extract(LEGACY_CORPORATE_TOKENS) print(f"\n📥 Legacy tokens extracted: {len(legacy_collection.tokens)}") # Show the chaos print("\n🔴 LEGACY TOKEN NAMING CHAOS:") for token in legacy_collection.tokens[:8]: print(f" {token.original_name} → {token.normalize_name()}") # Get translation dictionary translation = create_legacy_translation() print("\n🔄 TRANSLATION DICTIONARY MAPPINGS:") for legacy, dss in list(translation["mappings"]["tokens"].items())[:6]: print(f" {legacy} → {dss}") print("\n✅ RESULT: Unified DSS canonical tokens") print(" All naming conventions normalized") print(" Custom brand colors isolated in namespace") return legacy_collection async def demonstrate_conflict_strategies(): """ CASE: Show different merge strategies and their outcomes. """ print("\n" + "="*70) print("MERGE STRATEGIES COMPARISON") print("="*70) css_source = CSSTokenSource() # Create conflicting tokens source_a = """ :root { --primary: #3B82F6; --spacing-md: 16px; } """ source_b = """ :root { --primary: #2563EB; --spacing-md: 20px; } """ collection_a = await css_source.extract(source_a) collection_b = await css_source.extract(source_b) strategies = [ (MergeStrategy.FIRST, "Keep first occurrence"), (MergeStrategy.LAST, "Use last (override)"), (MergeStrategy.PREFER_SPECIFIC, "Prefer concrete values"), (MergeStrategy.MERGE_METADATA, "Merge metadata, use latest value"), ] for strategy, description in strategies: merger = TokenMerger(strategy=strategy) result = merger.merge([collection_a, collection_b]) primary_token = next( (t for t in result.collection.tokens if 'primary' in t.name.lower()), None ) print(f"\n📋 {strategy.value}: {description}") if primary_token: print(f" --primary result: {primary_token.value}") if result.conflicts: print(f" Resolution: {result.conflicts[0].resolution}") async def main(): """Run all merge demonstrations.""" print("\n" + "="*70) print("DSS MERGE CASE EXAMPLES") print("Demonstrating Multi-Source Token Ingestion") print("="*70) # Run demonstrations await demonstrate_merge_heroui_shadcn() await demonstrate_merge_with_legacy() await demonstrate_conflict_strategies() # Summary print("\n" + "="*70) print("SUMMARY: ATOMIC STRUCTURE DIFFERENCES") print("="*70) print(""" ┌─────────────────────────────────────────────────────────────────────┐ │ ATOMIC STRUCTURE COMPARISON │ ├─────────────────┬──────────────────────┬────────────────────────────┤ │ Feature │ HeroUI │ shadcn │ ├─────────────────┼──────────────────────┼────────────────────────────┤ │ Color System │ Numeric scales │ Semantic pairs │ │ │ (50-900) │ (primary/foreground) │ ├─────────────────┼──────────────────────┼────────────────────────────┤ │ Granularity │ HIGH (10 shades) │ LOW (2 values) │ ├─────────────────┼──────────────────────┼────────────────────────────┤ │ Naming │ --heroui-{cat}-{n} │ --{semantic} │ ├─────────────────┼──────────────────────┼────────────────────────────┤ │ CSS Variables │ Prefixed │ Unprefixed │ ├─────────────────┼──────────────────────┼────────────────────────────┤ │ Theme Layers │ content1-4 │ card, popover, muted │ ├─────────────────┼──────────────────────┼────────────────────────────┤ │ Design Tokens │ Full W3C-like │ Minimal semantic │ ├─────────────────┼──────────────────────┼────────────────────────────┤ │ DSS Mapping │ Direct 1:1 │ Expand to scales │ │ │ (strip prefix) │ (500 = default) │ └─────────────────┴──────────────────────┴────────────────────────────┘ """) print(""" ┌─────────────────────────────────────────────────────────────────────┐ │ DSS TRANSLATION APPROACH │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ HeroUI │ │ shadcn │ │ --heroui- │ TRANSLATION │ --primary ──────┐ │ │ primary-500 ────┼────── LAYER ────────┼→ color.primary.500 ←───────┤ │ │ │ --primary-foreground ─────┤ │ --heroui- │ │ ↓ │ │ content1 ───────┼─────────────────────┼→ color.neutral.50 │ │ │ │ │ │ │ DSS CANONICAL │ │ │ │ (IMMUTABLE) │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ """) if __name__ == "__main__": asyncio.run(main())