Centralize surface route normalization (#600)

Consolidate explicit and inferred surface route canonicalization behind one private rule, with characterization coverage for equivalent and invalid inputs.\n\nAI assistance: OpenAI Codex prepared this change under pbakaus's scheduled architecture-simplification authorization.
This commit is contained in:
Paul Bakaus
2026-08-16 14:24:31 -07:00
committed by GitHub
parent 9ce0350054
commit 21ad321a97
2 changed files with 17 additions and 11 deletions
+9 -11
View File
@@ -8,6 +8,12 @@ export function getSurfaceBriefDir(projectRoot) {
return path.join(projectRoot, '.impeccable', 'surfaces');
}
function normalizeRouteTarget(route) {
if (!route.startsWith('/') || route.includes('..')) return null;
const normalized = route.split(/[?#]/, 1)[0].replace(/\/{2,}/g, '/').replace(/\/$/, '') || '/';
return `route:${normalized}`;
}
export function normalizeSurfaceTarget(target, { projectRoot = process.cwd() } = {}) {
if (!target || typeof target !== 'string' || !target.trim()) return null;
const trimmed = target.trim();
@@ -21,21 +27,13 @@ export function normalizeSurfaceTarget(target, { projectRoot = process.cwd() } =
return null;
}
}
if (/^route:/i.test(trimmed)) {
const route = trimmed.slice(trimmed.indexOf(':') + 1).trim();
if (!route.startsWith('/') || route.includes('..')) return null;
const normalizedRoute = route.split(/[?#]/, 1)[0].replace(/\/{2,}/g, '/').replace(/\/$/, '') || '/';
return `route:${normalizedRoute}`;
}
if (trimmed === '/') return 'route:/';
if (/^route:/i.test(trimmed)) return normalizeRouteTarget(trimmed.slice(trimmed.indexOf(':') + 1).trim());
if (trimmed === '/') return normalizeRouteTarget(trimmed);
if (trimmed.startsWith('/')) {
const absolute = path.resolve(trimmed);
const relativeToProject = path.relative(projectRoot, absolute);
const isProjectFile = relativeToProject && !relativeToProject.startsWith('..') && !path.isAbsolute(relativeToProject);
if (!isProjectFile && !fs.existsSync(absolute) && !trimmed.includes('..')) {
const normalizedRoute = trimmed.split(/[?#]/, 1)[0].replace(/\/{2,}/g, '/').replace(/\/$/, '') || '/';
return `route:${normalizedRoute}`;
}
if (!isProjectFile && !fs.existsSync(absolute)) return normalizeRouteTarget(trimmed);
}
const abs = path.isAbsolute(trimmed) ? trimmed : path.resolve(projectRoot, trimmed);
const rel = path.relative(projectRoot, abs);
+8
View File
@@ -6,6 +6,7 @@ import path from 'node:path';
import {
listSurfaceBriefs,
normalizeSurfaceTarget,
resolveSurfaceBrief,
writeSurfaceBrief,
} from '../skill/scripts/lib/surface-briefs.mjs';
@@ -69,6 +70,13 @@ describe('surface briefs', () => {
assert.equal(result.brief?.primaryTarget, 'route:/pricing');
});
it('canonicalizes explicit and inferred route identifiers consistently', () => {
assert.equal(normalizeSurfaceTarget('route:/docs//intro/?from=nav#top', { projectRoot: cwd }), 'route:/docs/intro');
assert.equal(normalizeSurfaceTarget('/docs//intro/?from=nav#top', { projectRoot: cwd }), 'route:/docs/intro');
assert.equal(normalizeSurfaceTarget('route:/docs/../admin', { projectRoot: cwd }), null);
assert.equal(normalizeSurfaceTarget('/docs/../admin', { projectRoot: cwd }), null);
});
it('supports the root route even though the filesystem root exists', () => {
const filePath = writeSurfaceBrief({
projectRoot: cwd,