#!/usr/bin/env node /** * verify-site-routing.mjs — 校验组件端入口、SPA 路由契约和 sitemap 覆盖。 * 只使用 Node 内置模块,不启动服务、不修改文件。 */ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; import { join } from 'node:path'; const ROOT = process.cwd(); const SITE = join(ROOT, 'site'); const COMPONENTS = join(SITE, 'components'); const app = readFileSync(join(SITE, 'app.js'), 'utf8'); const data = JSON.parse(readFileSync(join(SITE, 'data.json'), 'utf8')); const sitemap = readFileSync(join(ROOT, 'sitemap.xml'), 'utf8'); const platforms = ['h5', 'react', 'vue2', 'vue3']; const failures = []; const check = (ok, message) => { if (!ok) failures.push(message); }; const components = data.components || []; check(components.length === 79, `expected 79 components, got ${components.length}`); check(app.includes("(?:\\/([a-z0-9-]+))?"), 'SPA platform route parser is missing'); check(app.includes("PLATFORM_KINDS = { h5: 'html', react: 'jsx', vue2: 'vue2', vue3: 'vue3' }"), 'platform kind map is missing'); check(app.includes("a.href = componentPageHref(c, platform)"), 'other-platform links do not use component pages'); let shellCount = 0; for (const component of components) { const slug = component.slug; const legacy = join(COMPONENTS, `${slug}.html`); check(existsSync(legacy), `missing legacy shell: ${slug}.html`); if (existsSync(legacy)) { const legacyText = readFileSync(legacy, 'utf8'); check(!legacyText.includes('aurora-admin/"site/components'), `legacy canonical is malformed: ${slug}`); } for (const platform of platforms) { const shell = join(COMPONENTS, slug, `${platform}.html`); shellCount += 1; check(existsSync(shell), `missing platform shell: ${slug}/${platform}.html`); if (!existsSync(shell)) continue; const text = readFileSync(shell, 'utf8'); check(text.includes(`#/component/${slug}/${platform}`), `wrong route target: ${slug}/${platform}`); check(text.includes(`/site/components/${slug}/${platform}.html`), `wrong canonical: ${slug}/${platform}`); check(!text.includes('aurora-admin/"site/components'), `malformed canonical: ${slug}/${platform}`); } } const urlCount = (sitemap.match(//g) || []).length; check(urlCount === 1 + components.length * (1 + platforms.length), `sitemap URL count is ${urlCount}, expected ${1 + components.length * (1 + platforms.length)}`); check(sitemap.includes('https://YOUR-ACCOUNT.github.io/aurora-admin/site/index.html'), 'site index is missing from sitemap'); const dirs = readdirSync(COMPONENTS).filter((name) => { const path = join(COMPONENTS, name); return existsSync(path) && statSync(path).isDirectory(); }); check(dirs.length === components.length, `platform shell directories are ${dirs.length}, expected ${components.length}`); check(shellCount === components.length * platforms.length, `platform shell count is ${shellCount}`); if (failures.length) { console.error(`[routing] FAIL (${failures.length})`); failures.forEach((failure) => console.error(`- ${failure}`)); process.exit(1); } console.log(`[routing] OK: ${components.length} components / ${shellCount} platform shells / ${urlCount} sitemap URLs`);