d38-round9-tokens.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #!/usr/bin/env node
  2. /**
  3. * D38: 第九轮——跨页重复色(≥3 处)提升为 uni.scss 全局令牌
  4. *
  5. * 依据 AGENTS.md / uni.scss §14 约定:同一色值在 ≥2~4 个文件出现即提升全局,
  6. * 单页专有色阶仍留在页面级 `$c-*`。本脚本幂等:已存在的令牌/规则不会重复写入。
  7. *
  8. * 用法: node scripts/d38-round9-tokens.js [--dry]
  9. */
  10. const fs = require('fs');
  11. const TOKENS = [
  12. ['$facade-fill-slate-25', '#F2F4F7', '冷调极浅底(教师端表单/计划卡)'],
  13. ['$facade-fill-slate-50-2', '#F7F9FC', '冷调浅底(与既有 $facade-fill-slate-50 #F8FAFC 区分)'],
  14. ['$facade-text-slate-600', '#5A6478', '深岩灰正文(教师端计划/AI 提示)'],
  15. ['$facade-text-gray-600', '#4B5563', '中性灰正文(活动详情/通用说明)'],
  16. ['$facade-ink-navy', '#1A2A4A', '藏青标题(门禁/深色卡片标题)'],
  17. ['$status-danger-light-2', '#FCA5A5', '错误浅色(挑战卡/失败态描边)'],
  18. ['$status-danger-strong-3', '#E53E3E', '错误深色(问卷/报告异常值)'],
  19. ['$status-danger-tint-4', '#FDE8E8', '错误极浅底(驳回/异常标签底)'],
  20. ['$status-danger-tint-5', '#FFF0F0', '错误极浅底之二(报告确认提示底)'],
  21. ['$status-warning-amber', '#FFC107', '琥珀警示(评分/星级)'],
  22. ['$status-warning-4', '#E6A23C', 'Element 警示橙(反馈弹窗)'],
  23. ['$status-warning-gold', '#F0B429', '暖金警示(报告列表徽标)'],
  24. ['$mat-green-700', '#388E3C', 'Material 绿 700(完成/通过)'],
  25. ['$mat-deep-orange', '#FF5722', 'Material 深橙(记录详情强调)'],
  26. ['$tint-blue-300', '#93C5FD', '蓝 300 描边/进度(空间测试)'],
  27. ['$accent-violet-300', '#C4B5FD', '紫 300 强调(DAN 报告)'],
  28. ['$tint-sky-soft-2', '#EAF4FC', '天蓝浅底(健康反馈/我的反馈)'],
  29. ['$tint-sky-ghost', '#F0F7FF', '天蓝极浅底(报告上传/列表)'],
  30. ['$tint-green-ghost', '#F0F9EB', '绿极浅底(成员列表/成功提示)'],
  31. ['$accent-pink-tint-2', '#FCE4EC', '粉浅底(报告详情/情绪标签)'],
  32. ['$wechat-green', '#07C160', '微信品牌绿(授权/分享入口)'],
  33. ];
  34. const DRY = process.argv.includes('--dry');
  35. // ---- 1) uni.scss ----
  36. const SCSS = 'uni.scss';
  37. let scss = fs.readFileSync(SCSS, 'utf8');
  38. const eolS = scss.includes('\r\n') ? '\r\n' : '\n';
  39. const missing = TOKENS.filter(([name]) => !new RegExp('^\\s*\\' + name + '\\s*:', 'm').test(scss));
  40. if (missing.length) {
  41. const block = eolS +
  42. '// ==================== §15 第九轮 · 跨页重复色提升(2026-10-21) ====================' + eolS +
  43. '// 判据:同一色值在 ≥3 个页面/组件出现,且不属于页面专有色阶;单页色阶仍用 $c-* 留在页面内。' + eolS +
  44. missing.map(([name, hex, desc]) => `${name}: ${hex};`.padEnd(40) + `// ${desc}`).join(eolS) + eolS;
  45. scss += block;
  46. if (!DRY) fs.writeFileSync(SCSS, scss, 'utf8');
  47. console.log('uni.scss 新增令牌:', missing.length);
  48. } else {
  49. console.log('uni.scss 令牌已齐备,跳过');
  50. }
  51. // ---- 2) replace-hex-to-token.js(脚本文件统一 LF,避免整文件行尾翻新) ----
  52. const RULES = 'scripts/replace-hex-to-token.js';
  53. let rules = fs.readFileSync(RULES, 'utf8').replace(/\r\n/g, '\n');
  54. const eolR = '\n';
  55. const newRules = [];
  56. for (const [name, hex] of TOKENS) {
  57. if (rules.toUpperCase().includes("'" + hex.toUpperCase() + "'")) continue;
  58. newRules.push(` ['${hex.toUpperCase()}', '${name}'],`);
  59. newRules.push(` ['${hex.toLowerCase()}', '${name}'],`);
  60. }
  61. if (newRules.length) {
  62. const marker = '\n].sort((a, b) => b[0].length - a[0].length)';
  63. const at = rules.indexOf(marker);
  64. if (at === -1) { console.log('FAIL: 规则数组锚点未找到'); process.exit(1); }
  65. const block = eolR + ' // ---- 第九轮(跨页重复色提升,2026-10-21)----' + eolR + newRules.join(eolR);
  66. rules = rules.slice(0, at) + block + rules.slice(at);
  67. if (!DRY) fs.writeFileSync(RULES, rules, 'utf8');
  68. console.log('replace-hex-to-token.js 新增规则:', newRules.length);
  69. } else {
  70. console.log('替换规则已齐备,跳过');
  71. }