Spaces:
Paused
Paused
| ; | |
| var __create = Object.create; | |
| var __defProp = Object.defineProperty; | |
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | |
| var __getOwnPropNames = Object.getOwnPropertyNames; | |
| var __getProtoOf = Object.getPrototypeOf; | |
| var __hasOwnProp = Object.prototype.hasOwnProperty; | |
| var __export = (target, all) => { | |
| for (var name in all) | |
| __defProp(target, name, { get: all[name], enumerable: true }); | |
| }; | |
| var __copyProps = (to, from, except, desc) => { | |
| if (from && typeof from === "object" || typeof from === "function") { | |
| for (let key of __getOwnPropNames(from)) | |
| if (!__hasOwnProp.call(to, key) && key !== except) | |
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | |
| } | |
| return to; | |
| }; | |
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | |
| // If the importer is in node compatibility mode or this is not an ESM | |
| // file that has been converted to a CommonJS file using a Babel- | |
| // compatible transform (i.e. "__esModule" has not been set), then set | |
| // "default" to the CommonJS "module.exports" for node compatibility. | |
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | |
| mod | |
| )); | |
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | |
| var fs_exports = {}; | |
| __export(fs_exports, { | |
| FS: () => FS, | |
| FSPath: () => FSPath | |
| }); | |
| module.exports = __toCommonJS(fs_exports); | |
| var fs = __toESM(require("fs")); | |
| var pathModule = __toESM(require("path")); | |
| var import_streams = require("./streams"); | |
| /** | |
| * FS | |
| * Pokemon Showdown - http://pokemonshowdown.com/ | |
| * | |
| * An abstraction layer around Node's filesystem. | |
| * | |
| * Advantages: | |
| * - write() etc do nothing in unit tests | |
| * - paths are always relative to PS's base directory | |
| * - Promises (seriously wtf Node Core what are you thinking) | |
| * - PS-style API: FS("foo.txt").write("bar") for easier argument order | |
| * - mkdirp | |
| * | |
| * FS is used nearly everywhere, but exceptions include: | |
| * - crashlogger.js - in case the crash is in here | |
| * - repl.js - which use Unix sockets out of this file's scope | |
| * - launch script - happens before modules are loaded | |
| * - sim/ - intended to be self-contained | |
| * | |
| * @author Guangcong Luo <guangcongluo@gmail.com> | |
| * @license MIT | |
| */ | |
| const DIST = `${pathModule.sep}dist${pathModule.sep}`; | |
| const ROOT_PATH = pathModule.resolve(__dirname, __dirname.includes(DIST) ? ".." : "", ".."); | |
| if (!global.__fsState) { | |
| global.__fsState = { | |
| pendingUpdates: /* @__PURE__ */ new Map() | |
| }; | |
| } | |
| class FSPath { | |
| constructor(path) { | |
| this.path = pathModule.resolve(ROOT_PATH, path); | |
| } | |
| parentDir() { | |
| return new FSPath(pathModule.dirname(this.path)); | |
| } | |
| read(options = "utf8") { | |
| if (typeof options !== "string" && options.encoding === void 0) { | |
| options.encoding = "utf8"; | |
| } | |
| return new Promise((resolve, reject) => { | |
| fs.readFile(this.path, options, (err, data) => { | |
| err ? reject(err) : resolve(data); | |
| }); | |
| }); | |
| } | |
| readSync(options = "utf8") { | |
| if (typeof options !== "string" && options.encoding === void 0) { | |
| options.encoding = "utf8"; | |
| } | |
| return fs.readFileSync(this.path, options); | |
| } | |
| readBuffer(options = {}) { | |
| return new Promise((resolve, reject) => { | |
| fs.readFile(this.path, options, (err, data) => { | |
| err ? reject(err) : resolve(data); | |
| }); | |
| }); | |
| } | |
| readBufferSync(options = {}) { | |
| return fs.readFileSync(this.path, options); | |
| } | |
| exists() { | |
| return new Promise((resolve) => { | |
| fs.exists(this.path, (exists) => { | |
| resolve(exists); | |
| }); | |
| }); | |
| } | |
| existsSync() { | |
| return fs.existsSync(this.path); | |
| } | |
| readIfExists() { | |
| return new Promise((resolve, reject) => { | |
| fs.readFile(this.path, "utf8", (err, data) => { | |
| if (err && err.code === "ENOENT") | |
| return resolve(""); | |
| err ? reject(err) : resolve(data); | |
| }); | |
| }); | |
| } | |
| readIfExistsSync() { | |
| try { | |
| return fs.readFileSync(this.path, "utf8"); | |
| } catch (err) { | |
| if (err.code !== "ENOENT") | |
| throw err; | |
| } | |
| return ""; | |
| } | |
| write(data, options = {}) { | |
| if (global.Config?.nofswriting) | |
| return Promise.resolve(); | |
| return new Promise((resolve, reject) => { | |
| fs.writeFile(this.path, data, options, (err) => { | |
| err ? reject(err) : resolve(); | |
| }); | |
| }); | |
| } | |
| writeSync(data, options = {}) { | |
| if (global.Config?.nofswriting) | |
| return; | |
| return fs.writeFileSync(this.path, data, options); | |
| } | |
| /** | |
| * Writes to a new file before renaming to replace an old file. If | |
| * the process crashes while writing, the old file won't be lost. | |
| * Does not protect against simultaneous writing; use writeUpdate | |
| * for that. | |
| */ | |
| async safeWrite(data, options = {}) { | |
| await FS(this.path + ".NEW").write(data, options); | |
| await FS(this.path + ".NEW").rename(this.path); | |
| } | |
| safeWriteSync(data, options = {}) { | |
| FS(this.path + ".NEW").writeSync(data, options); | |
| FS(this.path + ".NEW").renameSync(this.path); | |
| } | |
| /** | |
| * Safest way to update a file with in-memory state. Pass a callback | |
| * that fetches the data to be written. It will write an update, | |
| * avoiding race conditions. The callback may not necessarily be | |
| * called, if `writeUpdate` is called many times in a short period. | |
| * | |
| * `options.throttle`, if it exists, will make sure updates are not | |
| * written more than once every `options.throttle` milliseconds. | |
| * | |
| * No synchronous version because there's no risk of race conditions | |
| * with synchronous code; just use `safeWriteSync`. | |
| */ | |
| writeUpdate(dataFetcher, options = {}) { | |
| if (global.Config?.nofswriting) | |
| return; | |
| const pendingUpdate = __fsState.pendingUpdates.get(this.path); | |
| const throttleTime = options.throttle ? Date.now() + options.throttle : 0; | |
| if (pendingUpdate) { | |
| pendingUpdate.pendingDataFetcher = dataFetcher; | |
| pendingUpdate.pendingOptions = options; | |
| if (pendingUpdate.throttleTimer && throttleTime < pendingUpdate.throttleTime) { | |
| pendingUpdate.throttleTime = throttleTime; | |
| clearTimeout(pendingUpdate.throttleTimer); | |
| pendingUpdate.throttleTimer = setTimeout(() => this.checkNextUpdate(), throttleTime - Date.now()); | |
| } | |
| return; | |
| } | |
| if (!throttleTime) { | |
| this.writeUpdateNow(dataFetcher, options); | |
| return; | |
| } | |
| const update = { | |
| isWriting: false, | |
| pendingDataFetcher: dataFetcher, | |
| pendingOptions: options, | |
| throttleTime, | |
| throttleTimer: setTimeout(() => this.checkNextUpdate(), throttleTime - Date.now()) | |
| }; | |
| __fsState.pendingUpdates.set(this.path, update); | |
| } | |
| writeUpdateNow(dataFetcher, options) { | |
| const throttleTime = options.throttle ? Date.now() + options.throttle : 0; | |
| const update = { | |
| isWriting: true, | |
| pendingDataFetcher: null, | |
| pendingOptions: null, | |
| throttleTime, | |
| throttleTimer: null | |
| }; | |
| __fsState.pendingUpdates.set(this.path, update); | |
| void this.safeWrite(dataFetcher(), options).then(() => this.finishUpdate()); | |
| } | |
| checkNextUpdate() { | |
| const pendingUpdate = __fsState.pendingUpdates.get(this.path); | |
| if (!pendingUpdate) | |
| throw new Error(`FS: Pending update not found`); | |
| if (pendingUpdate.isWriting) | |
| throw new Error(`FS: Conflicting update`); | |
| const { pendingDataFetcher: dataFetcher, pendingOptions: options } = pendingUpdate; | |
| if (!dataFetcher || !options) { | |
| __fsState.pendingUpdates.delete(this.path); | |
| return; | |
| } | |
| this.writeUpdateNow(dataFetcher, options); | |
| } | |
| finishUpdate() { | |
| const pendingUpdate = __fsState.pendingUpdates.get(this.path); | |
| if (!pendingUpdate) | |
| throw new Error(`FS: Pending update not found`); | |
| if (!pendingUpdate.isWriting) | |
| throw new Error(`FS: Conflicting update`); | |
| pendingUpdate.isWriting = false; | |
| const throttleTime = pendingUpdate.throttleTime; | |
| if (!throttleTime || throttleTime < Date.now()) { | |
| this.checkNextUpdate(); | |
| return; | |
| } | |
| pendingUpdate.throttleTimer = setTimeout(() => this.checkNextUpdate(), throttleTime - Date.now()); | |
| } | |
| append(data, options = {}) { | |
| if (global.Config?.nofswriting) | |
| return Promise.resolve(); | |
| return new Promise((resolve, reject) => { | |
| fs.appendFile(this.path, data, options, (err) => { | |
| err ? reject(err) : resolve(); | |
| }); | |
| }); | |
| } | |
| appendSync(data, options = {}) { | |
| if (global.Config?.nofswriting) | |
| return; | |
| return fs.appendFileSync(this.path, data, options); | |
| } | |
| symlinkTo(target) { | |
| if (global.Config?.nofswriting) | |
| return Promise.resolve(); | |
| return new Promise((resolve, reject) => { | |
| fs.symlink(target, this.path, (err) => { | |
| err ? reject(err) : resolve(); | |
| }); | |
| }); | |
| } | |
| symlinkToSync(target) { | |
| if (global.Config?.nofswriting) | |
| return; | |
| return fs.symlinkSync(target, this.path); | |
| } | |
| copyFile(dest) { | |
| if (global.Config?.nofswriting) | |
| return Promise.resolve(); | |
| return new Promise((resolve, reject) => { | |
| fs.copyFile(this.path, dest, (err) => { | |
| err ? reject(err) : resolve(); | |
| }); | |
| }); | |
| } | |
| rename(target) { | |
| if (global.Config?.nofswriting) | |
| return Promise.resolve(); | |
| return new Promise((resolve, reject) => { | |
| fs.rename(this.path, target, (err) => { | |
| err ? reject(err) : resolve(); | |
| }); | |
| }); | |
| } | |
| renameSync(target) { | |
| if (global.Config?.nofswriting) | |
| return; | |
| return fs.renameSync(this.path, target); | |
| } | |
| readdir() { | |
| return new Promise((resolve, reject) => { | |
| fs.readdir(this.path, (err, data) => { | |
| err ? reject(err) : resolve(data); | |
| }); | |
| }); | |
| } | |
| readdirSync() { | |
| return fs.readdirSync(this.path); | |
| } | |
| async readdirIfExists() { | |
| if (await this.exists()) | |
| return this.readdir(); | |
| return Promise.resolve([]); | |
| } | |
| readdirIfExistsSync() { | |
| if (this.existsSync()) | |
| return this.readdirSync(); | |
| return []; | |
| } | |
| createReadStream() { | |
| return new FileReadStream(this.path); | |
| } | |
| createWriteStream(options = {}) { | |
| if (global.Config?.nofswriting) { | |
| return new import_streams.WriteStream({ write() { | |
| } }); | |
| } | |
| return new import_streams.WriteStream(fs.createWriteStream(this.path, options)); | |
| } | |
| createAppendStream(options = {}) { | |
| if (global.Config?.nofswriting) { | |
| return new import_streams.WriteStream({ write() { | |
| } }); | |
| } | |
| options.flags = options.flags || "a"; | |
| return new import_streams.WriteStream(fs.createWriteStream(this.path, options)); | |
| } | |
| unlinkIfExists() { | |
| if (global.Config?.nofswriting) | |
| return Promise.resolve(); | |
| return new Promise((resolve, reject) => { | |
| fs.unlink(this.path, (err) => { | |
| if (err && err.code === "ENOENT") | |
| return resolve(); | |
| err ? reject(err) : resolve(); | |
| }); | |
| }); | |
| } | |
| unlinkIfExistsSync() { | |
| if (global.Config?.nofswriting) | |
| return; | |
| try { | |
| fs.unlinkSync(this.path); | |
| } catch (err) { | |
| if (err.code !== "ENOENT") | |
| throw err; | |
| } | |
| } | |
| async rmdir(recursive) { | |
| if (global.Config?.nofswriting) | |
| return Promise.resolve(); | |
| return new Promise((resolve, reject) => { | |
| fs.rmdir(this.path, { recursive }, (err) => { | |
| err ? reject(err) : resolve(); | |
| }); | |
| }); | |
| } | |
| rmdirSync(recursive) { | |
| if (global.Config?.nofswriting) | |
| return; | |
| return fs.rmdirSync(this.path, { recursive }); | |
| } | |
| mkdir(mode = 493) { | |
| if (global.Config?.nofswriting) | |
| return Promise.resolve(); | |
| return new Promise((resolve, reject) => { | |
| fs.mkdir(this.path, mode, (err) => { | |
| err ? reject(err) : resolve(); | |
| }); | |
| }); | |
| } | |
| mkdirSync(mode = 493) { | |
| if (global.Config?.nofswriting) | |
| return; | |
| return fs.mkdirSync(this.path, mode); | |
| } | |
| mkdirIfNonexistent(mode = 493) { | |
| if (global.Config?.nofswriting) | |
| return Promise.resolve(); | |
| return new Promise((resolve, reject) => { | |
| fs.mkdir(this.path, mode, (err) => { | |
| if (err && err.code === "EEXIST") | |
| return resolve(); | |
| err ? reject(err) : resolve(); | |
| }); | |
| }); | |
| } | |
| mkdirIfNonexistentSync(mode = 493) { | |
| if (global.Config?.nofswriting) | |
| return; | |
| try { | |
| fs.mkdirSync(this.path, mode); | |
| } catch (err) { | |
| if (err.code !== "EEXIST") | |
| throw err; | |
| } | |
| } | |
| /** | |
| * Creates the directory (and any parent directories if necessary). | |
| * Does not throw if the directory already exists. | |
| */ | |
| async mkdirp(mode = 493) { | |
| try { | |
| await this.mkdirIfNonexistent(mode); | |
| } catch (err) { | |
| if (err.code !== "ENOENT") | |
| throw err; | |
| await this.parentDir().mkdirp(mode); | |
| await this.mkdirIfNonexistent(mode); | |
| } | |
| } | |
| /** | |
| * Creates the directory (and any parent directories if necessary). | |
| * Does not throw if the directory already exists. Synchronous. | |
| */ | |
| mkdirpSync(mode = 493) { | |
| try { | |
| this.mkdirIfNonexistentSync(mode); | |
| } catch (err) { | |
| if (err.code !== "ENOENT") | |
| throw err; | |
| this.parentDir().mkdirpSync(mode); | |
| this.mkdirIfNonexistentSync(mode); | |
| } | |
| } | |
| /** Calls the callback if the file is modified. */ | |
| onModify(callback) { | |
| fs.watchFile(this.path, (curr, prev) => { | |
| if (curr.mtime > prev.mtime) | |
| return callback(); | |
| }); | |
| } | |
| /** Clears callbacks added with onModify(). */ | |
| unwatch() { | |
| fs.unwatchFile(this.path); | |
| } | |
| async isFile() { | |
| return new Promise((resolve, reject) => { | |
| fs.stat(this.path, (err, stats) => { | |
| err ? reject(err) : resolve(stats.isFile()); | |
| }); | |
| }); | |
| } | |
| isFileSync() { | |
| return fs.statSync(this.path).isFile(); | |
| } | |
| async isDirectory() { | |
| return new Promise((resolve, reject) => { | |
| fs.stat(this.path, (err, stats) => { | |
| err ? reject(err) : resolve(stats.isDirectory()); | |
| }); | |
| }); | |
| } | |
| isDirectorySync() { | |
| return fs.statSync(this.path).isDirectory(); | |
| } | |
| async realpath() { | |
| return new Promise((resolve, reject) => { | |
| fs.realpath(this.path, (err, path) => { | |
| err ? reject(err) : resolve(path); | |
| }); | |
| }); | |
| } | |
| realpathSync() { | |
| return fs.realpathSync(this.path); | |
| } | |
| } | |
| class FileReadStream extends import_streams.ReadStream { | |
| constructor(file) { | |
| super(); | |
| this.fd = new Promise((resolve, reject) => { | |
| fs.open(file, "r", (err, fd) => err ? reject(err) : resolve(fd)); | |
| }); | |
| this.atEOF = false; | |
| } | |
| _read(size = 16384) { | |
| return new Promise((resolve, reject) => { | |
| if (this.atEOF) | |
| return void resolve(); | |
| this.ensureCapacity(size); | |
| void this.fd.then((fd) => { | |
| fs.read(fd, this.buf, this.bufEnd, size, null, (err, bytesRead, buf) => { | |
| if (err) | |
| return reject(err); | |
| if (!bytesRead) { | |
| this.atEOF = true; | |
| this.resolvePush(); | |
| return resolve(); | |
| } | |
| this.bufEnd += bytesRead; | |
| this.resolvePush(); | |
| resolve(); | |
| }); | |
| }); | |
| }); | |
| } | |
| _destroy() { | |
| return new Promise((resolve) => { | |
| void this.fd.then((fd) => { | |
| fs.close(fd, () => resolve()); | |
| }); | |
| }); | |
| } | |
| } | |
| function getFs(path) { | |
| return new FSPath(path); | |
| } | |
| const FS = Object.assign(getFs, { | |
| FileReadStream, | |
| FSPath, | |
| ROOT_PATH | |
| }); | |
| //# sourceMappingURL=fs.js.map | |