iter(g349): listbox 与 radiogroup 容器补可访问名
This commit is contained in:
@@ -1771,6 +1771,32 @@ function checkFormLabel(pkgs) {
|
||||
return issues;
|
||||
}
|
||||
|
||||
/*** 校验自定义角色容器的可访问名:无名 listbox / radiogroup 读屏只念「列表 / 组」,不说是哪一个 ***/
|
||||
function checkRoleNames(pkgs) {
|
||||
const issues = [];
|
||||
for (const pkg of pkgs) {
|
||||
if (pkg.type !== 'skin-dom') continue;
|
||||
const srcDir = path.join(ROOT, pkg.dir, 'src');
|
||||
if (!fs.existsSync(srcDir)) continue;
|
||||
for (const file of fs.readdirSync(srcDir).filter((f) => f.endsWith('.ts'))) {
|
||||
const lines = fs.readFileSync(path.join(srcDir, file), 'utf8').split(/\r?\n/);
|
||||
lines.forEach((line, i) => {
|
||||
if (!/role: '(listbox|radiogroup)'/.test(line)) return; // 卫语句:只查这两个会被念成控件容器的角色
|
||||
let depth = 0; // 花括号深度:把这次 h(...) 的入参对象整段圈出来,别扫到隔壁控件
|
||||
let text = '';
|
||||
for (let k = i; k < lines.length && k < i + 20; k++) {
|
||||
text += ' ' + lines[k];
|
||||
depth += (lines[k].match(/\{/g) ?? []).length - (lines[k].match(/\}/g) ?? []).length;
|
||||
if (depth <= 0 && k > i) break;
|
||||
}
|
||||
if (/aria-label|aria-labelledby/.test(text)) return;
|
||||
issues.push(`${pkg.name}/${file}:${i + 1} 的 ${line.trim().slice(0, 40)} 缺可访问名:读屏只会念「列表 / 组」,用户不知道是哪一个`);
|
||||
});
|
||||
}
|
||||
}
|
||||
return issues;
|
||||
}
|
||||
|
||||
/*** 校验同义词表:目标 id 必须真实存在(改名后残留会让回退指到空气),同一个词不得归两组(歧义会让结果随表序漂移) ***/
|
||||
function checkSynonyms(ids) {
|
||||
const issues = [];
|
||||
@@ -1859,6 +1885,7 @@ function cmdVerify() {
|
||||
issues.push(...checkFormSummary(pkgs)); // 汇总条必须实时重算
|
||||
issues.push(...checkFormBusy(pkgs)); // 提交忙碌态必须有可见反馈
|
||||
issues.push(...checkFormLabel(pkgs)); // 标签必须真正归属控件
|
||||
issues.push(...checkRoleNames(pkgs)); // listbox / radiogroup 必须有名字
|
||||
issues.push(...checkSynonyms(new Set(pkgs.flatMap((p) => (p.docs?.components ?? []).map((c) => c.id))))); // 同义词表指向的组件必须真实存在
|
||||
checkDarkTokens(issues);
|
||||
checkTokenParity(issues);
|
||||
@@ -1871,7 +1898,7 @@ function cmdVerify() {
|
||||
console.error(`${issues.length} violation(s)`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('verify OK (manifest ↔ docs ↔ demo 一致,文档 props ↔ 入参接口双向一致,皮肤无硬编码颜色与未定义令牌、暗色令牌齐全、tokens.json ↔ tokens.css 名字与值双源一致、@keyframes 无复制粘贴的重复帧、滚动容器全在细条规则内,README 组件清单与分组同步,backlog ↔ 留痕双向一致(编号严格递增、无重复 id、留痕时间线单调且带 +08:00,每个 iter 提交都有留痕),组合配方结构完整,MCP 工具清单三处一致,搜索同义词表目标存在且无歧义,combobox / slider / range 控件都有可访问名,toast 有 live 区域与 alert 抢占播报,表单错误文案被 aria-describedby 关联、标签归属控件(for / aria-labelledby)、重置真复位、错误环只在聚焦时亮、汇总条随校验重算、提交按钮有忙碌态,视觉回归抽查清单十九组件 × 五维度齐全)');
|
||||
console.log('verify OK (manifest ↔ docs ↔ demo 一致,文档 props ↔ 入参接口双向一致,皮肤无硬编码颜色与未定义令牌、暗色令牌齐全、tokens.json ↔ tokens.css 名字与值双源一致、@keyframes 无复制粘贴的重复帧、滚动容器全在细条规则内,README 组件清单与分组同步,backlog ↔ 留痕双向一致(编号严格递增、无重复 id、留痕时间线单调且带 +08:00,每个 iter 提交都有留痕),组合配方结构完整,MCP 工具清单三处一致,搜索同义词表目标存在且无歧义,combobox / slider / range 控件与 listbox / radiogroup 容器都有可访问名,toast 有 live 区域与 alert 抢占播报,表单错误文案被 aria-describedby 关联、标签归属控件(for / aria-labelledby)、重置真复位、错误环只在聚焦时亮、汇总条随校验重算、提交按钮有忙碌态,视觉回归抽查清单十九组件 × 五维度齐全)');
|
||||
}
|
||||
|
||||
/*** 校验 git 提交信息是否符合 COMMITTING.md 规范(参数为 message 文件路径或直接 message 文本),违规退出码 1 ***/
|
||||
|
||||
Reference in New Issue
Block a user