#!/usr/bin/env python3 """ DSS Token Validator Hook Detects hardcoded values that should use design tokens. Written from scratch for DSS. """ import json import re import sys from pathlib import Path # Patterns for hardcoded values that should be tokens HARDCODED_PATTERNS = [ { "id": "color-hex", "regex": r"(? bool: """Check if match is in allowlist.""" for pattern in ALLOWLIST: if re.search(pattern, match, re.IGNORECASE): return True return False def check_content(content: str, file_path: str, config: dict) -> list: """Check content for hardcoded values.""" issues = [] file_ext = Path(file_path).suffix.lower() enabled_categories = config.get("token_validator", {}).get("categories", []) for pattern_def in HARDCODED_PATTERNS: # Skip if file type doesn't match if file_ext not in pattern_def.get("file_types", []): continue # Skip if category not enabled (unless empty = all) if enabled_categories and pattern_def["category"] not in enabled_categories: continue matches = re.findall(pattern_def["regex"], content, re.IGNORECASE) for match in matches: if not is_allowlisted(match): issues.append({ "id": pattern_def["id"], "category": pattern_def["category"], "message": pattern_def["message"], "suggestion": pattern_def["suggestion"], "value": match[:50] # Truncate long matches }) # Deduplicate by id seen = set() unique_issues = [] for issue in issues: if issue["id"] not in seen: seen.add(issue["id"]) unique_issues.append(issue) return unique_issues def format_output(issues: list, file_path: str) -> str: """Format issues for display.""" if not issues: return "" category_icons = { "color": "[COLOR]", "spacing": "[SPACE]", "typography": "[FONT]", "border": "[BORDER]", "effects": "[EFFECT]", "layout": "[LAYOUT]" } lines = [f"\n=== DSS Token Validator: {file_path} ===\n"] for issue in issues: icon = category_icons.get(issue["category"], "[TOKEN]") lines.append(f"{icon} {issue['message']}") lines.append(f" Found: {issue['value']}") lines.append(f" {issue['suggestion']}\n") lines.append("=" * 50) return "\n".join(lines) def main(): """Main hook entry point.""" config = get_config() if not config.get("token_validator", {}).get("enabled", True): sys.exit(0) # Read hook input from stdin try: input_data = json.loads(sys.stdin.read()) except json.JSONDecodeError: sys.exit(0) tool_name = input_data.get("tool_name", "") tool_input = input_data.get("tool_input", {}) if tool_name not in ["Edit", "Write"]: sys.exit(0) file_path = tool_input.get("file_path", "") # Get content to check if tool_name == "Write": content = tool_input.get("content", "") elif tool_name == "Edit": content = tool_input.get("new_string", "") else: content = "" if not content or not file_path: sys.exit(0) # Check for token issues issues = check_content(content, file_path, config) if issues: output = format_output(issues, file_path) print(output, file=sys.stderr) # In strict mode, block on issues if config.get("token_validator", {}).get("strict_mode", False): sys.exit(2) sys.exit(0) if __name__ == "__main__": main()