Files
lucky_shop/scripts/verify-nav-title.js
ZF sun 55a9ed5946 refactor: 重构底部导航高亮逻辑,新增跨平台兼容与工具脚本
1. 抽离底部导航归属逻辑为纯函数resolveEntryTab,优化分包页面高亮规则,对齐iOS HIG规范
2. 新增页面Tab通配符映射,简化PAGE_TAB_MAP维护
3. 修复鸿蒙平台webview返回按钮适配问题
4. 新增pages.json校验与导航标题自动注入脚本
5. 优化启动页动画性能,提升合成渲染效率
6. 修复diy-picture组件v-for缺少key的警告
7. 清理鸿蒙平台多余的分包构建配置
8. 更新统计数据与store注释说明
2026-07-16 11:47:29 +08:00

105 lines
3.2 KiB
JavaScript

/**
* 验证 pages.json 的所有 page.style 块都已经有 navigationBarTitleText 字段,
* 且都在 // #ifdef / // #ifndef 块之外 (保证所有平台生效).
*
* 运行: node scripts/verify-nav-title.js
*/
const fs = require('fs');
const path = require('path');
const PAGES_JSON = path.join(__dirname, '..', 'pages.json');
const s = fs.readFileSync(PAGES_JSON, 'utf-8');
const lines = s.split(/\r?\n/);
let i = 0;
let totalStyle = 0, totalNavTitle = 0, insideIfdef = 0, doubleTitle = 0, missingTitle = [];
// 跟踪 subPackage 上下文, 让 missing-title 报出全路径 (root/path), 不只是 path
let currentSubRoot = null;
while (i < lines.length) {
// 跟踪 subPackage 的 root, 找路径时回退可见
const rootMatch = lines[i].match(/^\s*"root"\s*:\s*"([^"]+)"/);
if (rootMatch) {
currentSubRoot = rootMatch[1];
i++;
continue;
}
const m = lines[i].match(/^(\s*)"style"\s*:\s*\{\s*,?\s*$/);
if (m) {
totalStyle++;
const blockStart = i;
i++;
const bodyStart = i;
let depth = 1;
while (i < lines.length && depth > 0) {
const c = lines[i];
let b = 0;
let inS = false, e = false;
for (let k = 0; k < c.length; k++) {
const ch = c[k];
if (inS) {
if (e) e = false;
else if (ch === '\\') e = true;
else if (ch === '"') inS = false;
} else {
if (ch === '/' && c[k + 1] === '/') break;
if (ch === '"') inS = true;
else if (ch === '{') b++;
else if (ch === '}') b--;
}
}
depth += b;
i++;
}
const body = lines.slice(bodyStart, i - 1);
const titleIdxs = body
.map((l, idx) => /^\s*"navigationBarTitleText"\s*:/.test(l) ? idx : -1)
.filter(x => x >= 0);
totalNavTitle += titleIdxs.length;
if (titleIdxs.length > 1) doubleTitle++;
// 找最近的 path 行, 若处于 subPackage 则补上 root 前缀, 报全路径
let pathLine = '';
for (let k = blockStart - 1; k >= 0; k--) {
const pm = lines[k].match(/^\s*"path"\s*:\s*"([^"]+)"/);
if (pm) {
pathLine = pm[1];
break;
}
// 跨过 subPackage 边界 (遇到另一个 root) 视为顶层 pages
const rm = lines[k].match(/^\s*"root"\s*:\s*"([^"]+)"/);
if (rm) {
currentSubRoot = rm[1];
break;
}
}
if (titleIdxs.length === 0) {
// 只在缺标题时, 用 currentSubRoot 校正路径
// (找 path 时可能已被同包兄弟 root 行先 break 出, 这里用循环外的 currentSubRoot)
const fullPath = pathLine && currentSubRoot ? `${currentSubRoot}/${pathLine}` : pathLine;
missingTitle.push(fullPath);
} else {
for (const tIdx of titleIdxs) {
let d = 0;
for (let k = 0; k < tIdx; k++) {
const t = body[k];
if (/^\s*\/\/\s*#(ifdef|ifndef)\b/.test(t)) d++;
else if (/^\s*\/\/\s*#endif\b/.test(t)) d--;
}
if (d >= 1) insideIfdef++;
}
}
} else {
i++;
}
}
console.log('style blocks:', totalStyle);
console.log('navigationBarTitleText occurrences:', totalNavTitle);
console.log('inside-ifdef:', insideIfdef);
console.log('double-title:', doubleTitle);
console.log('missing-title:', missingTitle.length, missingTitle);
const ok = totalStyle === totalNavTitle && insideIfdef === 0 && doubleTitle === 0 && missingTitle.length === 0;
console.log(ok ? '✅ PASS' : '❌ FAIL');
process.exit(ok ? 0 : 1);