fix: handle duplicate raw-path claims by routing to orphaned

This commit is contained in:
meels
2026-07-28 13:13:33 +02:00
parent 027dcb4e4e
commit 80ef971d1a
2 changed files with 25 additions and 2 deletions

View File

@@ -29,9 +29,16 @@ function extractRawPath(text) {
} }
function derivePipeline({ rawFiles, sourcePages }) { function derivePipeline({ rawFiles, sourcePages }) {
// First claim on a raw path wins. A later page claiming the same file is a
// duplicate claim — real catalog drift — and joins `orphaned` rather than
// being silently dropped. `orphaned` therefore means "source page not paired
// with a raw file", whatever the reason.
const claimed = new Map(); const claimed = new Map();
const duplicates = [];
for (const page of sourcePages) { for (const page of sourcePages) {
if (page.rawPath) claimed.set(page.rawPath, page); if (!page.rawPath) continue;
if (claimed.has(page.rawPath)) duplicates.push(page);
else claimed.set(page.rawPath, page);
} }
const processed = []; const processed = [];
@@ -43,7 +50,9 @@ function derivePipeline({ rawFiles, sourcePages }) {
} }
const rawPaths = new Set(rawFiles.map((f) => f.path)); const rawPaths = new Set(rawFiles.map((f) => f.path));
const orphaned = sourcePages.filter((p) => !p.rawPath || !rawPaths.has(p.rawPath)); const orphaned = sourcePages
.filter((p) => !p.rawPath || !rawPaths.has(p.rawPath))
.concat(duplicates);
unprocessed.sort((a, b) => a.name.localeCompare(b.name)); unprocessed.sort((a, b) => a.name.localeCompare(b.name));
processed.sort((a, b) => b.page.name.localeCompare(a.page.name)); processed.sort((a, b) => b.page.name.localeCompare(a.page.name));

View File

@@ -68,6 +68,20 @@ test("derivePipeline treats a page with no raw path as orphaned", () => {
assert.equal(out.unprocessed.length, 1); assert.equal(out.unprocessed.length, 1);
}); });
test("derivePipeline routes a duplicate raw-path claim to orphaned", () => {
const out = derivePipeline({
rawFiles: [{ path: "raw/sources/a.md", name: "a.md", size: 10 }],
sourcePages: [
{ path: "wiki/sources/first.md", name: "first.md", rawPath: "raw/sources/a.md" },
{ path: "wiki/sources/second.md", name: "second.md", rawPath: "raw/sources/a.md" },
],
});
assert.equal(out.processed.length, 1);
assert.equal(out.processed[0].page.name, "first.md");
assert.equal(out.unprocessed.length, 0);
assert.deepEqual(out.orphaned.map((p) => p.name), ["second.md"]);
});
test("derivePipeline sorts unprocessed by name and processed newest first", () => { test("derivePipeline sorts unprocessed by name and processed newest first", () => {
const out = derivePipeline({ const out = derivePipeline({
rawFiles: [ rawFiles: [