typia
Version:
Superfast runtime validators with only one line
133 lines (132 loc) • 5.14 kB
JavaScript
import fs from "fs";
import path from "path";
//#region src/executable/FileSystemIdentity.ts
let FileSystemIdentity;
(function(_FileSystemIdentity) {
function create(caseSensitive, pathApi = path) {
const fold = (value) => caseSensitive ? value : value.toLowerCase();
const filesystemKey = (file) => fold(pathApi.normalize(file));
return {
caseSensitive,
contains: (file, directory) => {
const fileKey = filesystemKey(pathApi.resolve(file));
const directoryKey = filesystemKey(pathApi.resolve(directory));
const prefix = directoryKey.endsWith(pathApi.sep) ? directoryKey : `${directoryKey}${pathApi.sep}`;
return fileKey === directoryKey || fileKey.startsWith(prefix);
},
filesystemKey,
isDeclarationFile: (file) => DTS_PATTERN.test(fold(pathApi.basename(file))),
isSamePath: (x, y) => filesystemKey(x) === filesystemKey(y),
isSupportedExtension: (file) => {
const filename = fold(pathApi.basename(file));
return TS_PATTERN.test(filename) && DTS_PATTERN.test(filename) === false;
},
projectFileKey: fold
};
}
_FileSystemIdentity.create = create;
class Policy {
observe(caseSensitive, location) {
if (caseSensitive === void 0) return;
if (this.caseSensitive_ === void 0) {
this.caseSensitive_ = caseSensitive;
this.location_ = location;
} else if (this.caseSensitive_ !== caseSensitive) throw new URIError(`Error on TypiaGenerateWizard.generate(): inconsistent filesystem case behavior between ${this.location_} and ${location}.`);
}
get() {
if (this.caseSensitive_ === void 0) throw new URIError("Error on TypiaGenerateWizard.generate(): unable to determine filesystem case behavior for this run.");
return create(this.caseSensitive_);
}
}
_FileSystemIdentity.Policy = Policy;
async function inspectDirectory(directory) {
const names = await fs.promises.readdir(directory);
const entries = new Set(names);
for (const name of names) {
const alternate = alternateCase(name);
if (alternate === void 0) continue;
if (entries.has(alternate)) return true;
try {
await fs.promises.lstat(path.join(directory, alternate));
return false;
} catch (error) {
if (isMissingFileError(error)) return true;
throw error;
}
}
}
_FileSystemIdentity.inspectDirectory = inspectDirectory;
async function probeDirectory(directory) {
const inspected = await inspectDirectory(directory);
if (inspected !== void 0) return inspected;
for (let attempt = 0; attempt < 10; ++attempt) {
const name = `.typia-case-probe-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`.toLowerCase();
const original = path.join(directory, name);
const alternate = path.join(directory, name.toUpperCase());
let handle;
try {
handle = await fs.promises.open(original, "wx");
} catch (error) {
if (isAlreadyExistsError(error)) continue;
throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to probe filesystem case behavior at ${directory}: ${formatUnknownError(error)}`);
}
let closed = false;
try {
await handle.close();
closed = true;
try {
await fs.promises.lstat(alternate);
return false;
} catch (error) {
if (isMissingFileError(error)) return true;
throw error;
}
} finally {
let cleanupError;
if (closed === false) try {
await handle.close();
} catch (error) {
cleanupError = error;
}
try {
await fs.promises.unlink(original);
} catch (error) {
if (isMissingFileError(error) === false) cleanupError ??= error;
}
if (cleanupError !== void 0) throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to clean filesystem case probe ${original}: ${formatUnknownError(cleanupError)}`);
}
}
throw new URIError(`Error on TypiaGenerateWizard.generate(): unable to reserve a filesystem case probe at ${directory}.`);
}
_FileSystemIdentity.probeDirectory = probeDirectory;
function identityKey(stat, realpath) {
return stat.ino === BigInt(0) ? `path:${path.normalize(realpath)}` : `inode:${stat.dev}:${stat.ino}`;
}
_FileSystemIdentity.identityKey = identityKey;
function alternateCase(name) {
let changed = false;
let output = "";
for (const character of name) if (character >= "a" && character <= "z") {
output += character.toUpperCase();
changed = true;
} else if (character >= "A" && character <= "Z") {
output += character.toLowerCase();
changed = true;
} else output += character;
return changed ? output : void 0;
}
function isAlreadyExistsError(error) {
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
}
function isMissingFileError(error) {
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
}
function formatUnknownError(error) {
return error instanceof Error ? error.message : String(error);
}
})(FileSystemIdentity || (FileSystemIdentity = {}));
const TS_PATTERN = /\.[cm]?tsx?$/;
const DTS_PATTERN = /\.d\.[cm]?tsx?$/;
//#endregion
export { FileSystemIdentity };
//# sourceMappingURL=FileSystemIdentity.mjs.map