// 对账:sitemap 页名 vs lanhu-pages 实际文件名 import fs from 'node:fs'; import path from 'node:path'; const ROOT = 'e:/code/crm-backend-matt'; const data = JSON.parse(fs.readFileSync(`${ROOT}/.scratch/lanhu-latest/axure-v29.json`, 'utf8')); const OUT_DIR = `${ROOT}/.scratch/opportunity-bugfix/lanhu-pages`; const actual = new Set(fs.readdirSync(OUT_DIR)); const safe = (s) => s.replace(/[\\/:*?"<>|\s]+/g, '_'); // 复现 fetch 的命名顺序(含冲突后缀) const used = new Set(); const expected = new Map(); // url -> file for (const [url, e] of Object.entries(data.pages)) { // sitemap 页名优先,兜底 url let name = url; const find = (nodes) => { for (const n of nodes || []) { if (n.url === url) { name = n.pageName; return true; } if (n.children && find(n.children)) return true; } return false; }; find(data.sitemap.rootNodes); let s = safe(name); let base = s, i = 2; while (used.has(s.toLowerCase())) s = `${base}_${i++}`; used.add(s.toLowerCase()); expected.set(url, s + '.md'); } console.log('expected:', expected.size, 'actual:', actual.size); const missing = [], renamed = []; for (const [url, f] of expected) { if (actual.has(f)) continue; // 找可能带后缀的实际文件 const stem = f.replace(/\.md$/, ''); const cands = [...actual].filter(a => a.startsWith(stem)); if (cands.length) renamed.push(`${f} => ${cands.join(', ')}`); else missing.push(f); } console.log('\n--- 直接对不上但疑似带后缀 ---'); console.log(renamed.join('\n') || '(none)'); console.log('\n--- 完全找不到 ---'); console.log(missing.join('\n') || '(none)'); // 实际有但期望没有 const extra = [...actual].filter(a => ![...expected.values()].includes(a)); console.log('\n--- 实际存在但映射不到 ---'); console.log(extra.join('\n') || '(none)');