Something went wrong. Try again.
A simple DAV sync application / cli
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960// Helpers for sync-relative paths: "/"-separated, no leading or trailing slash, NFC.
export function normalize(path: string): string { return path.normalize("NFC").split("/").filter(Boolean).join("/");}
/** * Whether a single name, as the other side reported it, can be used as one path * segment here. A server is not trusted to name only things inside the folder: * ".." or a name that holds a separator would reach outside it. */export function isSafeName(name: string): boolean { if (name === "" || name === "." || name === ".." || /[/\0]/.test(name)) return false; // A backslash is an ordinary character elsewhere, but a separator on Windows. return process.platform !== "win32" || !name.includes("\\");}
export function parentOf(path: string): string { const slash = path.lastIndexOf("/"); return slash === -1 ? "" : path.slice(0, slash);}
export function nameOf(path: string): string { return path.slice(path.lastIndexOf("/") + 1);}
export function depth(path: string): number { return path === "" ? 0 : path.split("/").length;}
/** True when `path` lies strictly below `dir` ("" is the root, above everything). */export function isBelow(path: string, dir: string): boolean { return dir === "" ? path !== "" : path.startsWith(dir + "/");}
/** `path` with its `from` prefix replaced by `to`. `path` must be `from` or below it. */export function rebase(path: string, from: string, to: string): string { return path === from ? to : to + path.slice(from.length);}
/** Every ancestor directory of `path`, outermost first, excluding the root. */export function ancestors(path: string): string[] { const parts = path.split("/"); return parts.slice(0, -1).map((_, index) => parts.slice(0, index + 1).join("/"));}
/** Runs `fn` over `items` with at most `limit` in flight, preserving order in the result. */export async function mapLimit<T, R>(items: readonly T[], limit: number, fn: (item: T) => Promise<R>): Promise<R[]> { const results = new Array<R>(items.length); let next = 0; const worker = async () => { while (next < items.length) { const index = next++; results[index] = await fn(items[index]!); } }; await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker)); return results;}