UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

102 lines (101 loc) 2.92 kB
import fs from "node:fs"; import path from "node:path"; import { randomUUID } from "node:crypto"; //#region src/infra/path-case.ts function swapAsciiCase(value) { return value.replace(/[A-Za-z]/g, (char) => { const lower = char.toLowerCase(); return char === lower ? char.toUpperCase() : lower; }); } function sameFsObject(a, b) { return a.dev === b.dev && a.ino === b.ino; } function probeDirectoryEntry(dir, name) { const swapped = swapAsciiCase(name); if (swapped === name) return; try { const names = fs.readdirSync(dir); if (names.includes(name) && names.includes(swapped)) return false; const original = fs.lstatSync(path.join(dir, name)); try { return sameFsObject(original, fs.lstatSync(path.join(dir, swapped))); } catch (error) { const code = error.code; return code === "ENOENT" || code === "ENOTDIR" ? false : void 0; } } catch { return; } } function probeDirectoryContents(dir) { try { for (const name of fs.readdirSync(dir)) { const result = probeDirectoryEntry(dir, name); if (result !== void 0) return result; } } catch { return; } } function probeDirectoryWithTemporaryEntry(dir) { const name = `.openclaw-case-probe-${randomUUID()}`; const probePath = path.join(dir, name); let created = false; let result; try { fs.writeFileSync(probePath, "", { flag: "wx", mode: 384 }); created = true; result = probeDirectoryEntry(dir, name); } catch { result = void 0; } if (created) try { fs.unlinkSync(probePath); } catch (error) { if (error.code !== "ENOENT") throw error; } return result; } function platformDefault() { return process.platform === "darwin" || process.platform === "win32"; } function probeDirectory(dir) { return probeDirectoryContents(dir) ?? probeDirectoryWithTemporaryEntry(dir); } /** Resolves path-local case semantics, or undefined when the filesystem cannot be probed. */ function tryResolvePathCaseInsensitive(value) { const resolved = path.resolve(value); try { fs.lstatSync(resolved); const parent = path.dirname(resolved); return probeDirectoryEntry(parent, path.basename(resolved)) ?? probeDirectory(parent); } catch (error) { const code = error.code; if (code !== "ENOENT" && code !== "ENOTDIR") return; } let candidate = path.dirname(resolved); for (;;) { let isDirectory = false; try { isDirectory = fs.statSync(candidate).isDirectory(); } catch {} if (isDirectory) try { return probeDirectory(candidate); } catch { return; } const parent = path.dirname(candidate); if (parent === candidate) return; candidate = parent; } } /** Returns whether the target path's filesystem matches names case-insensitively. */ function isPathCaseInsensitive(value) { return tryResolvePathCaseInsensitive(value) ?? platformDefault(); } //#endregion export { tryResolvePathCaseInsensitive as i, sameFsObject as n, swapAsciiCase as r, isPathCaseInsensitive as t };