fix: restore project placeholders regardless of case

This commit is contained in:
muena
2026-10-06 13:38:21 +02:00
parent 8de3ce9326
commit 7db3949d66
3 changed files with 49 additions and 9 deletions

View File

@@ -4,7 +4,7 @@ import { homedir } from "node:os";
import { basename, dirname, join } from "node:path";
import { useEffect, useState } from "react";
import { depseudonymizeDocument } from "./velum";
import { canonicalProjectPath, listAllRuns, resolveWithin, restorePath, restoreText, runCopiesPath, scanRestorableCopyFiles } from "./lib/velum-project";
import { canonicalProjectPath, listAllRuns, resolveWithin, restorePath, restoreTextWithCount, runCopiesPath, scanRestorableCopyFiles } from "./lib/velum-project";
import type { ProjectFile, ProjectRun } from "./lib/velum-project";
import { canonicalPerson, mergePeople } from "./lib/project-review";
import { planProjectRevision, reviseProjectRun } from "./lib/project-revision";
@@ -173,10 +173,13 @@ function FilePicker(props: { run: ProjectRun; directory: string; historical?: bo
const parent = join(homedir(), "Downloads", "Velum");
let targetRoot: string | undefined;
try {
if (!Object.keys(props.run.mapping).length) throw new Error("Dieser Projektstand hat keine Übersetzungstabelle.");
const names = new Set<string>();
const planned = files.filter((item) => selected.has(item.relPath)).map((file) => ({
file, restoredName: restorePath(file.relPath, props.run.mapping, props.run.matchModes),
}));
const renamedFiles = planned.filter(({ file, restoredName }) => restoredName !== file.relPath).length;
let contentReplacements = 0;
for (const { restoredName } of planned) {
if (names.has(restoredName)) throw new Error(`Mehrdeutiger Ausgabename: ${restoredName}`);
names.add(restoredName);
@@ -188,14 +191,24 @@ function FilePicker(props: { run: ProjectRun; directory: string; historical?: bo
const target = resolveWithin(targetRoot, restoredName);
if (!(await fs.lstat(source)).isFile()) throw new Error(`Keine reguläre Datei: ${file.relPath}`);
const data = await fs.readFile(source);
const result = file.kind === "document"
? await depseudonymizeDocument(basename(file.relPath), data, props.run.mapping)
: Buffer.from(restoreText(data.toString("utf8"), props.run.mapping, props.run.matchModes), "utf8");
let result: Buffer;
if (file.kind === "document") {
result = await depseudonymizeDocument(basename(file.relPath), data, props.run.mapping);
} else {
const restored = restoreTextWithCount(data.toString("utf8"), props.run.mapping, props.run.matchModes);
contentReplacements += restored.replacements;
result = Buffer.from(restored.text, "utf8");
}
await fs.mkdir(dirname(target), { recursive: true, mode: 0o700 });
await fs.writeFile(target, result, { flag: "wx", mode: 0o600 });
}
if (!renamedFiles && !contentReplacements && planned.every(({ file }) => file.kind === "text")) {
throw new Error("Keine passenden Velum-Platzhalter in den ausgewählten Textdateien oder Dateinamen gefunden. Bitte Quelle und Projektstand prüfen.");
}
toast.style = Toast.Style.Success;
toast.title = `${selected.size} Klartext-Dateien in Downloads`;
toast.message = `${contentReplacements} Textersetzungen · ${renamedFiles} Dateinamen geändert`
+ (planned.some(({ file }) => file.kind === "document") ? " · Office-Inhalte nicht gezählt" : "");
await showInFinder(targetRoot).catch(() => undefined);
} catch (error) {
if (targetRoot) await fs.rm(targetRoot, { recursive: true, force: true });