openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
102 lines (101 loc) • 2.92 kB
JavaScript
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 };