diff --git a/src/path.ts b/src/path.ts index c50d9a9..d01f425 100644 --- a/src/path.ts +++ b/src/path.ts @@ -237,7 +237,21 @@ export function transformLink(src: FullSlug, target: string, opts: TransformOpti const [targetCanonical, targetAnchor] = splitAnchor(canonicalSlug); if (opts.strategy === "shortest") { + const isMultiSegment = targetCanonical.includes("/"); + const isFolderTarget = isFolderPath(targetSlug); const matchingFileNames = opts.allSlugs.filter((slug) => { + if (isMultiSegment) { + // Multi-segment partial path: match by suffix + if (slug === targetCanonical || slug.endsWith("/" + targetCanonical)) { + return true; + } + // Folder targets have "/index" stripped — also match the "/index" variant + if (isFolderTarget) { + const withIndex = targetCanonical + "/index"; + return slug === withIndex || slug.endsWith("/" + withIndex); + } + return false; + } const parts = slug.split("/"); const fileName = parts.at(-1); return targetCanonical === fileName; diff --git a/test/path.test.ts b/test/path.test.ts index 47f51fb..6654a54 100644 --- a/test/path.test.ts +++ b/test/path.test.ts @@ -247,6 +247,96 @@ describe("transformLink", () => { }); }); + describe("multi-segment partial path (shortest)", () => { + const multiSegSlugs = [ + "Compendium/Species/Elf/Wood", + "Compendium/Species/Elf/index", + "Compendium/Species/Elf/Eladrin", + "Compendium/Spells/index", + "Compendium/Spells/Bane", + "Campaigns/Unnamed/People/index", + "index", + ] as FullSlug[]; + + const opts: TransformOptions = { strategy: "shortest", allSlugs: multiSegSlugs }; + + it("resolves multi-segment path Species/Elf/Wood to unique match", () => { + const cur = "Campaigns/Unnamed/People/index" as FullSlug; + expect(transformLink(cur, "Species/Elf/Wood", opts)).toBe( + "../../../Compendium/Species/Elf/Wood", + ); + }); + + it("resolves multi-segment path Species/Elf/index to folder page", () => { + const cur = "Campaigns/Unnamed/People/index" as FullSlug; + expect(transformLink(cur, "Species/Elf/index", opts)).toBe( + "../../../Compendium/Species/Elf/", + ); + }); + + it("falls back to absolute when multi-segment path has no match", () => { + const cur = "index" as FullSlug; + expect(transformLink(cur, "Species/Elf/NoSuchPage", opts)).toBe("./Species/Elf/NoSuchPage"); + }); + + it("resolves single-segment name that is unique", () => { + const cur = "index" as FullSlug; + expect(transformLink(cur, "Bane", opts)).toBe("./Compendium/Spells/Bane"); + }); + + it("resolves exact full path as multi-segment match", () => { + const cur = "index" as FullSlug; + expect(transformLink(cur, "Compendium/Species/Elf/Eladrin", opts)).toBe( + "./Compendium/Species/Elf/Eladrin", + ); + }); + }); + + describe("multi-segment partial path (shortest)", () => { + const multiSegSlugs = [ + "Compendium/Species/Elf/Wood", + "Compendium/Species/Elf/index", + "Compendium/Species/Elf/Eladrin", + "Compendium/Spells/index", + "Compendium/Spells/Bane", + "Campaigns/Unnamed/People/index", + "index", + ] as FullSlug[]; + + const opts: TransformOptions = { strategy: "shortest", allSlugs: multiSegSlugs }; + + it("resolves multi-segment path Species/Elf/Wood to unique match", () => { + const cur = "Campaigns/Unnamed/People/index" as FullSlug; + expect(transformLink(cur, "Species/Elf/Wood", opts)).toBe( + "../../../Compendium/Species/Elf/Wood", + ); + }); + + it("resolves multi-segment path Species/Elf/index to folder page", () => { + const cur = "Campaigns/Unnamed/People/index" as FullSlug; + expect(transformLink(cur, "Species/Elf/index", opts)).toBe( + "../../../Compendium/Species/Elf/", + ); + }); + + it("falls back to absolute when multi-segment path has no match", () => { + const cur = "index" as FullSlug; + expect(transformLink(cur, "Species/Elf/NoSuchPage", opts)).toBe("./Species/Elf/NoSuchPage"); + }); + + it("resolves single-segment name that is unique", () => { + const cur = "index" as FullSlug; + expect(transformLink(cur, "Bane", opts)).toBe("./Compendium/Spells/Bane"); + }); + + it("resolves exact full path as multi-segment match", () => { + const cur = "index" as FullSlug; + expect(transformLink(cur, "Compendium/Species/Elf/Eladrin", opts)).toBe( + "./Compendium/Species/Elf/Eladrin", + ); + }); + }); + describe("folder page bug regression", () => { const spellSlugs = [ "Compendium/Spells/index",