iter(g186): 固化视觉回归抽查清单
This commit is contained in:
@@ -1235,6 +1235,52 @@ function checkPropsDoc(pkg, comps) {
|
||||
return issues;
|
||||
}
|
||||
|
||||
/*** 视觉回归抽查清单校验:ITERATION.md 的清单必须六个高频组件齐全、每条带合法维度标签、条目数达标 ***/
|
||||
function checkVisualChecklist() {
|
||||
const DIMS = ['边框', '阴影', '过渡', '焦点环', '暗色']; // 五个必覆盖维度
|
||||
const REQUIRED = ['button', 'textField', 'select', 'modal', 'dataTable', 'toast']; // 六个代表组件
|
||||
const MIN_PER_GROUP = 3; // 每个组件至少三条可勾选要点
|
||||
const MIN_TOTAL = 18; // 清单总条目下限
|
||||
const file = path.join(ROOT, 'ITERATION.md');
|
||||
if (!fs.existsSync(file)) return ['视觉回归抽查清单:找不到 ITERATION.md'];
|
||||
const lines = fs.readFileSync(file, 'utf8').replace(/\r\n/g, '\n').split('\n');
|
||||
const start = lines.findIndex((l) => /^##\s+视觉回归抽查清单/.test(l));
|
||||
if (start === -1) return ['视觉回归抽查清单:ITERATION.md 缺少《视觉回归抽查清单》章节'];
|
||||
const rest = lines.slice(start + 1);
|
||||
const stop = rest.findIndex((l) => /^##\s+/.test(l)); // 下一个二级标题即章节结束
|
||||
const body = stop === -1 ? rest : rest.slice(0, stop);
|
||||
const issues = [];
|
||||
const groups = new Map(); // 组件 id → 该段的维度标签列表
|
||||
let current = null;
|
||||
for (const line of body) {
|
||||
const head = line.match(/^###\s+(\S+)/);
|
||||
if (head) {
|
||||
current = head[1];
|
||||
if (!groups.has(current)) groups.set(current, []);
|
||||
continue;
|
||||
}
|
||||
const item = line.match(/^-\s+\[[ x]\]\s+【([^】]+)】/);
|
||||
if (!item) continue;
|
||||
if (!current) {
|
||||
issues.push(`视觉回归抽查清单:条目「${line.trim().slice(0, 24)}」没有归到任何 ### 组件段下`);
|
||||
continue;
|
||||
}
|
||||
if (!DIMS.includes(item[1])) issues.push(`视觉回归抽查清单:${current} 的条目维度「${item[1]}」不在五类之内(${DIMS.join(' / ')})`);
|
||||
groups.get(current).push(item[1]);
|
||||
}
|
||||
for (const id of REQUIRED) {
|
||||
const items = groups.get(id);
|
||||
if (!items) issues.push(`视觉回归抽查清单:缺少 ### ${id} 段`);
|
||||
else if (items.length < MIN_PER_GROUP) issues.push(`视觉回归抽查清单:${id} 只有 ${items.length} 条要点,至少 ${MIN_PER_GROUP} 条`);
|
||||
}
|
||||
const total = [...groups.values()].reduce((sum, items) => sum + items.length, 0);
|
||||
if (total < MIN_TOTAL) issues.push(`视觉回归抽查清单:合计 ${total} 条要点,至少 ${MIN_TOTAL} 条`);
|
||||
const covered = new Set([...groups.values()].flat());
|
||||
const missed = DIMS.filter((d) => !covered.has(d));
|
||||
if (missed.length) issues.push(`视觉回归抽查清单:维度未覆盖 ${missed.join(' / ')}(五类都要有)`);
|
||||
return issues;
|
||||
}
|
||||
|
||||
/*** 清单一致性校验:组件文档块的 id / props 说明 / demo 锚点必须与代码和演示产物对齐 ***/
|
||||
function cmdVerify() {
|
||||
const issues = [];
|
||||
@@ -1290,13 +1336,14 @@ function cmdVerify() {
|
||||
checkDarkTokens(issues);
|
||||
checkLlmsFull(pkgs, issues);
|
||||
issues.push(...checkIterations());
|
||||
issues.push(...checkVisualChecklist());
|
||||
|
||||
if (issues.length) {
|
||||
for (const it of issues) console.error('verify: ' + it);
|
||||
console.error(`${issues.length} violation(s)`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('verify OK (manifest ↔ docs ↔ demo 一致,文档 props ↔ 入参接口双向一致,皮肤无硬编码颜色与未定义令牌、暗色令牌齐全,README 组件清单与分组同步,backlog ↔ 留痕一致(编号严格递增、无重复 id、留痕时间线单调且带 +08:00),组合配方结构完整,MCP 工具清单三处一致)');
|
||||
console.log('verify OK (manifest ↔ docs ↔ demo 一致,文档 props ↔ 入参接口双向一致,皮肤无硬编码颜色与未定义令牌、暗色令牌齐全,README 组件清单与分组同步,backlog ↔ 留痕一致(编号严格递增、无重复 id、留痕时间线单调且带 +08:00),组合配方结构完整,MCP 工具清单三处一致,视觉回归抽查清单六组件 × 五维度齐全)');
|
||||
}
|
||||
|
||||
/*** 校验 git 提交信息是否符合 COMMITTING.md 规范(参数为 message 文件路径或直接 message 文本),违规退出码 1 ***/
|
||||
|
||||
Reference in New Issue
Block a user