probe-token-litter.mjs 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. // 票 15 盘点(只读):组件内散落的主题色字面量清点,用于设计 token 替换面
  2. // 输出:按「色值族」聚合的 (文件, 出现次数, 出现的 alpha/形态)
  3. import { readFileSync } from 'node:fs'
  4. import { readdirSync, statSync } from 'node:fs'
  5. import { join, relative } from 'node:path'
  6. const root = 'src/modules/cockpit'
  7. const files = []
  8. ;(function walk(dir) {
  9. for (const e of readdirSync(dir)) {
  10. const p = join(dir, e)
  11. if (statSync(p).isDirectory()) walk(p)
  12. else if (/\.(vue|js|css)$/.test(e)) files.push(p)
  13. }
  14. })(root)
  15. const THEME = {
  16. cyan: /#4fd8ff|rgba?\(\s*79\s*,\s*216\s*,\s*255/gi,
  17. cyanD: /#1b93cf|rgba?\(\s*27\s*,\s*147\s*,\s*207/gi,
  18. line: /rgba?\(\s*58\s*,\s*170\s*,\s*226/gi,
  19. lineHi: /rgba?\(\s*96\s*,\s*220\s*,\s*255/gi,
  20. insetHi: /rgba?\(\s*130\s*,\s*225\s*,\s*255/gi,
  21. lv1: /#ff4d5e|rgba?\(\s*255\s*,\s*77\s*,\s*94/gi,
  22. lv2: /#ffa63d|rgba?\(\s*255\s*,\s*166\s*,\s*61/gi,
  23. lv4: /#35e39a|rgba?\(\s*53\s*,\s*227\s*,\s*154/gi,
  24. neutral: /#6d92ae|rgba?\(\s*109\s*,\s*146\s*,\s*174/gi,
  25. text: /#e6f5ff/gi,
  26. text2: /#a8cbe2/gi,
  27. title: /#eaf9ff/gi,
  28. panelTopBase: /rgba?\(\s*12\s*,\s*48\s*,\s*86/gi,
  29. panelBotBase: /rgba?\(\s*3\s*,\s*14\s*,\s*28/gi,
  30. panelMid: /rgba?\(\s*6\s*,\s*24\s*,\s*44/gi,
  31. headGradA: /rgba?\(\s*24\s*,\s*96\s*,\s*152/gi,
  32. headGradB: /rgba?\(\s*12\s*,\s*52\s*,\s*90/gi,
  33. headGradC: /rgba?\(\s*90\s*,\s*200\s*,\s*255/gi,
  34. headHoverA: /rgba?\(\s*34\s*,\s*116\s*,\s*176/gi,
  35. headHoverB: /rgba?\(\s*16\s*,\s*66\s*,\s*110/gi,
  36. blueText: /#9dc2d9/gi,
  37. mapBg: /#04121f/gi,
  38. }
  39. const rows = []
  40. for (const f of files) {
  41. const src = readFileSync(f, 'utf8')
  42. for (const [name, re] of Object.entries(THEME)) {
  43. const hits = src.match(re)
  44. if (hits) {
  45. const variants = [...new Set(hits.map((h) => h.replace(/\s+/g, '')))]
  46. rows.push({ family: name, file: relative('.', f), count: hits.length, variants: variants.slice(0, 12).join(' ') })
  47. }
  48. }
  49. }
  50. const byFamily = new Map()
  51. for (const r of rows) {
  52. const cur = byFamily.get(r.family) || { total: 0, files: new Map() }
  53. cur.total += r.count
  54. cur.files.set(r.file, r)
  55. byFamily.set(r.family, cur)
  56. }
  57. for (const [family, v] of [...byFamily.entries()].sort((a, b) => b[1].total - a[1].total)) {
  58. console.log(`\n### ${family} 合计 ${v.total}`)
  59. for (const [file, r] of [...v.files.entries()].sort((a, b) => b[1].count - a[1].count)) {
  60. console.log(` ${String(r.count).padStart(3)} ${file}`)
  61. console.log(` 变体: ${r.variants}`)
  62. }
  63. }