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.', );