agent-Specialization/scripts/color_map.py

83 lines
2.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
color_map.py —— 硬编码色值 → token 反查。
解析 _tokens.scss 各主题真实值,对给定色值判定它等于哪个 tokenA类或无对应B类
用法:
python3 scripts/color_map.py <file> # 分析某文件里所有硬编码色的可映射性
"""
import sys, re, os
from collections import defaultdict
TOK = "static/src/styles/base/_tokens.scss"
def norm(v):
"""归一化色值:小写、去多余空格、#abc->#aabbcc、rgb 空格统一。"""
v = v.strip().lower()
v = re.sub(r'\s+', '', v)
m = re.fullmatch(r'#([0-9a-f])([0-9a-f])([0-9a-f])', v)
if m:
v = '#' + ''.join(c*2 for c in m.groups())
return v
def load_tokens():
txt = open(TOK, encoding='utf-8').read()
# semantic blocks only ([data-theme])
themes = {}
for m in re.finditer(r":root\[data-theme='([^']+)'\]\s*\{([^}]*)\}", txt):
name, body = m.group(1), m.group(2)
d = {}
for dm in re.finditer(r'(--[a-z0-9-]+)\s*:\s*([^;]+);', body):
d[norm(dm.group(2))] = dm.group(1)
themes[name] = d
return themes
def analyze(path, themes):
text = open(path, encoding='utf-8').read()
# only style content for vue
if path.endswith('.vue'):
style = '\n'.join(m.group(1) for m in re.finditer(r'<style[^>]*>(.*?)</style>', text, re.S|re.I))
else:
style = text
style = re.sub(r'/\*.*?\*/', '', style, flags=re.S)
style = re.sub(r'//[^\n]*', '', style)
vals = re.findall(r'#[0-9a-fA-F]{3,8}\b|rgba?\([0-9 ,.%/]+\)|hsla?\([0-9 ,.%/]+\)', style)
A = defaultdict(list) # value -> [(theme, token)]
B = defaultdict(int) # value -> count (no match)
counts = defaultdict(int)
for raw in vals:
n = norm(raw)
counts[raw] += 1
hits = []
for tname, d in themes.items():
if n in d:
hits.append((tname, d[n]))
if hits:
A[raw] = hits
else:
B[raw] += 1
return counts, A, B
def main():
themes = load_tokens()
path = sys.argv[1]
counts, A, B = analyze(path, themes)
print(f"=== {path} ===")
print(f"硬编码色值种类: {len(counts)}, 总出现: {sum(counts.values())}")
print(f"\n--- A类(有 token 对应, 可映射) ---")
for v in sorted(A, key=lambda x:-counts[x]):
# 取 classic 优先的 token 名
toks = {t:tok for t,tok in A[v]}
cls = toks.get('classic')
shown = cls or list(toks.values())[0]
themes_hit = ','.join(sorted(toks.keys()))
print(f" {counts[v]:3d}× {v:32s} -> {shown:28s} (命中主题: {themes_hit})")
print(f"\n--- B类(无 token 对应, 野色, 需决策) ---")
for v in sorted(B, key=lambda x:-B[x]):
print(f" {B[v]:3d}× {v}")
if not B:
print(" (无 — 此文件可全量安全迁移)")
if __name__ == '__main__':
main()