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:
Digital Production Factory
2025-12-09 18:45:48 -03:00
commit 276ed71f31
884 changed files with 373737 additions and 0 deletions

93
examples/01_basic_ingestion.py Executable file
View File

@@ -0,0 +1,93 @@
#!/usr/bin/env python3
"""
Example 1: Basic Token Ingestion
Shows how to ingest design tokens from different sources.
"""
import asyncio
import sys
from pathlib import Path
# Add project root to path
sys.path.insert(0, str(Path(__file__).parent.parent))
async def main():
print("=" * 60)
print("EXAMPLE 1: Basic Token Ingestion")
print("=" * 60)
# 1. CSS Token Ingestion
print("\n1. CSS Custom Properties")
print("-" * 40)
from tools.ingest.css import CSSTokenSource
css_content = """
:root {
--color-primary: #3B82F6;
--color-secondary: #10B981;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
}
"""
css_parser = CSSTokenSource()
css_result = await css_parser.extract(css_content)
print(f"✅ Extracted {len(css_result.tokens)} CSS tokens:")
for token in css_result.tokens[:3]:
print(f" {token.name} = {token.value} ({token.type.value})")
# 2. SCSS Token Ingestion
print("\n2. SCSS Variables")
print("-" * 40)
from tools.ingest.scss import SCSSTokenSource
scss_content = """
$primary-color: #3B82F6;
$secondary-color: #10B981;
$font-family-sans: 'Inter', sans-serif;
$font-size-base: 16px;
"""
scss_parser = SCSSTokenSource()
scss_result = await scss_parser.extract(scss_content)
print(f"✅ Extracted {len(scss_result.tokens)} SCSS tokens:")
for token in scss_result.tokens[:3]:
print(f" {token.name} = {token.value}")
# 3. JSON Tokens (W3C Format)
print("\n3. JSON Design Tokens (W3C)")
print("-" * 40)
from tools.ingest.json_tokens import JSONTokenSource
import json
json_content = {
"color": {
"primary": {
"500": {"value": "#3B82F6", "type": "color"},
"600": {"value": "#2563EB", "type": "color"}
}
},
"spacing": {
"md": {"value": "16px", "type": "dimension"}
}
}
json_parser = JSONTokenSource()
json_result = await json_parser.extract(json.dumps(json_content))
print(f"✅ Extracted {len(json_result.tokens)} JSON tokens:")
for token in json_result.tokens:
print(f" {token.name} = {token.value} ({token.type.value})")
print("\n" + "=" * 60)
print(f"Total tokens extracted: {len(css_result.tokens) + len(scss_result.tokens) + len(json_result.tokens)}")
print("=" * 60)
if __name__ == "__main__":
asyncio.run(main())

87
examples/02_token_merge.py Executable file
View File

@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""
Example 2: Token Merging with Conflict Resolution
Shows how to merge tokens from multiple sources using different strategies.
"""
import asyncio
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
async def main():
print("=" * 60)
print("EXAMPLE 2: Token Merging & Conflict Resolution")
print("=" * 60)
from tools.ingest.merge import TokenMerger, MergeStrategy
from tools.ingest.base import TokenCollection, DesignToken, TokenType
# Create tokens from different sources
print("\n1. Creating token collections from different sources...")
print("-" * 60)
css_tokens = TokenCollection([
DesignToken(name="color.primary", value="#FF0000", type=TokenType.COLOR, source="css"),
DesignToken(name="color.secondary", value="#00FF00", type=TokenType.COLOR, source="css"),
DesignToken(name="spacing.md", value="16px", type=TokenType.SPACING, source="css"),
])
figma_tokens = TokenCollection([
DesignToken(name="color.primary", value="#3B82F6", type=TokenType.COLOR, source="figma"),
DesignToken(name="color.accent", value="#F59E0B", type=TokenType.COLOR, source="figma"),
])
tailwind_tokens = TokenCollection([
DesignToken(name="color.primary", value="#2563EB", type=TokenType.COLOR, source="tailwind"),
DesignToken(name="spacing.lg", value="24px", type=TokenType.SPACING, source="tailwind"),
])
print(f"CSS: {len(css_tokens.tokens)} tokens")
print(f"Figma: {len(figma_tokens.tokens)} tokens")
print(f"Tailwind: {len(tailwind_tokens.tokens)} tokens")
# Test different merge strategies
strategies = [
MergeStrategy.FIRST,
MergeStrategy.LAST,
MergeStrategy.PREFER_FIGMA,
]
for strategy in strategies:
print(f"\n2. Merge Strategy: {strategy.value.upper()}")
print("-" * 60)
merger = TokenMerger(strategy=strategy)
result = merger.merge([css_tokens, figma_tokens, tailwind_tokens])
print(f"✅ Merged: {len(result.collection.tokens)} tokens")
print(f"⚠️ Conflicts: {len(result.conflicts)}")
if result.conflicts:
print("\nConflict Resolutions:")
for conflict in result.conflicts:
print(f"{conflict.token_name}:")
print(f" Existing: {conflict.existing.value} (from {conflict.existing.source})")
print(f" Incoming: {conflict.incoming.value} (from {conflict.incoming.source})")
print(f" ✓ Chose: {conflict.resolved_token.value} (from {conflict.resolved_token.source})")
# Show final token values
print("\nFinal Tokens:")
for token in result.collection.tokens:
print(f" {token.name}: {token.value} (source: {token.source})")
print("\n" + "=" * 60)
print("💡 Key Takeaways:")
print(" • FIRST: Keeps first occurrence, ignores later sources")
print(" • LAST: Override with latest source")
print(" • PREFER_FIGMA: Prioritizes Figma as source of truth")
print(" • PREFER_CODE: Prioritizes code sources (CSS, SCSS)")
print("=" * 60)
if __name__ == "__main__":
asyncio.run(main())

97
examples/03_project_analysis.py Executable file
View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""
Example 3: Project Analysis & Quick Wins
Shows how to analyze a React project and identify improvement opportunities.
"""
import asyncio
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
async def main():
print("=" * 60)
print("EXAMPLE 3: Project Analysis & Quick Wins")
print("=" * 60)
# Use current directory as example project
project_path = "."
# 1. Scan Project
print("\n1. Scanning Project...")
print("-" * 60)
from tools.analyze.scanner import ProjectScanner
scanner = ProjectScanner(project_path)
analysis = await scanner.scan()
print(f"✅ Project scanned successfully")
print(f"\nProject Details:")
print(f" Framework: {analysis.framework}")
print(f" Styling: {analysis.styling_approach}")
print(f" Package Manager: {analysis.package_manager}")
print(f" Has TypeScript: {analysis.has_typescript}")
print(f" Components Found: {len(analysis.components)}")
# 2. Find Quick Wins
print("\n2. Finding Quick Wins...")
print("-" * 60)
from tools.analyze.quick_wins import QuickWinFinder
finder = QuickWinFinder(project_path)
wins = await finder.find_all()
print(f"✅ Found {len(wins.opportunities)} improvement opportunities\n")
# Group by type
by_type = {}
for win in wins.opportunities:
win_type = win.type.value
if win_type not in by_type:
by_type[win_type] = []
by_type[win_type].append(win)
print("Breakdown by Type:")
for win_type, items in sorted(by_type.items()):
print(f" {win_type}: {len(items)} opportunities")
# 3. Show Top Priorities (High Impact, Low Effort)
print("\n3. Top Priorities (High ROI)")
print("-" * 60)
high_roi = [
w for w in wins.opportunities
if w.impact.value == "high" and w.effort.value in ["low", "medium"]
]
if high_roi:
for i, win in enumerate(high_roi[:5], 1):
print(f"\n{i}. {win.title}")
print(f" Type: {win.type.value}")
print(f" Impact: {win.impact.value} | Effort: {win.effort.value}")
print(f" Description: {win.description}")
if win.suggested_fix:
print(f" Fix: {win.suggested_fix}")
else:
print(" No high-ROI opportunities found (project is well-optimized!)")
# 4. Generate Report
print("\n4. Generating Report...")
print("-" * 60)
report = await finder.generate_report()
print(report[:500] + "..." if len(report) > 500 else report)
print("\n" + "=" * 60)
print("💡 Next Steps:")
print(" 1. Review high-impact, low-effort wins")
print(" 2. Create backlog tickets for improvements")
print(" 3. Use MCP tools for automated fixes")
print("=" * 60)
if __name__ == "__main__":
asyncio.run(main())

