fix: restore placeholders within filenames

This commit is contained in:
muena
2026-10-06 13:33:21 +02:00
parent 0ec5b0745e
commit 8de3ce9326
2 changed files with 15 additions and 3 deletions

View File

@@ -244,12 +244,12 @@ export function replaceSpans(
return output; return output;
} }
function restorePattern(mapping: PlaceholderMapping, matchModes: ProjectRun["matchModes"]): RegExp | undefined { function restorePattern(mapping: PlaceholderMapping, matchModes: ProjectRun["matchModes"], pathSegment = false): RegExp | undefined {
const keys = Object.keys(mapping).sort((a, b) => b.length - a.length); const keys = Object.keys(mapping).sort((a, b) => b.length - a.length);
if (!keys.length) return undefined; if (!keys.length) return undefined;
const parts = keys.map((key) => { const parts = keys.map((key) => {
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
return matchModes?.[key] === "anywhere" return pathSegment || matchModes?.[key] === "anywhere"
? escaped : `(?<![\\p{L}\\p{N}])${escaped}(?![\\p{L}\\p{N}])`; ? escaped : `(?<![\\p{L}\\p{N}])${escaped}(?![\\p{L}\\p{N}])`;
}); });
return new RegExp(parts.join("|"), "gu"); return new RegExp(parts.join("|"), "gu");
@@ -271,7 +271,9 @@ export function restoreText(source: string, mapping: PlaceholderMapping, matchMo
} }
export function restorePath(relPath: string, mapping: PlaceholderMapping, matchModes?: ProjectRun["matchModes"]): string { export function restorePath(relPath: string, mapping: PlaceholderMapping, matchModes?: ProjectRun["matchModes"]): string {
const pattern = restorePattern(mapping, matchModes); // Filenames can join a placeholder directly to another identifier fragment.
// Restricting replacements to word boundaries would leave those names masked.
const pattern = restorePattern(mapping, matchModes, true);
const segments = safeRelativePath(relPath).split("/").map((segment) => { const segments = safeRelativePath(relPath).split("/").map((segment) => {
const restored = pattern ? segment.replace(pattern, (key) => mapping[key].original) : segment; const restored = pattern ? segment.replace(pattern, (key) => mapping[key].original) : segment;
if (restored.includes("/") || restored.includes("\\") || restored === "." || restored === "..") { if (restored.includes("/") || restored.includes("\\") || restored === "." || restored === "..") {

View File

@@ -129,6 +129,16 @@ describe("Velum-Projektstände", () => {
expect(project.restorePath("PERSON_01_Bericht.txt", { expect(project.restorePath("PERSON_01_Bericht.txt", {
PERSON_01: { original: "Max Mustermann", type: "PERSON" }, PERSON_01: { original: "Max Mustermann", type: "PERSON" },
})).toBe("Max Mustermann_Bericht.txt"); })).toBe("Max Mustermann_Bericht.txt");
expect(project.restorePath("Archiv/BerichtPERSON_01.docx", {
PERSON_01: { original: "Max Mustermann", type: "PERSON" },
})).toBe("Archiv/BerichtMax Mustermann.docx");
expect(project.restoreText("BerichtPERSON_01", {
PERSON_01: { original: "Max Mustermann", type: "PERSON" },
})).toBe("BerichtPERSON_01");
expect(project.restorePath("PERSON_0101.txt", {
PERSON_01: { original: "Falsch", type: "PERSON" },
PERSON_0101: { original: "Richtig", type: "PERSON" },
})).toBe("Richtig.txt");
expect(() => project.safeRelativePath("../geheim.txt")).toThrow(); expect(() => project.safeRelativePath("../geheim.txt")).toThrow();
}); });