Files
2026-06-25 19:06:59 -04:00

51 lines
1.6 KiB
JavaScript

import { readFile, stat } from 'node:fs/promises';
import path from 'node:path';
import { fail, pass, repositoryRoot } from './lib.mjs';
const manifest = JSON.parse(
await readFile(
path.join(repositoryRoot, 'src', 'contracts', 'phase9', 'route-manifest.json'),
'utf8',
),
);
const errors = [];
const requiredLocales = ['en', 'fr', 'ar'];
const ids = new Set();
if (JSON.stringify(manifest.locales) !== JSON.stringify(requiredLocales)) {
errors.push('Route locales must remain exactly en, fr, ar.');
}
for (const route of manifest.routes) {
if (ids.has(route.id)) errors.push(`Duplicate route ID: ${route.id}`);
ids.add(route.id);
for (const locale of requiredLocales) {
if (typeof route.slugs[locale] !== 'string') errors.push(`${route.id} has no ${locale} slug.`);
}
}
for (const locale of requiredLocales) {
if (!manifest.hreflang.values.includes(locale)) errors.push(`hreflang omits ${locale}.`);
}
if (manifest.hreflang.xDefaultLocale !== 'en') errors.push('x-default must resolve to English.');
if (manifest.switching.dropUnknownQuery !== true) {
errors.push('Unknown query parameters must be dropped.');
}
for (const routeFile of [
'src/app/[locale]/page.tsx',
'src/app/[locale]/[slug]/page.tsx',
'src/app/[locale]/not-found.tsx',
]) {
try {
await stat(path.join(repositoryRoot, routeFile));
} catch {
errors.push(`Runtime route implementation missing: ${routeFile}`);
}
}
if (errors.length > 0) fail(errors);
else
pass(
`${manifest.routes.length} route IDs have complete locale, runtime, hash, query, ` +
'and hreflang contracts.',
);