113
examples/README.md Normal file
View File

@@ -0,0 +1,113 @@
# DSS Code Examples
Practical examples showing how to use DSS core functionality.
## Running the Examples
```bash
# Activate virtual environment
source .venv/bin/activate
# Run any example
python examples/01_basic_ingestion.py
python examples/02_token_merge.py
python examples/03_project_analysis.py
```
## Example List
### 01_basic_ingestion.py
**Topic**: Token Ingestion from Multiple Sources
Shows how to extract design tokens from:
- CSS custom properties (`:root { --var: value; }`)
- SCSS variables (`$var: value;`)
- JSON tokens (W3C Design Tokens format)
**Output**: Demonstrates token extraction with counts and preview
---
### 02_token_merge.py
**Topic**: Merging Tokens with Conflict Resolution
Shows how to:
- Create token collections from different sources
- Merge tokens using different strategies (FIRST, LAST, PREFER_FIGMA)
- Resolve conflicts between sources
- Understand which strategy to use when
**Output**: Side-by-side comparison of merge strategies and conflict resolution
---
### 03_project_analysis.py
**Topic**: Project Analysis & Quick Wins
Shows how to:
- Scan a project for framework and styling detection
- Find improvement opportunities (quick wins)
- Prioritize changes by impact vs effort
- Generate improvement reports
**Output**: Project stats, quick win recommendations, prioritized task list
---
## More Examples
Check the [QUICKSTART.md](../docs/QUICKSTART.md) for:
- Full workflow examples (Figma → DSS → Storybook)
- REST API usage
- MCP tool integration
- Production deployment patterns
## Adding Your Own Examples
1. Create a new file: `examples/XX_your_example.py`
2. Add docstring explaining the example
3. Use `async def main()` pattern
4. Add to this README
5. Submit PR!
## Common Patterns
### Basic Example Structure
```python
#!/usr/bin/env python3
"""Brief description of what this example demonstrates"""
import asyncio
import sys
from pathlib import Path
# Add project to path
sys.path.insert(0, str(Path(__file__).parent.parent))
async def main():
print("=" * 60)
print("EXAMPLE TITLE")
print("=" * 60)
# Your code here
if __name__ == "__main__":
asyncio.run(main())
```
### Error Handling
```python
try:
result = await some_operation()
print(f"✅ Success: {result}")
except Exception as e:
print(f"❌ Error: {e}")
```
## Need Help?
- Read [QUICKSTART.md](../docs/QUICKSTART.md) for detailed guides
- Check [ARCHITECTURE.md](../docs/ARCHITECTURE.md) for system design
- Review [PROJECT_MEMORY.md](../PROJECT_MEMORY.md) for module inventory

613
examples/merge_cases.py Executable file
View File

@@ -0,0 +1,613 @@
"""
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())