import { readFile } from 'node:fs/promises'; import path from 'node:path'; import { dist, requireDist, resolveFile } from './lib/dist.mjs'; import { walk } from './lib/walk.mjs'; const allowedPreservedRoutes = new Set(['/fleeting/', '/reconcile/']); const failures = []; async function targetExists(pathname) { if (allowedPreservedRoutes.has(pathname)) return true; return (await resolveFile(pathname)) !== null; } await requireDist(); const files = await walk(dist); const checkedFiles = files.filter((file) => /\.(html|xml|css|webmanifest)$/.test(file)); function pagePathname(file) { const rel = path.relative(dist, file).replaceAll(path.sep, '/'); if (rel === 'index.html') return '/'; if (rel.endsWith('/index.html')) return `/${rel.slice(0, -'index.html'.length)}`; return `/${rel}`; } function collectUrlReferences(body, rel) { const urls = []; for (const match of body.matchAll(/\b(?:href|src|poster)=["']([^"']+)["']/g)) { urls.push(match[1]); } for (const match of body.matchAll(/\bsrcset=["']([^"']+)["']/g)) { for (const candidate of match[1].split(',')) { const url = candidate.trim().split(/\s+/)[0]; if (url) urls.push(url); } } if (rel.endsWith('.css')) { for (const match of body.matchAll(/url\(\s*['"]?([^'")]+)['"]?\s*\)/g)) { urls.push(match[1]); } } if (rel.endsWith('.webmanifest')) { try { const manifest = JSON.parse(body); for (const key of ['start_url', 'scope']) { if (typeof manifest[key] === 'string') urls.push(manifest[key]); } for (const icon of manifest.icons ?? []) { if (typeof icon?.src === 'string') urls.push(icon.src); } for (const screenshot of manifest.screenshots ?? []) { if (typeof screenshot?.src === 'string') urls.push(screenshot.src); } } catch { failures.push(`${rel}: invalid web manifest JSON`); } } return urls; } for (const file of checkedFiles) { const body = await readFile(file, 'utf8'); const rel = path.relative(dist, file); const baseUrl = new URL(pagePathname(file), 'https://schmelczer.dev'); for (const raw of collectUrlReferences(body, rel)) { if (/^(mailto:|tel:|data:)/i.test(raw)) continue; let parsed; try { parsed = new URL(raw, baseUrl); } catch { failures.push(`${rel}: invalid URL ${raw}`); continue; } if (parsed.origin !== 'https://schmelczer.dev') continue; if (!(await targetExists(parsed.pathname))) { failures.push(`${rel}: missing local target ${parsed.pathname}`); } } } if (failures.length > 0) { console.error(failures.join('\n')); process.exit(1); } console.log('No missing local href/src targets found in dist/.');