Regression / regression (push) Canceled after 0s
本提交含两条并行工作线,因互相咬合(package.json scripts、regression.yml、 npm run build 链)无法按文件干净拆分,故合并为一次自洽提交。 ## 详情页减重(本轮主任务:修复「AI 干太重」) - 导航收敛:宽屏只用右侧目录、≤1200px 只用页内 sticky 导航,纯 CSS 媒体查询 实现(不引入 JS 宽度监听)。此前两套导航同时可见,active 状态互相打架。 - 入口去重:标题区由「查看示例/在线测试/契约 JSON」三个减为「在线测试」一个; 契约 JSON 归入实现资源;删除示例底部重复的「在线测试」。 - 示例工具栏:删除与目录锚点重复的示例下拉选择器;「全部展开代码」只在 示例数 >1 时出现(103 个组件里 49 个仅 1 个示例,此前恒显示)。 - 重复文案:示例区两句同义导语合并为一句。 - 首页 CTA 由 5 个减为 2 个(浏览组件/快速开始),测试总览入口挂到已有的 通过率统计卡上,不再另占 Hero 按钮。 - 统一详情取数:抽出 fetchDetail/loadDetail 作为 details/*.json 的唯一路径, FAQ 不再自行 fetch 一遍,与组件页共用缓存与失败兜底。 ## i18n - 删除 12 组重复键(含整段 FAQ 说明),字典 604 → 585 唯一键。 - 删除本次改动产生的 6 个死键。 - verify-i18n.mjs 新增 `unique dictionary keys` 断言:重复键在对象字面量里 是静默的后值覆盖,此前无从发现;现由门禁拦住。 ## 文档事实修正(实测为准) - TESTING/CONTRIBUTING:79 → 103 组件;旧断言数改为回指 tests/report.json。 - PLATFORMS:移动端 108 文件/18 端 → 282 文件/47 端;契约 5 → 47; 令牌 17 → 15;uni-app SFC 21 → 50。 - AGENTS:断言 1405/18 页 → 1464/103 页(PC)、807/47 页(移动端)。 - package.json:YOUR-ACCOUNT 占位 → gitea 实址与 kole-ui.mymoyu.top。 ## 品牌标识(并行会话成果,一并入库) - brand-mark.json 收归真源,build:brand 生成 favicon 与单色 SVG; PC 与移动端共用资产,verify:brand 24 条断言。 - regression.yml 增加 verify:brand 步骤。 ## 门禁与验收 新增工具:verify-component-page.mjs(86 条真实浏览器断言,随详情页改造同步 更新为「只允许一套导航可见」)、verify-brand-mark.mjs、lib/i18n-dead-keys.mjs (只读诊断)。 回归:PC 100%(1464/1464,103 页,N/A 50)· 移动端 100%(807/807,47 页)。 门禁:component-page 86 · i18n 17 · brand 24 · routes all · smoke all · theme OK · isolation 31 · nav all · examples 9 · api-docs 10 · mobile-docs 12。 已知未做:i18n 另有约 44 条历史死键(非本次产生),已记为 ROADMAP S8-P6; 顶栏与悬浮区的两个主题入口为刻意设计(verify-theme 断言其互斥),未删。
48 lines
2.2 KiB
JavaScript
48 lines
2.2 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* i18n-dead-keys.mjs — 精确列出「确定死亡」的字典键,供人工确认后删除。
|
||
*
|
||
* 判定分两档(避免误删用拼接方式消费的键):
|
||
* DEAD — 键串在 site/ 任何源文件(除 i18n.js)中都不出现,也不作为任何文件的子串。
|
||
* REVIEW — 键串只作为更长字符串的一部分出现(典型是 T('前缀') + x 拼出来的),
|
||
* 必须人工判断,工具不当作可删。
|
||
*
|
||
* 只读:不修改任何文件。
|
||
*/
|
||
import { readFileSync, readdirSync } from 'node:fs';
|
||
import { join, extname } from 'node:path';
|
||
|
||
const ROOT = join(import.meta.dirname, '..', '..');
|
||
const SITE = join(ROOT, 'site');
|
||
const i18n = readFileSync(join(SITE, 'i18n.js'), 'utf8');
|
||
const block = i18n.match(/var\s+EN\s*=\s*\{([\s\S]*?)\n\s*\};/);
|
||
if (!block) { console.error('FAIL: 没找到 EN 字典块'); process.exit(1); }
|
||
|
||
const keys = [];
|
||
const re = /^[ \t]*(["'])((?:\\.|(?!\1)[\s\S])*?)\1[ \t]*:/gm;
|
||
let m;
|
||
while ((m = re.exec(block[1])) !== null) keys.push(m[2].replace(/\\(["'])/g, '$1'));
|
||
|
||
/* 消费方:site 下的 js / html(i18n.js 本身除外);changelog.json、data.json 是构建产物,
|
||
其中的中文是历史记录,不代表 i18n 键被消费,故不纳入。 */
|
||
const consumers = readdirSync(SITE)
|
||
.filter((f) => (extname(f) === '.js' && f !== 'i18n.js') || extname(f) === '.html')
|
||
.map((f) => readFileSync(join(SITE, f), 'utf8'))
|
||
.join('\n');
|
||
|
||
const dead = [];
|
||
const review = [];
|
||
for (const key of keys) {
|
||
if (consumers.includes(key)) continue; // 精确命中:在用
|
||
/* 是否作为更长字符串的一部分出现 —— 拼接消费的迹象 */
|
||
const probe = key.length > 8 ? key.slice(0, 8) : key;
|
||
if (consumers.includes(probe)) review.push(key); // 疑似拼接消费,人工判断
|
||
else dead.push(key);
|
||
}
|
||
|
||
console.log(`字典 ${keys.length} 键 · 确定死亡 ${dead.length} · 待人工判断 ${review.length}\n`);
|
||
console.log('=== DEAD(键串在 site/ 源文件中完全不出现)===');
|
||
for (const k of dead) console.log(` ${k}`);
|
||
console.log('\n=== REVIEW(疑似以拼接方式消费,不要自动删)===');
|
||
for (const k of review) console.log(` ${k}`);
|