mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-24 14:55:37 +00:00
48 lines
1.5 KiB
TypeScript
48 lines
1.5 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
|
|
export async function renameLibraryProject(
|
|
source: string,
|
|
name: string,
|
|
allowedPaths: string[],
|
|
sidecars: (path: string) => string[],
|
|
) {
|
|
if (!allowedPaths.includes(source)) throw new Error("Project is not in the library");
|
|
const clean = name.trim();
|
|
if (
|
|
!clean ||
|
|
clean === "." ||
|
|
clean === ".." ||
|
|
/[<>:"/\\|?*]/.test(clean) ||
|
|
[...clean].some((char) => char.charCodeAt(0) < 32) ||
|
|
/[. ]$/.test(clean)
|
|
)
|
|
throw new Error("Choose a valid project name");
|
|
const target = path.join(path.dirname(source), `${clean}${path.extname(source)}`);
|
|
if (target === source) return target;
|
|
// An exclusive link prevents a rename from overwriting another project.
|
|
await fs.link(source, target);
|
|
const copied: string[] = [];
|
|
try {
|
|
const previous = sidecars(source),
|
|
next = sidecars(target);
|
|
for (let i = 0; i < previous.length; i++) {
|
|
try {
|
|
await fs.copyFile(previous[i], next[i], fs.constants.COPYFILE_EXCL);
|
|
copied.push(next[i]);
|
|
} catch (error) {
|
|
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
}
|
|
}
|
|
await fs.unlink(source);
|
|
} catch (error) {
|
|
await Promise.all([target, ...copied].map((file) => fs.rm(file, { force: true })));
|
|
throw error;
|
|
}
|
|
// Auxiliary files can be cleaned up independently once the project has moved.
|
|
await Promise.all(
|
|
sidecars(source).map((file) => fs.rm(file, { force: true }).catch(() => undefined)),
|
|
);
|
|
return target;
|
|
}
|