UNPKG

@blouflashdb/eslint-plugin-pinia

Version:
1,176 lines (1,169 loc) 43 kB
import { n as __esm } from "./chunk-BLWcukCW.js"; import path from "node:path"; import { fileURLToPath } from "node:url"; import nativeFsp from "node:fs/promises"; //#region node_modules/@humanfs/core/src/hfs.js /** * Asserts that the given path is a valid file path. * @param {any} fileOrDirPath The path to check. * @returns {void} * @throws {TypeError} When the path is not a non-empty string. */ function assertValidFileOrDirPath(fileOrDirPath) { if (!fileOrDirPath || !(fileOrDirPath instanceof URL) && typeof fileOrDirPath !== "string") throw new TypeError("Path must be a non-empty string or URL."); } /** * Asserts that the given file contents are valid. * @param {any} contents The contents to check. * @returns {void} * @throws {TypeError} When the contents are not a string or ArrayBuffer. */ function assertValidFileContents(contents) { if (typeof contents !== "string" && !(contents instanceof ArrayBuffer) && !ArrayBuffer.isView(contents)) throw new TypeError("File contents must be a string, ArrayBuffer, or ArrayBuffer view."); } /** * Converts the given contents to Uint8Array. * @param {any} contents The data to convert. * @returns {Uint8Array} The converted Uint8Array. * @throws {TypeError} When the contents are not a string or ArrayBuffer. */ function toUint8Array(contents) { if (contents instanceof Uint8Array) return contents; if (typeof contents === "string") return encoder.encode(contents); if (contents instanceof ArrayBuffer) return new Uint8Array(contents); if (ArrayBuffer.isView(contents)) { const bytes = contents.buffer.slice(contents.byteOffset, contents.byteOffset + contents.byteLength); return new Uint8Array(bytes); } throw new TypeError("Invalid contents type. Expected string or ArrayBuffer."); } var decoder, encoder, NoSuchMethodError, MethodNotSupportedError, ImplAlreadySetError, LogEntry, Hfs; var init_hfs = __esm({ "node_modules/@humanfs/core/src/hfs.js": (() => { decoder = new TextDecoder(); encoder = new TextEncoder(); NoSuchMethodError = class extends Error { /** * Creates a new instance. * @param {string} methodName The name of the method that was missing. */ constructor(methodName) { super(`Method "${methodName}" does not exist on impl.`); } }; MethodNotSupportedError = class extends Error { /** * Creates a new instance. * @param {string} methodName The name of the method that was missing. */ constructor(methodName) { super(`Method "${methodName}" is not supported on this impl.`); } }; ImplAlreadySetError = class extends Error { /** * Creates a new instance. */ constructor() { super(`Implementation already set.`); } }; LogEntry = class { /** * The type of log entry. * @type {string} */ type; /** * The data associated with the log entry. * @type {any} */ data; /** * The time at which the log entry was created. * @type {number} */ timestamp = Date.now(); /** * Creates a new instance. * @param {string} type The type of log entry. * @param {any} [data] The data associated with the log entry. */ constructor(type, data) { this.type = type; this.data = data; } }; Hfs = class { /** * The base implementation for this instance. * @type {HfsImpl} */ #baseImpl; /** * The current implementation for this instance. * @type {HfsImpl} */ #impl; /** * A map of log names to their corresponding entries. * @type {Map<string,Array<LogEntry>>} */ #logs = /* @__PURE__ */ new Map(); /** * Creates a new instance. * @param {object} options The options for the instance. * @param {HfsImpl} options.impl The implementation to use. */ constructor({ impl }) { this.#baseImpl = impl; this.#impl = impl; } /** * Logs an entry onto all currently open logs. * @param {string} methodName The name of the method being called. * @param {...*} args The arguments to the method. * @returns {void} */ #log(methodName, ...args) { for (const logs of this.#logs.values()) logs.push(new LogEntry("call", { methodName, args })); } /** * Starts a new log with the given name. * @param {string} name The name of the log to start; * @returns {void} * @throws {Error} When the log already exists. * @throws {TypeError} When the name is not a non-empty string. */ logStart(name) { if (!name || typeof name !== "string") throw new TypeError("Log name must be a non-empty string."); if (this.#logs.has(name)) throw new Error(`Log "${name}" already exists.`); this.#logs.set(name, []); } /** * Ends a log with the given name and returns the entries. * @param {string} name The name of the log to end. * @returns {Array<LogEntry>} The entries in the log. * @throws {Error} When the log does not exist. */ logEnd(name) { if (this.#logs.has(name)) { const logs = this.#logs.get(name); this.#logs.delete(name); return logs; } throw new Error(`Log "${name}" does not exist.`); } /** * Determines if the current implementation is the base implementation. * @returns {boolean} True if the current implementation is the base implementation. */ isBaseImpl() { return this.#impl === this.#baseImpl; } /** * Sets the implementation for this instance. * @param {object} impl The implementation to use. * @returns {void} */ setImpl(impl) { this.#log("implSet", impl); if (this.#impl !== this.#baseImpl) throw new ImplAlreadySetError(); this.#impl = impl; } /** * Resets the implementation for this instance back to its original. * @returns {void} */ resetImpl() { this.#log("implReset"); this.#impl = this.#baseImpl; } /** * Asserts that the given method exists on the current implementation. * @param {string} methodName The name of the method to check. * @returns {void} * @throws {NoSuchMethodError} When the method does not exist on the current implementation. */ #assertImplMethod(methodName) { if (typeof this.#impl[methodName] !== "function") throw new NoSuchMethodError(methodName); } /** * Asserts that the given method exists on the current implementation, and if not, * throws an error with a different method name. * @param {string} methodName The name of the method to check. * @param {string} targetMethodName The name of the method that should be reported * as an error when methodName does not exist. * @returns {void} * @throws {NoSuchMethodError} When the method does not exist on the current implementation. */ #assertImplMethodAlt(methodName, targetMethodName) { if (typeof this.#impl[methodName] !== "function") throw new MethodNotSupportedError(targetMethodName); } /** * Calls the given method on the current implementation. * @param {string} methodName The name of the method to call. * @param {...any} args The arguments to the method. * @returns {any} The return value from the method. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. */ #callImplMethod(methodName, ...args) { this.#log(methodName, ...args); this.#assertImplMethod(methodName); return this.#impl[methodName](...args); } /** * Calls the given method on the current implementation and doesn't log the call. * @param {string} methodName The name of the method to call. * @param {...any} args The arguments to the method. * @returns {any} The return value from the method. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. */ #callImplMethodWithoutLog(methodName, ...args) { this.#assertImplMethod(methodName); return this.#impl[methodName](...args); } /** * Calls the given method on the current implementation but logs a different method name. * @param {string} methodName The name of the method to call. * @param {string} targetMethodName The name of the method to log. * @param {...any} args The arguments to the method. * @returns {any} The return value from the method. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. */ #callImplMethodAlt(methodName, targetMethodName, ...args) { this.#log(targetMethodName, ...args); this.#assertImplMethodAlt(methodName, targetMethodName); return this.#impl[methodName](...args); } /** * Reads the given file and returns the contents as text. Assumes UTF-8 encoding. * @param {string|URL} filePath The file to read. * @returns {Promise<string|undefined>} The contents of the file. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {TypeError} When the file path is not a non-empty string. */ async text(filePath) { assertValidFileOrDirPath(filePath); const result = await this.#callImplMethodAlt("bytes", "text", filePath); return result ? decoder.decode(result) : void 0; } /** * Reads the given file and returns the contents as JSON. Assumes UTF-8 encoding. * @param {string|URL} filePath The file to read. * @returns {Promise<any|undefined>} The contents of the file as JSON. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {SyntaxError} When the file contents are not valid JSON. * @throws {TypeError} When the file path is not a non-empty string. */ async json(filePath) { assertValidFileOrDirPath(filePath); const result = await this.#callImplMethodAlt("bytes", "json", filePath); return result ? JSON.parse(decoder.decode(result)) : void 0; } /** * Reads the given file and returns the contents as an ArrayBuffer. * @param {string|URL} filePath The file to read. * @returns {Promise<ArrayBuffer|undefined>} The contents of the file as an ArrayBuffer. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {TypeError} When the file path is not a non-empty string. * @deprecated Use bytes() instead. */ async arrayBuffer(filePath) { assertValidFileOrDirPath(filePath); return (await this.#callImplMethodAlt("bytes", "arrayBuffer", filePath))?.buffer; } /** * Reads the given file and returns the contents as an Uint8Array. * @param {string|URL} filePath The file to read. * @returns {Promise<Uint8Array|undefined>} The contents of the file as an Uint8Array. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {TypeError} When the file path is not a non-empty string. */ async bytes(filePath) { assertValidFileOrDirPath(filePath); return this.#callImplMethod("bytes", filePath); } /** * Writes the given data to the given file. Creates any necessary directories along the way. * If the data is a string, UTF-8 encoding is used. * @param {string|URL} filePath The file to write. * @param {string|ArrayBuffer|ArrayBufferView} contents The data to write. * @returns {Promise<void>} A promise that resolves when the file is written. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {TypeError} When the file path is not a non-empty string. */ async write(filePath, contents) { assertValidFileOrDirPath(filePath); assertValidFileContents(contents); this.#log("write", filePath, contents); let value = toUint8Array(contents); return this.#callImplMethodWithoutLog("write", filePath, value); } /** * Appends the given data to the given file. Creates any necessary directories along the way. * If the data is a string, UTF-8 encoding is used. * @param {string|URL} filePath The file to append to. * @param {string|ArrayBuffer|ArrayBufferView} contents The data to append. * @returns {Promise<void>} A promise that resolves when the file is appended to. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {TypeError} When the file path is not a non-empty string. * @throws {TypeError} When the file contents are not a string or ArrayBuffer. * @throws {Error} When the file cannot be appended to. */ async append(filePath, contents) { assertValidFileOrDirPath(filePath); assertValidFileContents(contents); this.#log("append", filePath, contents); let value = toUint8Array(contents); return this.#callImplMethodWithoutLog("append", filePath, value); } /** * Determines if the given file exists. * @param {string|URL} filePath The file to check. * @returns {Promise<boolean>} True if the file exists. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {TypeError} When the file path is not a non-empty string. */ async isFile(filePath) { assertValidFileOrDirPath(filePath); return this.#callImplMethod("isFile", filePath); } /** * Determines if the given directory exists. * @param {string|URL} dirPath The directory to check. * @returns {Promise<boolean>} True if the directory exists. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {TypeError} When the directory path is not a non-empty string. */ async isDirectory(dirPath) { assertValidFileOrDirPath(dirPath); return this.#callImplMethod("isDirectory", dirPath); } /** * Creates the given directory. * @param {string|URL} dirPath The directory to create. * @returns {Promise<void>} A promise that resolves when the directory is created. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {TypeError} When the directory path is not a non-empty string. */ async createDirectory(dirPath) { assertValidFileOrDirPath(dirPath); return this.#callImplMethod("createDirectory", dirPath); } /** * Deletes the given file or empty directory. * @param {string|URL} filePath The file to delete. * @returns {Promise<boolean>} A promise that resolves when the file or * directory is deleted, true if the file or directory is deleted, false * if the file or directory does not exist. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {TypeError} When the file path is not a non-empty string. */ async delete(filePath) { assertValidFileOrDirPath(filePath); return this.#callImplMethod("delete", filePath); } /** * Deletes the given file or directory recursively. * @param {string|URL} dirPath The directory to delete. * @returns {Promise<boolean>} A promise that resolves when the file or * directory is deleted, true if the file or directory is deleted, false * if the file or directory does not exist. * @throws {NoSuchMethodError} When the method does not exist on the current implementation. * @throws {TypeError} When the directory path is not a non-empty string. */ async deleteAll(dirPath) { assertValidFileOrDirPath(dirPath); return this.#callImplMethod("deleteAll", dirPath); } /** * Returns a list of directory entries for the given path. * @param {string|URL} dirPath The path to the directory to read. * @returns {AsyncIterable<HfsDirectoryEntry>} A promise that resolves with the * directory entries. * @throws {TypeError} If the directory path is not a string or URL. * @throws {Error} If the directory cannot be read. */ async *list(dirPath) { assertValidFileOrDirPath(dirPath); yield* await this.#callImplMethod("list", dirPath); } /** * Walks a directory using a depth-first traversal and returns the entries * from the traversal. * @param {string|URL} dirPath The path to the directory to walk. * @param {Object} [options] The options for the walk. * @param {(entry:HfsWalkEntry) => Promise<boolean>|boolean} [options.directoryFilter] A filter function to determine * if a directory's entries should be included in the walk. * @param {(entry:HfsWalkEntry) => Promise<boolean>|boolean} [options.entryFilter] A filter function to determine if * an entry should be included in the walk. * @returns {AsyncIterable<HfsWalkEntry>} A promise that resolves with the * directory entries. * @throws {TypeError} If the directory path is not a string or URL. * @throws {Error} If the directory cannot be read. */ async *walk(dirPath, { directoryFilter = () => true, entryFilter = () => true } = {}) { assertValidFileOrDirPath(dirPath); this.#log("walk", dirPath, { directoryFilter, entryFilter }); const walk = async function* (dirPath$1, { directoryFilter: directoryFilter$1, entryFilter: entryFilter$1, parentPath = "", depth = 1 }) { let dirEntries; try { dirEntries = await this.#callImplMethodWithoutLog("list", dirPath$1); } catch (error) { if (error.code === "ENOENT") return; throw error; } for await (const listEntry of dirEntries) { const walkEntry = { path: listEntry.name, depth, ...listEntry }; if (parentPath) walkEntry.path = `${parentPath}/${walkEntry.path}`; let shouldEmitEntry = entryFilter$1(walkEntry); if (shouldEmitEntry.then) shouldEmitEntry = await shouldEmitEntry; if (shouldEmitEntry) yield walkEntry; if (listEntry.isDirectory) { let shouldWalkDirectory = directoryFilter$1(walkEntry); if (shouldWalkDirectory.then) shouldWalkDirectory = await shouldWalkDirectory; if (!shouldWalkDirectory) continue; yield* walk(dirPath$1 instanceof URL ? new URL(listEntry.name, dirPath$1.href.endsWith("/") ? dirPath$1.href : `${dirPath$1.href}/`) : `${dirPath$1.endsWith("/") ? dirPath$1 : `${dirPath$1}/`}${listEntry.name}`, { directoryFilter: directoryFilter$1, entryFilter: entryFilter$1, parentPath: walkEntry.path, depth: depth + 1 }); } } }.bind(this); yield* walk(dirPath, { directoryFilter, entryFilter }); } /** * Returns the size of the given file. * @param {string|URL} filePath The path to the file to read. * @returns {Promise<number>} A promise that resolves with the size of the file. * @throws {TypeError} If the file path is not a string or URL. * @throws {Error} If the file cannot be read. */ async size(filePath) { assertValidFileOrDirPath(filePath); return this.#callImplMethod("size", filePath); } /** * Returns the last modified timestamp of the given file or directory. * @param {string|URL} fileOrDirPath The path to the file or directory. * @returns {Promise<Date|undefined>} A promise that resolves with the last modified date * or undefined if the file or directory does not exist. * @throws {TypeError} If the path is not a string or URL. */ async lastModified(fileOrDirPath) { assertValidFileOrDirPath(fileOrDirPath); return this.#callImplMethod("lastModified", fileOrDirPath); } /** * Copys a file from one location to another. * @param {string|URL} source The path to the file to copy. * @param {string|URL} destination The path to the new file. * @returns {Promise<void>} A promise that resolves when the file is copied. * @throws {TypeError} If the file path is not a string or URL. * @throws {Error} If the file cannot be copied. */ async copy(source, destination) { assertValidFileOrDirPath(source); assertValidFileOrDirPath(destination); return this.#callImplMethod("copy", source, destination); } /** * Copies a file or directory from one location to another. * @param {string|URL} source The path to the file or directory to copy. * @param {string|URL} destination The path to copy the file or directory to. * @returns {Promise<void>} A promise that resolves when the file or directory is * copied. * @throws {TypeError} If the directory path is not a string or URL. * @throws {Error} If the directory cannot be copied. */ async copyAll(source, destination) { assertValidFileOrDirPath(source); assertValidFileOrDirPath(destination); return this.#callImplMethod("copyAll", source, destination); } /** * Moves a file from the source path to the destination path. * @param {string|URL} source The location of the file to move. * @param {string|URL} destination The destination of the file to move. * @returns {Promise<void>} A promise that resolves when the move is complete. * @throws {TypeError} If the file or directory paths are not strings. * @throws {Error} If the file or directory cannot be moved. */ async move(source, destination) { assertValidFileOrDirPath(source); assertValidFileOrDirPath(destination); return this.#callImplMethod("move", source, destination); } /** * Moves a file or directory from one location to another. * @param {string|URL} source The path to the file or directory to move. * @param {string|URL} destination The path to move the file or directory to. * @returns {Promise<void>} A promise that resolves when the file or directory is * moved. * @throws {TypeError} If the source is not a string or URL. * @throws {TypeError} If the destination is not a string or URL. * @throws {Error} If the file or directory cannot be moved. */ async moveAll(source, destination) { assertValidFileOrDirPath(source); assertValidFileOrDirPath(destination); return this.#callImplMethod("moveAll", source, destination); } }; }) }); //#endregion //#region node_modules/@humanfs/core/src/errors.js var init_errors = __esm({ "node_modules/@humanfs/core/src/errors.js": (() => {}) }); //#endregion //#region node_modules/@humanfs/core/src/index.js var init_src$1 = __esm({ "node_modules/@humanfs/core/src/index.js": (() => { init_hfs(); init_errors(); }) }); //#endregion //#region node_modules/@humanwhocodes/retry/dist/retrier.js /** * Logs a message to the console if the DEBUG environment variable is set. * @param {string} message The message to log. * @returns {void} */ function debug(message) { if (globalThis?.process?.env.DEBUG === "@hwc/retry") console.debug(message); } /** * Checks if it is time to retry a task based on the timestamp and last attempt time. * @param {RetryTask} task The task to check. * @param {number} maxDelay The maximum delay for the queue. * @returns {boolean} true if it is time to retry, false otherwise. */ function isTimeToRetry(task, maxDelay) { const timeSinceLastAttempt = Date.now() - task.lastAttempt; const timeSinceStart = Math.max(task.lastAttempt - task.timestamp, 1); return timeSinceLastAttempt >= Math.min(timeSinceStart * 1.2, maxDelay); } /** * Checks if it is time to bail out based on the given timestamp. * @param {RetryTask} task The task to check. * @param {number} timeout The timeout for the queue. * @returns {boolean} true if it is time to bail, false otherwise. */ function isTimeToBail(task, timeout) { return task.age > timeout; } /** * Creates a new promise with resolve and reject functions. * @returns {{promise:Promise<any>, resolve:(value:any) => any, reject: (value:any) => any}} A new promise. */ function createPromise() { if (Promise.withResolvers) return Promise.withResolvers(); let resolve$1, reject; const promise = new Promise((res, rej) => { resolve$1 = res; reject = rej; }); if (resolve$1 === void 0 || reject === void 0) throw new Error("Promise executor did not initialize resolve or reject."); return { promise, resolve: resolve$1, reject }; } var MAX_TASK_TIMEOUT, MAX_TASK_DELAY, MAX_CONCURRENCY, RetryTask, Retrier; var init_retrier = __esm({ "node_modules/@humanwhocodes/retry/dist/retrier.js": (() => { MAX_TASK_TIMEOUT = 6e4; MAX_TASK_DELAY = 100; MAX_CONCURRENCY = 1e3; RetryTask = class { /** * The unique ID for the task. * @type {string} */ id = Math.random().toString(36).slice(2); /** * The function to call. * @type {Function} */ fn; /** * The error that was thrown. * @type {Error} */ error; /** * The timestamp of the task. * @type {number} */ timestamp = Date.now(); /** * The timestamp of the last attempt. * @type {number} */ lastAttempt = this.timestamp; /** * The resolve function for the promise. * @type {Function} */ resolve; /** * The reject function for the promise. * @type {Function} */ reject; /** * The AbortSignal to monitor for cancellation. * @type {AbortSignal|undefined} */ signal; /** * Creates a new instance. * @param {Function} fn The function to call. * @param {Error} error The error that was thrown. * @param {Function} resolve The resolve function for the promise. * @param {Function} reject The reject function for the promise. * @param {AbortSignal|undefined} signal The AbortSignal to monitor for cancellation. */ constructor(fn, error, resolve$1, reject, signal) { this.fn = fn; this.error = error; this.timestamp = Date.now(); this.lastAttempt = Date.now(); this.resolve = resolve$1; this.reject = reject; this.signal = signal; } /** * Gets the age of the task. * @returns {number} The age of the task in milliseconds. * @readonly */ get age() { return Date.now() - this.timestamp; } }; Retrier = class { /** * Represents the queue for processing tasks. * @type {Array<RetryTask>} */ #retrying = []; /** * Represents the queue for pending tasks. * @type {Array<Function>} */ #pending = []; /** * The number of tasks currently being processed. * @type {number} */ #working = 0; /** * The timeout for the queue. * @type {number} */ #timeout; /** * The maximum delay for the queue. * @type {number} */ #maxDelay; /** * The setTimeout() timer ID. * @type {NodeJS.Timeout|undefined} */ #timerId; /** * The function to call. * @type {Function} */ #check; /** * The maximum number of concurrent tasks. * @type {number} */ #concurrency; /** * Creates a new instance. * @param {Function} check The function to call. * @param {object} [options] The options for the instance. * @param {number} [options.timeout] The timeout for the queue. * @param {number} [options.maxDelay] The maximum delay for the queue. * @param {number} [options.concurrency] The maximum number of concurrent tasks. */ constructor(check, { timeout = MAX_TASK_TIMEOUT, maxDelay = MAX_TASK_DELAY, concurrency = MAX_CONCURRENCY } = {}) { if (typeof check !== "function") throw new Error("Missing function to check errors"); this.#check = check; this.#timeout = timeout; this.#maxDelay = maxDelay; this.#concurrency = concurrency; } /** * Gets the number of tasks waiting to be retried. * @returns {number} The number of tasks in the retry queue. */ get retrying() { return this.#retrying.length; } /** * Gets the number of tasks waiting to be processed in the pending queue. * @returns {number} The number of tasks in the pending queue. */ get pending() { return this.#pending.length; } /** * Gets the number of tasks currently being processed. * @returns {number} The number of tasks currently being processed. */ get working() { return this.#working; } /** * Calls the function and retries if it fails. * @param {Function} fn The function to call. * @param {Object} options The options for the job. * @param {AbortSignal} [options.signal] The AbortSignal to monitor for cancellation. * @param {Promise<any>} options.promise The promise to return when the function settles. * @param {Function} options.resolve The resolve function for the promise. * @param {Function} options.reject The reject function for the promise. * @returns {Promise<any>} A promise that resolves when the function is * called successfully. */ #call(fn, { signal, promise, resolve: resolve$1, reject }) { let result; try { result = fn(); } catch (error) { reject(new Error(`Synchronous error: ${error.message}`, { cause: error })); return promise; } if (!result || typeof result.then !== "function") { reject(/* @__PURE__ */ new Error("Result is not a promise.")); return promise; } this.#working++; promise.finally(() => { this.#working--; this.#processPending(); }).catch(() => {}); Promise.resolve(result).then((value) => { debug("Function called successfully without retry."); resolve$1(value); }).catch((error) => { if (!this.#check(error)) { reject(error); return; } const task = new RetryTask(fn, error, resolve$1, reject, signal); debug(`Function failed, queuing for retry with task ${task.id}.`); this.#retrying.push(task); signal?.addEventListener("abort", () => { debug(`Task ${task.id} was aborted due to AbortSignal.`); reject(signal.reason); }); this.#processQueue(); }); return promise; } /** * Adds a new retry job to the queue. * @template {(...args: unknown[]) => Promise<unknown>} Func * @template {Awaited<ReturnType<Func>>} RetVal * @param {Func} fn The function to call. * @param {object} [options] The options for the job. * @param {AbortSignal} [options.signal] The AbortSignal to monitor for cancellation. * @returns {Promise<RetVal>} A promise that resolves when the queue is processed. */ retry(fn, { signal } = {}) { signal?.throwIfAborted(); const { promise, resolve: resolve$1, reject } = createPromise(); this.#pending.push(() => this.#call(fn, { signal, promise, resolve: resolve$1, reject })); this.#processPending(); return promise; } /** * Processes the pending queue and the retry queue. * @returns {void} */ #processAll() { if (this.pending) this.#processPending(); if (this.retrying) this.#processQueue(); } /** * Processes the pending queue to see which tasks can be started. * @returns {void} */ #processPending() { debug(`Processing pending tasks: ${this.pending} pending, ${this.working} working.`); const available = this.#concurrency - this.working; if (available <= 0) return; const count = Math.min(this.pending, available); for (let i = 0; i < count; i++) this.#pending.shift()?.(); debug(`Processed pending tasks: ${this.pending} pending, ${this.working} working.`); } /** * Processes the queue. * @returns {void} */ #processQueue() { clearTimeout(this.#timerId); this.#timerId = void 0; debug(`Processing retry queue: ${this.retrying} retrying, ${this.working} working.`); const processAgain = () => { this.#timerId = setTimeout(() => this.#processAll(), 0); }; const task = this.#retrying.shift(); if (!task) { debug("Queue is empty, exiting."); if (this.pending) processAgain(); return; } if (isTimeToBail(task, this.#timeout)) { debug(`Task ${task.id} was abandoned due to timeout.`); task.reject(task.error); processAgain(); return; } if (!isTimeToRetry(task, this.#maxDelay)) { debug(`Task ${task.id} is not ready to retry, skipping.`); this.#retrying.push(task); processAgain(); return; } task.lastAttempt = Date.now(); Promise.resolve(task.fn()).then((result) => { debug(`Task ${task.id} succeeded after ${task.age}ms.`); task.resolve(result); }).catch((error) => { if (!this.#check(error)) { debug(`Task ${task.id} failed with non-retryable error: ${error.message}.`); task.reject(error); return; } task.lastAttempt = Date.now(); this.#retrying.push(task); debug(`Task ${task.id} failed, requeueing to try again.`); }).finally(() => { this.#processAll(); }); } }; }) }); //#endregion //#region node_modules/@humanfs/node/src/node-hfs.js var RETRY_ERROR_CODES, NodeHfsDirectoryEntry, NodeHfsImpl, NodeHfs, hfs; var init_node_hfs = __esm({ "node_modules/@humanfs/node/src/node-hfs.js": (() => { init_src$1(); init_retrier(); RETRY_ERROR_CODES = new Set(["ENFILE", "EMFILE"]); NodeHfsDirectoryEntry = class { /** * The name of the directory entry. * @type {string} */ name; /** * True if the entry is a file. * @type {boolean} */ isFile; /** * True if the entry is a directory. * @type {boolean} */ isDirectory; /** * True if the entry is a symbolic link. * @type {boolean} */ isSymlink; /** * Creates a new instance. * @param {Dirent} dirent The directory entry to wrap. */ constructor(dirent) { this.name = dirent.name; this.isFile = dirent.isFile(); this.isDirectory = dirent.isDirectory(); this.isSymlink = dirent.isSymbolicLink(); } }; NodeHfsImpl = class { /** * The file system module to use. * @type {Fsp} */ #fsp; /** * The retryer object used for retrying operations. * @type {Retrier} */ #retrier; /** * Creates a new instance. * @param {object} [options] The options for the instance. * @param {Fsp} [options.fsp] The file system module to use. */ constructor({ fsp = nativeFsp } = {}) { this.#fsp = fsp; this.#retrier = new Retrier((error) => RETRY_ERROR_CODES.has(error.code)); } /** * Reads a file and returns the contents as an Uint8Array. * @param {string|URL} filePath The path to the file to read. * @returns {Promise<Uint8Array|undefined>} A promise that resolves with the contents * of the file or undefined if the file doesn't exist. * @throws {Error} If the file cannot be read. * @throws {TypeError} If the file path is not a string. */ bytes(filePath) { return this.#retrier.retry(() => this.#fsp.readFile(filePath)).then((buffer) => new Uint8Array(buffer.buffer)).catch((error) => { if (error.code === "ENOENT") return; throw error; }); } /** * Writes a value to a file. If the value is a string, UTF-8 encoding is used. * @param {string|URL} filePath The path to the file to write. * @param {Uint8Array} contents The contents to write to the * file. * @returns {Promise<void>} A promise that resolves when the file is * written. * @throws {TypeError} If the file path is not a string. * @throws {Error} If the file cannot be written. */ async write(filePath, contents) { const value = Buffer.from(contents); return this.#retrier.retry(() => this.#fsp.writeFile(filePath, value)).catch((error) => { if (error.code === "ENOENT") { const dirPath = path.dirname(filePath instanceof URL ? fileURLToPath(filePath) : filePath); return this.#fsp.mkdir(dirPath, { recursive: true }).then(() => this.#fsp.writeFile(filePath, value)); } throw error; }); } /** * Appends a value to a file. If the value is a string, UTF-8 encoding is used. * @param {string|URL} filePath The path to the file to append to. * @param {Uint8Array} contents The contents to append to the * file. * @returns {Promise<void>} A promise that resolves when the file is * written. * @throws {TypeError} If the file path is not a string. * @throws {Error} If the file cannot be appended to. */ async append(filePath, contents) { const value = Buffer.from(contents); return this.#retrier.retry(() => this.#fsp.appendFile(filePath, value)).catch((error) => { if (error.code === "ENOENT") { const dirPath = path.dirname(filePath instanceof URL ? fileURLToPath(filePath) : filePath); return this.#fsp.mkdir(dirPath, { recursive: true }).then(() => this.#fsp.appendFile(filePath, value)); } throw error; }); } /** * Checks if a file exists. * @param {string|URL} filePath The path to the file to check. * @returns {Promise<boolean>} A promise that resolves with true if the * file exists or false if it does not. * @throws {Error} If the operation fails with a code other than ENOENT. */ isFile(filePath) { return this.#fsp.stat(filePath).then((stat) => stat.isFile()).catch((error) => { if (error.code === "ENOENT") return false; throw error; }); } /** * Checks if a directory exists. * @param {string|URL} dirPath The path to the directory to check. * @returns {Promise<boolean>} A promise that resolves with true if the * directory exists or false if it does not. * @throws {Error} If the operation fails with a code other than ENOENT. */ isDirectory(dirPath) { return this.#fsp.stat(dirPath).then((stat) => stat.isDirectory()).catch((error) => { if (error.code === "ENOENT") return false; throw error; }); } /** * Creates a directory recursively. * @param {string|URL} dirPath The path to the directory to create. * @returns {Promise<void>} A promise that resolves when the directory is * created. */ async createDirectory(dirPath) { await this.#fsp.mkdir(dirPath, { recursive: true }); } /** * Deletes a file or empty directory. * @param {string|URL} fileOrDirPath The path to the file or directory to * delete. * @returns {Promise<boolean>} A promise that resolves when the file or * directory is deleted, true if the file or directory is deleted, false * if the file or directory does not exist. * @throws {TypeError} If the file or directory path is not a string. * @throws {Error} If the file or directory cannot be deleted. */ delete(fileOrDirPath) { return this.#fsp.rm(fileOrDirPath).then(() => true).catch((error) => { if (error.code === "ERR_FS_EISDIR") return this.#fsp.rmdir(fileOrDirPath).then(() => true); if (error.code === "ENOENT") return false; throw error; }); } /** * Deletes a file or directory recursively. * @param {string|URL} fileOrDirPath The path to the file or directory to * delete. * @returns {Promise<boolean>} A promise that resolves when the file or * directory is deleted, true if the file or directory is deleted, false * if the file or directory does not exist. * @throws {TypeError} If the file or directory path is not a string. * @throws {Error} If the file or directory cannot be deleted. */ deleteAll(fileOrDirPath) { return this.#fsp.rm(fileOrDirPath, { recursive: true }).then(() => true).catch((error) => { if (error.code === "ENOENT") return false; throw error; }); } /** * Returns a list of directory entries for the given path. * @param {string|URL} dirPath The path to the directory to read. * @returns {AsyncIterable<HfsDirectoryEntry>} A promise that resolves with the * directory entries. * @throws {TypeError} If the directory path is not a string. * @throws {Error} If the directory cannot be read. */ async *list(dirPath) { const entries = await this.#fsp.readdir(dirPath, { withFileTypes: true }); for (const entry of entries) yield new NodeHfsDirectoryEntry(entry); } /** * Returns the size of a file. This method handles ENOENT errors * and returns undefined in that case. * @param {string|URL} filePath The path to the file to read. * @returns {Promise<number|undefined>} A promise that resolves with the size of the * file in bytes or undefined if the file doesn't exist. */ size(filePath) { return this.#fsp.stat(filePath).then((stat) => stat.size).catch((error) => { if (error.code === "ENOENT") return; throw error; }); } /** * Returns the last modified date of a file or directory. This method handles ENOENT errors * and returns undefined in that case. * @param {string|URL} fileOrDirPath The path to the file to read. * @returns {Promise<Date|undefined>} A promise that resolves with the last modified * date of the file or directory, or undefined if the file doesn't exist. */ lastModified(fileOrDirPath) { return this.#fsp.stat(fileOrDirPath).then((stat) => stat.mtime).catch((error) => { if (error.code === "ENOENT") return; throw error; }); } /** * Copies a file from one location to another. * @param {string|URL} source The path to the file to copy. * @param {string|URL} destination The path to copy the file to. * @returns {Promise<void>} A promise that resolves when the file is copied. * @throws {Error} If the source file does not exist. * @throws {Error} If the source file is a directory. * @throws {Error} If the destination file is a directory. */ copy(source, destination) { return this.#fsp.copyFile(source, destination); } /** * Copies a file or directory from one location to another. * @param {string|URL} source The path to the file or directory to copy. * @param {string|URL} destination The path to copy the file or directory to. * @returns {Promise<void>} A promise that resolves when the file or directory is * copied. * @throws {Error} If the source file or directory does not exist. * @throws {Error} If the destination file or directory is a directory. */ async copyAll(source, destination) { if (await this.isFile(source)) return this.copy(source, destination); const sourceStr = source instanceof URL ? fileURLToPath(source) : source; const destinationStr = destination instanceof URL ? fileURLToPath(destination) : destination; await this.createDirectory(destination); for await (const entry of this.list(source)) { const fromEntryPath = path.join(sourceStr, entry.name); const toEntryPath = path.join(destinationStr, entry.name); if (entry.isDirectory) await this.copyAll(fromEntryPath, toEntryPath); else await this.copy(fromEntryPath, toEntryPath); } } /** * Moves a file from the source path to the destination path. * @param {string|URL} source The location of the file to move. * @param {string|URL} destination The destination of the file to move. * @returns {Promise<void>} A promise that resolves when the move is complete. * @throws {TypeError} If the file paths are not strings. * @throws {Error} If the file cannot be moved. */ move(source, destination) { return this.#fsp.stat(source).then((stat) => { if (stat.isDirectory()) throw new Error(`EISDIR: illegal operation on a directory, move '${source}' -> '${destination}'`); return this.#fsp.rename(source, destination); }); } /** * Moves a file or directory from the source path to the destination path. * @param {string|URL} source The location of the file or directory to move. * @param {string|URL} destination The destination of the file or directory to move. * @returns {Promise<void>} A promise that resolves when the move is complete. * @throws {TypeError} If the file paths are not strings. * @throws {Error} If the file or directory cannot be moved. */ async moveAll(source, destination) { return this.#fsp.rename(source, destination); } }; NodeHfs = class extends Hfs { /** * Creates a new instance. * @param {object} [options] The options for the instance. * @param {Fsp} [options.fsp] The file system module to use. */ constructor({ fsp } = {}) { super({ impl: new NodeHfsImpl({ fsp }) }); } }; hfs = new NodeHfs(); }) }); //#endregion //#region node_modules/@humanfs/node/src/index.js var init_src = __esm({ "node_modules/@humanfs/node/src/index.js": (() => { init_node_hfs(); init_src$1(); }) }); //#endregion init_src(); export { Hfs, NodeHfs, NodeHfsImpl, hfs };