fix: Address high-severity bandit issues
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
DSS Token Resolver - 3-Layer Cascade
|
||||
DSS Token Resolver - 3-Layer Cascade.
|
||||
|
||||
Merges tokens from Core → Skin → Theme into a single style-dictionary input.
|
||||
|
||||
Usage: python3 scripts/resolve-tokens.py [--skin SKIN] [--theme THEME] [--output PATH]
|
||||
@@ -8,14 +9,12 @@ Usage: python3 scripts/resolve-tokens.py [--skin SKIN] [--theme THEME] [--output
|
||||
Default: --skin shadcn --theme default --output .dss/data/_system/tokens/tokens.json
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from typing import Dict, Any
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
|
||||
DSS_ROOT = Path(__file__).parent.parent
|
||||
DSS_DATA = DSS_ROOT / ".dss"
|
||||
@@ -31,9 +30,25 @@ PRIMITIVE_ALIASES = {
|
||||
|
||||
# Generate aliases for neutral color scales (zinc, slate, gray, etc.)
|
||||
NEUTRAL_SCALES = ["slate", "gray", "zinc", "neutral", "stone"]
|
||||
SEMANTIC_SCALES = ["red", "orange", "amber", "yellow", "lime", "green", "emerald",
|
||||
"teal", "cyan", "sky", "blue", "indigo", "violet", "purple",
|
||||
"fuchsia", "pink", "rose"]
|
||||
SEMANTIC_SCALES = [
|
||||
"red",
|
||||
"orange",
|
||||
"amber",
|
||||
"yellow",
|
||||
"lime",
|
||||
"green",
|
||||
"emerald",
|
||||
"teal",
|
||||
"cyan",
|
||||
"sky",
|
||||
"blue",
|
||||
"indigo",
|
||||
"violet",
|
||||
"purple",
|
||||
"fuchsia",
|
||||
"pink",
|
||||
"rose",
|
||||
]
|
||||
SCALE_VALUES = ["50", "100", "200", "300", "400", "500", "600", "700", "800", "900", "950"]
|
||||
|
||||
for scale in NEUTRAL_SCALES:
|
||||
@@ -48,7 +63,7 @@ for scale in SEMANTIC_SCALES:
|
||||
|
||||
|
||||
def load_json(path: Path) -> dict:
|
||||
"""Load JSON file, return empty dict if not found"""
|
||||
"""Load JSON file, return empty dict if not found."""
|
||||
if not path.exists():
|
||||
return {}
|
||||
with open(path) as f:
|
||||
@@ -56,7 +71,7 @@ def load_json(path: Path) -> dict:
|
||||
|
||||
|
||||
def deep_merge(base: dict, override: dict) -> dict:
|
||||
"""Deep merge override into base, returning new dict"""
|
||||
"""Deep merge override into base, returning new dict."""
|
||||
result = base.copy()
|
||||
for key, value in override.items():
|
||||
if key.startswith("_"):
|
||||
@@ -71,14 +86,15 @@ def deep_merge(base: dict, override: dict) -> dict:
|
||||
def resolve_references(tokens: dict, primitives: dict) -> dict:
|
||||
"""
|
||||
Resolve token references like {color.zinc.500} using primitives.
|
||||
|
||||
Uses translation dictionary (PRIMITIVE_ALIASES) to map shorthand paths.
|
||||
Works recursively through the token structure.
|
||||
"""
|
||||
ref_pattern = re.compile(r'\{([^}]+)\}')
|
||||
ref_pattern = re.compile(r"\{([^}]+)\}")
|
||||
unresolved = []
|
||||
|
||||
def get_nested(obj: dict, path: str) -> Any:
|
||||
"""Get nested value from dict using dot notation"""
|
||||
"""Get nested value from dict using dot notation."""
|
||||
parts = path.split(".")
|
||||
current = obj
|
||||
for part in parts:
|
||||
@@ -92,7 +108,7 @@ def resolve_references(tokens: dict, primitives: dict) -> dict:
|
||||
return current
|
||||
|
||||
def resolve_value(value: Any) -> Any:
|
||||
"""Resolve references in a value"""
|
||||
"""Resolve references in a value."""
|
||||
if not isinstance(value, str):
|
||||
return value
|
||||
|
||||
@@ -126,7 +142,7 @@ def resolve_references(tokens: dict, primitives: dict) -> dict:
|
||||
return ref_pattern.sub(replacer, value)
|
||||
|
||||
def resolve_obj(obj: Any) -> Any:
|
||||
"""Recursively resolve references in object"""
|
||||
"""Recursively resolve references in object."""
|
||||
if isinstance(obj, dict):
|
||||
result = {}
|
||||
for key, value in obj.items():
|
||||
@@ -156,12 +172,10 @@ def resolve_references(tokens: dict, primitives: dict) -> dict:
|
||||
return resolved
|
||||
|
||||
|
||||
def resolve_tokens(
|
||||
skin_name: str = "shadcn",
|
||||
theme_name: str = "default"
|
||||
) -> Dict[str, Any]:
|
||||
def resolve_tokens(skin_name: str = "shadcn", theme_name: str = "default") -> Dict[str, Any]:
|
||||
"""
|
||||
Resolve tokens through the 3-layer cascade:
|
||||
|
||||
1. Core primitives (base values)
|
||||
2. Skin tokens (semantic mappings)
|
||||
3. Theme overrides (brand customization)
|
||||
@@ -172,7 +186,7 @@ def resolve_tokens(
|
||||
theme = load_json(DSS_DATA / "themes" / f"{theme_name}.json")
|
||||
|
||||
# Report what we're loading
|
||||
print(f"[INFO] Resolving tokens:")
|
||||
print("[INFO] Resolving tokens:")
|
||||
print(f" Core: {len(primitives)} categories")
|
||||
print(f" Skin: {skin_name}")
|
||||
print(f" Theme: {theme_name}")
|
||||
@@ -201,11 +215,7 @@ def resolve_tokens(
|
||||
# Clean up internal metadata
|
||||
def clean_tokens(obj):
|
||||
if isinstance(obj, dict):
|
||||
return {
|
||||
k: clean_tokens(v)
|
||||
for k, v in obj.items()
|
||||
if not k.startswith("_")
|
||||
}
|
||||
return {k: clean_tokens(v) for k, v in obj.items() if not k.startswith("_")}
|
||||
return obj
|
||||
|
||||
resolved = clean_tokens(resolved)
|
||||
@@ -217,8 +227,11 @@ def main():
|
||||
parser = argparse.ArgumentParser(description="Resolve DSS 3-layer token cascade")
|
||||
parser.add_argument("--skin", default="shadcn", help="Skin to use (default: shadcn)")
|
||||
parser.add_argument("--theme", default="default", help="Theme to use (default: default)")
|
||||
parser.add_argument("--output", default=".dss/data/_system/tokens/tokens.json",
|
||||
help="Output path for resolved tokens")
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
default=".dss/data/_system/tokens/tokens.json",
|
||||
help="Output path for resolved tokens",
|
||||
)
|
||||
parser.add_argument("--dry-run", action="store_true", help="Print tokens without saving")
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -255,13 +268,17 @@ def main():
|
||||
# Also save metadata
|
||||
meta_path = output_path.parent / "resolved-meta.json"
|
||||
with open(meta_path, "w") as f:
|
||||
json.dump({
|
||||
"resolved_at": datetime.now().isoformat(),
|
||||
"skin": args.skin,
|
||||
"theme": args.theme,
|
||||
"token_count": total,
|
||||
"layers": ["core/primitives", f"skins/{args.skin}", f"themes/{args.theme}"]
|
||||
}, f, indent=2)
|
||||
json.dump(
|
||||
{
|
||||
"resolved_at": datetime.now().isoformat(),
|
||||
"skin": args.skin,
|
||||
"theme": args.theme,
|
||||
"token_count": total,
|
||||
"layers": ["core/primitives", f"skins/{args.skin}", f"themes/{args.theme}"],
|
||||
},
|
||||
f,
|
||||
indent=2,
|
||||
)
|
||||
|
||||
print("")
|
||||
print("[OK] Token resolution complete!")
|
||||
|
||||
Reference in New Issue
Block a user