#!/usr/bin/env node /** * 批量替换硬编码色值为 SCSS 令牌(CSS style 块内,零视觉风险) * 用法: * node scripts/replace-hex-to-token.js --batch gray # 仅灰阶 * node scripts/replace-hex-to-token.js --batch brand # 仅品牌/状态色 * node scripts/replace-hex-to-token.js # 全部 */ const fs = require('fs') const path = require('path') const ROOT = path.resolve(__dirname, '..') const EXCLUDE_DIRS = new Set(['node_modules', 'dist', 'unpackage', '.git', 'docs']) const ALL_RULES = [ // ---- 灰阶(neutral)---- ['#FFFFFF', '$app-surface'], ['#ffffff', '$app-surface'], ['#FFF', '$app-surface'], ['#fff', '$app-surface'], ['#333333', '$facade-text-strong'], ['#333', '$facade-text-strong'], ['#666666', '$facade-text-body'], ['#666', '$facade-text-body'], ['#999999', '$facade-text-muted'], ['#999', '$facade-text-muted'], ['#F5F5F5', '$facade-fill-2'], ['#f5f5f5', '$facade-fill-2'], ['#F0F0F0', '$facade-fill'], ['#f0f0f0', '$facade-fill'], ['#FAFAFA', '$facade-fill-ghost'], ['#fafafa', '$facade-fill-ghost'], ['#F9FAFB', '$facade-fill-gray-50'], ['#f9fafb', '$facade-fill-gray-50'], ['#BBBBBB', '$facade-text-ghost-light'], ['#bbbbbb', '$facade-text-ghost-light'], ['#BBB', '$facade-text-ghost-light'], ['#bbb', '$facade-text-ghost-light'], ['#CCCCCC', '$facade-text-ghost'], ['#cccccc', '$facade-text-ghost'], ['#CCC', '$facade-text-ghost'], ['#ccc', '$facade-text-ghost'], ['#DDDDDD', '$facade-border-soft'], ['#dddddd', '$facade-border-soft'], ['#DDD', '$facade-border-soft'], ['#ddd', '$facade-border-soft'], ['#EEEEEE', '$facade-hairline-2'], ['#eeeeee', '$facade-hairline-2'], ['#EEE', '$facade-hairline-2'], ['#eee', '$facade-hairline-2'], // ---- 品牌/状态色(brand/status)---- ['#F97316', '$brand-primary'], ['#f97316', '$brand-primary'], ['#FF8C42', '$dim-body'], ['#ff8c42', '$dim-body'], ['#FFF7ED', '$uni-primary-pale'], ['#fff7ed', '$uni-primary-pale'], ['#FB923C', '$brand-primary-light'], ['#fb923c', '$brand-primary-light'], ['#10B981', '$status-success'], ['#10b981', '$status-success'], ['#EF4444', '$status-danger'], ['#ef4444', '$status-danger'], ['#6366F1', '$dim-wisdom'], ['#6366f1', '$dim-wisdom'], ['#C62828', '$status-danger-strong-2'], ['#c62828', '$status-danger-strong-2'], // ---- 第二轮(高频色,2026-10-20 批量收割)---- ['#94A3B8', '$app-text-subtle'], ['#94a3b8', '$app-text-subtle'], ['#1E293B', '$uni-text-color'], ['#1e293b', '$uni-text-color'], ['#64748B', '$uni-text-color-secondary'], ['#64748b', '$uni-text-color-secondary'], ['#E2E8F0', '$uni-border-color-light'], ['#e2e8f0', '$uni-border-color-light'], ['#F5F7FA', '$app-bg'], ['#f5f7fa', '$app-bg'], ['#667EEA', '$accent-indigo'], ['#667eea', '$accent-indigo'], ['#9CA3AF', '$facade-text-gray-400'], ['#9ca3af', '$facade-text-gray-400'], ['#FFF3E0', '$fortune-1-tint'], ['#fff3e0', '$fortune-1-tint'], ['#FED7AA', '$brand-primary-light-2'], ['#fed7aa', '$brand-primary-light-2'], ['#F1F5F9', '$facade-fill-slate'], ['#f1f5f9', '$facade-fill-slate'], ['#4CAF50', '$mat-green'], ['#4caf50', '$mat-green'], ['#E8F5E9', '$mat-green-tint'], ['#e8f5e9', '$mat-green-tint'], ['#F59E0B', '$dim-wealth'], ['#f59e0b', '$dim-wealth'], ['#F8F8F8', '$facade-fill-page'], ['#f8f8f8', '$facade-fill-page'], ['#FEF3C7', '$status-warning-soft'], ['#fef3c7', '$status-warning-soft'], ['#E65100', '$mat-orange-strong'], ['#e65100', '$mat-orange-strong'], ['#2E7D32', '$mat-green-strong'], ['#2e7d32', '$mat-green-strong'], ['#888888', '$facade-text-faint'], ['#888', '$facade-text-faint'], ['#F3F4F6', '$facade-fill-gray-100'], ['#f3f4f6', '$facade-fill-gray-100'], ['#E3F2FD', '$mat-blue-tint'], ['#e3f2fd', '$mat-blue-tint'], ['#EA580C', '$brand-primary-dark'], ['#ea580c', '$brand-primary-dark'], ['#E5E7EB', '$facade-gray-200'], ['#e5e7eb', '$facade-gray-200'], ['#E0E0E0', '$facade-hairline'], ['#e0e0e0', '$facade-hairline'], ['#1F2937', '$facade-text-gray-800'], ['#1f2937', '$facade-text-gray-800'], ['#6B7280', '$facade-text-slate'], ['#6b7280', '$facade-text-slate'], ['#F5FAFE', '$facade-fill-blue-ghost'], ['#f5fafe', '$facade-fill-blue-ghost'], ['#CBD5E1', '$uni-border-color'], ['#cbd5e1', '$uni-border-color'], ['#374151', '$facade-text-gray-700'], ['#374151', '$facade-text-gray-700'], ['#764BA2', '$accent-indigo-deep'], ['#764ba2', '$accent-indigo-deep'], ['#F8FAFC', '$facade-fill-slate-50'], ['#f8fafc', '$facade-fill-slate-50'], ['#FFD700', '$accent-gold'], ['#ffd700', '$accent-gold'], ['#1565C0', '$mat-blue-strong'], ['#1565c0', '$mat-blue-strong'], ['#DC2626', '$status-danger-deep'], ['#dc2626', '$status-danger-deep'], ['#475569', '$facade-text-slate-deep'], ['#475569', '$facade-text-slate-deep'], ['#8B5CF6', '$facade-violet'], ['#8b5cf6', '$facade-violet'], ['#334155', '$facade-text-slate-700'], ['#334155', '$facade-text-slate-700'], ['#FFB366', '$dim-body-light'], ['#ffb366', '$dim-body-light'], ['#FFEBEE', '$fortune-0-tint'], ['#ffebee', '$fortune-0-tint'], ['#34D399', '$status-success-light-3'], ['#34d399', '$status-success-light-3'], ['#1A1A2E', '$app-ink-night'], ['#1a1a2e', '$app-ink-night'], ['#E8E8E8', '$facade-fill-4'], ['#e8e8e8', '$facade-fill-4'], ['#16A34A', '$status-success-strong-2'], ['#16a34a', '$status-success-strong-2'], ['#FEE2E2', '$status-danger-soft'], ['#fee2e2', '$status-danger-soft'], ['#C2410C', '$brand-primary-deep'], ['#c2410c', '$brand-primary-deep'], ['#FFF7E6', '$brand-primary-tint-2'], ['#fff7e6', '$brand-primary-tint-2'], ['#22C55E', '$status-success-2'], ['#22c55e', '$status-success-2'], ['#3B82F6', '$status-info'], ['#3b82f6', '$status-info'], ['#2196F3', '$mat-blue-base'], ['#2196f3', '$mat-blue-base'], ['#D97706', '$status-warning-deep'], ['#d97706', '$status-warning-deep'], ['#0EA5E9', '$uni-info'], ['#0ea5e9', '$uni-info'], ['#DCFCE7', '$status-success-soft-2'], ['#dcfce7', '$status-success-soft-2'], ['#555555', '$facade-text-deep'], ['#555', '$facade-text-deep'], ['#818CF8', '$dim-wisdom-light'], ['#818cf8', '$dim-wisdom-light'], ['#FF9800', '$mat-orange-base'], ['#ff9800', '$mat-orange-base'], ['#F5F9FC', '$uni-bg-color'], ['#f5f9fc', '$uni-bg-color'], ['#F0FDF4', '$status-success-tint-2'], ['#f0fdf4', '$status-success-tint-2'], ['#D1FAE5', '$status-success-soft'], ['#d1fae5', '$status-success-soft'], ['#DBEAFE', '$status-info-soft'], ['#dbeafe', '$status-info-soft'], ['#92400E', '$status-warning-strong'], ['#92400e', '$status-warning-strong'], // ---- 第四轮(flat 设计主题,2026-10-20 收编为 $flat-* 全局令牌)---- ['#4ECDC4', '$flat-teal'], ['#4ecdc4', '$flat-teal'], ['#44B09E', '$flat-teal-deep'], ['#44b09e', '$flat-teal-deep'], ['#A8E063', '$flat-green'], ['#a8e063', '$flat-green'], ['#56AB2F', '$flat-green-deep'], ['#56ab2f', '$flat-green-deep'], ['#FFF9F0', '$flat-bg'], ['#fff9f0', '$flat-bg'], ['#FFF5EB', '$flat-card'], ['#fff5eb', '$flat-card'], ['#FFF0E6', '$flat-warm'], ['#fff0e6', '$flat-warm'], ['#F5F0EB', '$flat-line'], ['#f5f0eb', '$flat-line'], ['#2D3436', '$flat-ink'], ['#2d3436', '$flat-ink'], ['#B2BEC3', '$flat-muted'], ['#b2bec3', '$flat-muted'], ['#636E72', '$flat-muted-2'], ['#636e72', '$flat-muted-2'], ['#FFE0E0', '$flat-danger-line'], ['#ffe0e0', '$flat-danger-line'], ['#E17055', '$flat-orange-text'], ['#e17055', '$flat-orange-text'], ['#FFB088', '$flat-orange-soft'], ['#ffb088', '$flat-orange-soft'], ['#FFD93D', '$flat-bar'], ['#ffd93d', '$flat-bar'], // ---- 第五轮(现有令牌补登记,2026-10-20)---- ['#059669', '$status-success-deep'], ['#059669', '$status-success-deep'], ['#FF6B35', '$mind-accent'], ['#ff6b35', '$mind-accent'], ['#D1D5DB', '$app-border-strong'], ['#d1d5db', '$app-border-strong'], ['#FFEDD5', '$facade-brand-tint-2'], ['#ffedd5', '$facade-brand-tint-2'], ['#B45309', '$status-warning-strong-2'], ['#b45309', '$status-warning-strong-2'], ['#16213E', '$app-ink-night-2'], ['#16213e', '$app-ink-night-2'], ['#ECFDF5', '$status-success-tint'], ['#ecfdf5', '$status-success-tint'], ['#FFFBEB', '$dim-wealth-tint'], ['#fffbeb', '$dim-wealth-tint'], ['#9A3412', '$mat-orange-deep'], ['#9a3412', '$mat-orange-deep'], ['#FDE68A', '$status-warning-light'], ['#fde68a', '$status-warning-light'], ['#F0F4FF', '$dim-wisdom-tint-3'], ['#f0f4ff', '$dim-wisdom-tint-3'], ['#2563EB', '$status-info-deep'], ['#2563eb', '$status-info-deep'], ['#FFF8E1', '$mat-amber-tint'], ['#fff8e1', '$mat-amber-tint'], ['#0284C7', '$status-info-deep-2'], ['#0284c7', '$status-info-deep-2'], ['#1890FF', '$status-info-3'], ['#1890ff', '$status-info-3'], ['#EEF2FF', '$dim-wisdom-tint-2'], ['#eef2ff', '$dim-wisdom-tint-2'], ['#F9F9F9', '$facade-fill-ghost-2'], ['#f9f9f9', '$facade-fill-ghost-2'], ['#EC4899', '$accent-pink'], ['#ec4899', '$accent-pink'], // ---- 第六轮(新增全局令牌,2026-10-20)---- ['#FFF0E0', '$warm-peach'], ['#fff0e0', '$warm-peach'], ['#8A94A6', '$text-steel'], ['#8a94a6', '$text-steel'], ['#2A2A4A', '$game-ink'], ['#2a2a4a', '$game-ink'], ['#1F2D3D', '$ink-steel'], ['#1f2d3d', '$ink-steel'], ['#EDE9FE', '$violet-tint-100'], ['#ede9fe', '$violet-tint-100'], ['#8D6E63', '$brown-warm'], ['#8d6e63', '$brown-warm'], ['#F56C6C', '$el-danger'], ['#f56c6c', '$el-danger'], ['#F44336', '$mat-red'], ['#f44336', '$mat-red'], ['#52C41A', '$status-success-3'], ['#52c41a', '$status-success-3'], ['#1A1A1A', '$text-charcoal'], ['#1a1a1a', '$text-charcoal'], ['#AAA', '$text-ghost-soft'], ['#aaa', '$text-ghost-soft'], // ---- 第七轮(2026-10-21)---- ['#FEF2F2', '$status-danger-tint-2'], ['#fef2f2', '$status-danger-tint-2'], ['#FFA500', '$accent-gold-deep'], ['#ffa500', '$accent-gold-deep'], ['#38BDF8', '$status-info-light'], ['#38bdf8', '$status-info-light'], ['#FF4D4F', '$status-danger-2'], ['#ff4d4f', '$status-danger-2'], ['#E6F7FF', '$status-info-tint-3'], ['#e6f7ff', '$status-info-tint-3'], ['#FF6B9D', '$dim-mind'], ['#ff6b9d', '$dim-mind'], ['#1E3A5F', '$accent-navy'], ['#1e3a5f', '$accent-navy'], ['#1976D2', '$mat-blue'], ['#1976d2', '$mat-blue'], ['#FBBF24', '$status-warning'], ['#fbbf24', '$status-warning'], ['#FFF1E6', '$tint-warm-soft'], ['#fff1e6', '$tint-warm-soft'], ['#BAE6FD', '$tint-sky-line'], ['#bae6fd', '$tint-sky-line'], ['#F7F7F7', '$facade-fill-cool'], ['#f7f7f7', '$facade-fill-cool'], ['#F6FFED', '$status-success-tint-3'], ['#f6ffed', '$status-success-tint-3'], ['#FECACA', '$danger-line'], ['#fecaca', '$danger-line'], ['#BBDEFB', '$mat-blue-light'], ['#bbdefb', '$mat-blue-light'], ['#E0E7FF', '$accent-indigo-tint'], ['#e0e7ff', '$accent-indigo-tint'], ['#F57F17', '$mat-amber-strong'], ['#f57f17', '$mat-amber-strong'], ['#F0F9FF', '$tint-sky-soft'], ['#f0f9ff', '$tint-sky-soft'], ['#A5B4FC', '$indigo-light'], ['#a5b4fc', '$indigo-light'], ['#F57C00', '$mat-orange-700'], ['#f57c00', '$mat-orange-700'], ['#7C2D12', '$mat-orange-900'], ['#7c2d12', '$mat-orange-900'], ['#FFE66D', '$accent-yellow-light'], ['#ffe66d', '$accent-yellow-light'], ['#E64340', '$wechat-red'], ['#e64340', '$wechat-red'], ['#8A6D3B', '$brown-olive'], ['#8a6d3b', '$brown-olive'], ['#67C23A', '$el-success'], ['#67c23a', '$el-success'], ['#E5E5E5', '$facade-line'], ['#e5e5e5', '$facade-line'], ['#E0F2FE', '$tint-sky-tint'], ['#e0f2fe', '$tint-sky-tint'], ['#047857', '$status-success-deep-2'], ['#047857', '$status-success-deep-2'], ['#FF6B6B', '$accent-coral'], ['#ff6b6b', '$accent-coral'], ['#FCD34D', '$accent-amber-light'], ['#fcd34d', '$accent-amber-light'], ['#42A5F5', '$mat-blue-400'], ['#42a5f5', '$mat-blue-400'], ['#166534', '$mat-green-800'], ['#166534', '$mat-green-800'], ['#FDBA74', '$mat-orange-300'], ['#fdba74', '$mat-orange-300'], ['#FFE0B2', '$mat-orange-100'], ['#ffe0b2', '$mat-orange-100'], ['#C8E6C9', '$mat-green-100'], ['#c8e6c9', '$mat-green-100'], ['#ECEFF1', '$mat-bluegray-50'], ['#eceff1', '$mat-bluegray-50'], ['#78909C', '$mat-bluegray-400'], ['#78909c', '$mat-bluegray-400'], ['#6D28D9', '$violet-700'], ['#6d28d9', '$violet-700'], ['#D6EAF8', '$tint-sky-blue'], ['#d6eaf8', '$tint-sky-blue'], ['#FF4444', '$danger-bright'], ['#ff4444', '$danger-bright'], // ---- 第八轮(uni.scss 已有令牌补登记,2026-10-21)---- ['#43A047', '$mat-green-base-2'], ['#43a047', '$mat-green-base-2'], ['#EDF2F7', '$uni-bg-color-grey'], ['#edf2f7', '$uni-bg-color-grey'], ['#7C3AED', '$facade-violet-deep'], ['#7c3aed', '$facade-violet-deep'], ['#FA8C16', '$brand-primary-2'], ['#fa8c16', '$brand-primary-2'], ['#065F46', '$status-success-strong'], ['#065f46', '$status-success-strong'], ['#BBF7D0', '$tint-green-line'], ['#bbf7d0', '$tint-green-line'], ['#FFF3E6', '$warm-cream'], ['#fff3e6', '$warm-cream'], ['#F3E5F5', '$fortune-3-tint'], ['#f3e5f5', '$fortune-3-tint'], ['#7B1FA2', '$fortune-3-ink'], ['#7b1fa2', '$fortune-3-ink'], ['#B8860B', '$hint-gold-ink'], ['#b8860b', '$hint-gold-ink'], ['#F9F9FF', '$dim-wisdom-tint-5'], ['#f9f9ff', '$dim-wisdom-tint-5'], ['#66BB6A', '$mat-green-light-2'], ['#66bb6a', '$mat-green-light-2'], ['#A5D6A7', '$mat-green-soft'], ['#a5d6a7', '$mat-green-soft'], ['#FFE4CC', '$tint-warm-edge'], ['#ffe4cc', '$tint-warm-edge'], ['#F87171', '$status-danger-light'], ['#f87171', '$status-danger-light'], ['#A78BFA', '$facade-violet-light'], ['#a78bfa', '$facade-violet-light'], ['#FFF8F0', '$dim-body-tint'], ['#fff8f0', '$dim-body-tint'], ['#3730A3', '$dim-wisdom-ink'], ['#3730a3', '$dim-wisdom-ink'], ['#F5F6FA', '$app-bg-2'], ['#f5f6fa', '$app-bg-2'], ['#F5F3FF', '$facade-violet-tint-2'], ['#f5f3ff', '$facade-violet-tint-2'], ['#F0F0FF', '$dim-wisdom-tint'], ['#f0f0ff', '$dim-wisdom-tint'], ['#4338CA', '$accent-indigo-ink'], ['#4338ca', '$accent-indigo-ink'], ['#1D4ED8', '$status-info-deep-3'], ['#1d4ed8', '$status-info-deep-3'], ['#FFF5F5', '$status-danger-tint'], ['#fff5f5', '$status-danger-tint'], ['#EFF6FF', '$status-info-tint'], ['#eff6ff', '$status-info-tint'], ['#F08A7A', '$uni-warm'], ['#f08a7a', '$uni-warm'], ['#FF8FB1', '$dim-mind-light-2'], ['#ff8fb1', '$dim-mind-light-2'], ['#A7F3D0', '$status-success-light'], ['#a7f3d0', '$status-success-light'], ['#444', '$facade-text-deep-2'], ['#444', '$facade-text-deep-2'], ['#4F46E5', '$dim-wisdom-deep'], ['#4f46e5', '$dim-wisdom-deep'], ['#F7F8FA', '$app-surface-subtle'], ['#f7f8fa', '$app-surface-subtle'], ['#A855F7', '$facade-violet-light-2'], ['#a855f7', '$facade-violet-light-2'], ['#81C784', '$mat-green-light'], ['#81c784', '$mat-green-light'], ['#BFDBFE', '$tint-blue-line'], ['#bfdbfe', '$tint-blue-line'], ['#FFF1F0', '$status-danger-tint-3'], ['#fff1f0', '$status-danger-tint-3'], ['#C7D2FE', '$tint-indigo-line'], ['#c7d2fe', '$tint-indigo-line'], ['#FCE7F3', '$accent-pink-tint'], ['#fce7f3', '$accent-pink-tint'], ['#FEF9E7', '$hint-cream-bg'], ['#fef9e7', '$hint-cream-bg'], ['#F0E6C0', '$hint-cream-border'], ['#f0e6c0', '$hint-cream-border'], ['#F3E8FF', '$tint-purple-soft'], ['#f3e8ff', '$tint-purple-soft'], ].sort((a, b) => b[0].length - a[0].length) const GRAY_RULES = ALL_RULES.filter(r => { const i = ALL_RULES.indexOf(r); return i < 30 }) const BRAND_RULES = ALL_RULES.filter(r => { const i = ALL_RULES.indexOf(r); return i >= 30 }) const SECOND_RULES = ALL_RULES.filter(r => { const i = ALL_RULES.indexOf(r); return i >= 30 }) const batch = process.argv.find(a => a.startsWith('--batch='))?.split('=')[1] const rules = batch === 'brand' ? BRAND_RULES : batch === 'gray' ? GRAY_RULES : ALL_RULES const label = batch === 'brand' ? '品牌/状态色' : batch === 'gray' ? '灰阶' : '全部' console.log(`\n批次: ${label} 规则数: ${rules.length}\n`) function walk(dir, out = []) { for (const name of fs.readdirSync(dir)) { if (EXCLUDE_DIRS.has(name)) continue const p = path.join(dir, name) const st = fs.statSync(p) if (st.isDirectory()) walk(p, out) else if (name.endsWith('.vue')) out.push(p) } return out } function countReplacements(text, rules) { let n = 0 for (const [hex] of rules) { const escaped = hex.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') n += (text.match(new RegExp(escaped + '(?![0-9a-fA-F])', 'g')) || []).length } return n } function applyRules(text, rules) { let result = text for (const [hex, token] of rules) { const escaped = hex.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') result = result.replace(new RegExp(escaped + '(?![0-9a-fA-F])', 'g'), token) } return result } function processFile(filePath) { const src = fs.readFileSync(filePath, 'utf8') // 按 " const replCount = countReplacements(body, rules) if (replCount === 0) continue const newBody = applyRules(body, rules) totalRepl += replCount // 若