#!/usr/bin/env node /** * 品牌色/令牌引用完整性审计 * * 检查美化治理过程中容易出现的四类回归(均为真实踩过的坑): * 1) 'BrandColors.xxx' 字符串字面量 —— 字符串不是变量,作为颜色值无效 * 2) BrandColors.xxx 使用但未 import —— 运行时 ReferenceError / undefined * 3) import 落在 之后 —— 模块作用域外,运行时标识符未定义 * 4) 从 utils/brand-colors.js 具名导入不存在的导出 —— 值为 undefined * * 用法: node scripts/audit-brandcolor-integrity.js * 退出码: 0 通过 / 1 存在问题 */ const fs = require('fs') const path = require('path') const ROOT = path.resolve(__dirname, '..') const EXCLUDE_DIRS = new Set(['node_modules', 'dist', 'unpackage', '.git', 'scripts', 'docs', '.tmp_equiv']) const SKIP_FILES = new Set(['components/mp-html/node/node.vue']) // mp-html 源码保持原样 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 } const bcSrc = fs.readFileSync(path.join(ROOT, 'utils/brand-colors.js'), 'utf8') const exportsSet = new Set() for (const m of bcSrc.matchAll(/export\s+const\s+(\w+)/g)) exportsSet.add(m[1]) for (const m of bcSrc.matchAll(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*:\s*'/gm)) exportsSet.add(m[1]) exportsSet.add('default') const issues = { stringLiteral: [], missingImport: [], strayImport: [], badNamedImport: [] } for (const abs of walk(ROOT)) { const rel = path.relative(ROOT, abs).split(path.sep).join('/') if (SKIP_FILES.has(rel)) continue const src = fs.readFileSync(abs, 'utf8') const scriptIdx = src.search(/ 之后', badNamedImport: 'brand-colors 具名导入不存在', } let failed = 0 for (const [key, list] of Object.entries(issues)) { if (list.length) failed += list.length console.log(labels[key] + ': ' + list.length) list.slice(0, 20).forEach(x => console.log(' - ' + x)) } console.log(failed === 0 ? 'PASS' : 'FAIL(' + failed + ')') process.exit(failed === 0 ? 0 : 1)