UNPKG

@fimbul/wotan

Version:

Pluggable TypeScript and JavaScript linter

137 lines 5.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CachedFileSystem = exports.FileKind = void 0; const tslib_1 = require("tslib"); const inversify_1 = require("inversify"); const ymir_1 = require("@fimbul/ymir"); const bind_decorator_1 = require("bind-decorator"); const utils_1 = require("../utils"); const path = require("path"); var FileKind; (function (FileKind) { FileKind[FileKind["NonExistent"] = 0] = "NonExistent"; FileKind[FileKind["File"] = 1] = "File"; FileKind[FileKind["Directory"] = 2] = "Directory"; FileKind[FileKind["Other"] = 3] = "Other"; })(FileKind = exports.FileKind || (exports.FileKind = {})); let CachedFileSystem = class CachedFileSystem { constructor(fs, cache) { this.fs = fs; this.realpath = this.fs.realpath === undefined ? undefined : (file) => { return utils_1.resolveCachedResult(this.realpathCache, this.fs.normalizePath(file), () => this.fs.realpath(file)); }; this.fileKindCache = cache.create(); this.realpathCache = cache.create(); this.direntCache = cache.create(); } isFile(file) { return utils_1.resolveCachedResult(this.fileKindCache, this.fs.normalizePath(file), this.doGetKind) === 1 /* File */; } isDirectory(dir) { return utils_1.resolveCachedResult(this.fileKindCache, this.fs.normalizePath(dir), this.doGetKind) === 2 /* Directory */; } getKind(file) { return utils_1.resolveCachedResult(this.fileKindCache, this.fs.normalizePath(file), this.doGetKind); } doGetKind(file) { try { return statsToKind(this.fs.stat(file)); } catch { return 0 /* NonExistent */; } } readDirectory(dir) { dir = this.fs.normalizePath(dir); let cachedResult = this.direntCache.get(dir); if (cachedResult !== undefined) return cachedResult.map((entry) => ({ kind: this.fileKindCache.get(this.fs.normalizePath(path.join(dir, entry))), name: entry })); cachedResult = []; const result = []; for (const entry of this.fs.readDirectory(dir)) { if (typeof entry === 'string') { cachedResult.push(entry); result.push({ kind: this.getKind(path.join(dir, entry)), name: entry }); } else { cachedResult.push(entry.name); const filePath = path.join(dir, entry.name); let kind; if (entry.isSymbolicLink()) { kind = this.getKind(filePath); } else { kind = statsToKind(entry); this.fileKindCache.set(this.fs.normalizePath(filePath), kind); } result.push({ kind, name: entry.name }); } } this.direntCache.set(dir, cachedResult); return result; } readFile(file) { return this.fs.readFile(this.fs.normalizePath(file)); } writeFile(file, content) { file = this.fs.normalizePath(file); this.fs.writeFile(file, content); this.updateCache(file, 1 /* File */); } remove(file) { file = this.fs.normalizePath(file); this.fs.deleteFile(file); this.updateCache(file, 0 /* NonExistent */); } createDirectory(dir) { dir = this.fs.normalizePath(dir); if (this.fileKindCache.get(dir) === 2 /* Directory */) return; return this.doCreateDirectory(dir); } doCreateDirectory(dir) { try { this.fs.createDirectory(dir); } catch (e) { try { const stat = this.fs.stat(dir); if (!stat.isDirectory()) throw e; } catch { const parent = this.fs.normalizePath(path.dirname(dir)); if (parent === dir) throw e; this.doCreateDirectory(parent); this.fs.createDirectory(dir); } } this.updateCache(dir, 2 /* Directory */); } updateCache(file, kind) { // this currently doesn't handle directory removal as there is no API for that if (this.fileKindCache.get(file) === kind) return; this.fileKindCache.set(file, kind); if (kind === 0 /* NonExistent */) this.realpathCache.delete(file); // only invalidate realpath cache on file removal // invalidate direntCache unconditionally as the new file's name might differ in case from the one we have here this.direntCache.delete(this.fs.normalizePath(path.dirname(file))); } }; tslib_1.__decorate([ bind_decorator_1.default, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", Number) ], CachedFileSystem.prototype, "doGetKind", null); CachedFileSystem = tslib_1.__decorate([ inversify_1.injectable(), tslib_1.__metadata("design:paramtypes", [ymir_1.FileSystem, ymir_1.CacheFactory]) ], CachedFileSystem); exports.CachedFileSystem = CachedFileSystem; function statsToKind(stats) { return stats.isFile() ? 1 /* File */ : stats.isDirectory() ? 2 /* Directory */ : 3 /* Other */; } //# sourceMappingURL=cached-file-system.js.map