@intlayer/chokidar
Version:
Scans and builds Intlayer declaration files into dictionaries based on Intlayer configuration.
1 lines • 7.8 kB
Source Map (JSON)
{"version":3,"file":"pLimit.mjs","names":["#head","#tail","#size"],"sources":["../../../src/utils/pLimit.ts"],"sourcesContent":["/*\nHow it works:\n`this.#head` is an instance of `Node` which keeps track of its current value and nests another instance of `Node` that keeps the value that comes after it. When a value is provided to `.enqueue()`, the code needs to iterate through `this.#head`, going deeper and deeper to find the last value. However, iterating through every single item is slow. This problem is solved by saving a reference to the last value as `this.#tail` so that it can reference it to add a new value.\n*/\n\nclass Node<T> {\n value: T;\n next: Node<T> | undefined;\n\n constructor(value: T) {\n this.value = value;\n }\n}\n\nexport class Queue<T> {\n #head: Node<T> | undefined;\n #tail: Node<T> | undefined;\n #size!: number;\n\n constructor() {\n this.clear();\n }\n\n enqueue(value: T): void {\n const node = new Node(value);\n\n if (this.#head) {\n this.#tail!.next = node;\n this.#tail = node;\n } else {\n this.#head = node;\n this.#tail = node;\n }\n\n this.#size++;\n }\n\n dequeue(): T | undefined {\n const current = this.#head;\n if (!current) {\n return;\n }\n\n this.#head = current.next;\n this.#size--;\n return current.value;\n }\n\n peek(): T | undefined {\n if (!this.#head) {\n return;\n }\n\n return this.#head.value;\n\n // TODO: Node.js 18.\n // return this.#head?.value;\n }\n\n clear(): void {\n this.#head = undefined;\n this.#tail = undefined;\n this.#size = 0;\n }\n\n get size(): number {\n return this.#size;\n }\n\n *[Symbol.iterator](): Generator<T, void, unknown> {\n let current = this.#head;\n\n while (current) {\n yield current.value;\n current = current.next;\n }\n }\n\n *drain(): Generator<T | undefined, void, unknown> {\n while (this.#head) {\n yield this.dequeue();\n }\n }\n}\n\nexport const pLimit = (concurrency: number) => {\n validateConcurrency(concurrency);\n\n const queue = new Queue<() => void>();\n let activeCount = 0;\n\n const idleWaiters: Array<() => void> = [];\n const notifyIdleIfNeeded = (): void => {\n if (activeCount === 0 && queue.size === 0) {\n while (idleWaiters.length) idleWaiters.pop()?.();\n }\n };\n\n const resumeNext = (): void => {\n // Process the next queued function if we're under the concurrency limit\n if (activeCount < concurrency && queue.size > 0) {\n activeCount++;\n queue.dequeue()?.();\n }\n };\n\n const next = (): void => {\n activeCount--;\n resumeNext();\n };\n\n const run = async (\n fn: (...args: any[]) => Promise<any>,\n resolve: (value: Promise<any>) => void,\n arguments_: any[]\n ): Promise<void> => {\n // Execute the function and capture the result promise\n const result = (async () => fn(...arguments_))();\n\n // Resolve immediately with the promise (don't wait for completion)\n resolve(result);\n\n // Wait for the function to complete (success or failure)\n // We catch errors here to prevent unhandled rejections,\n // but the original promise rejection is preserved for the caller\n try {\n await result;\n } catch {}\n\n // Decrement active count and process next queued function\n next();\n };\n\n const enqueue = (\n fn: (...args: any[]) => Promise<any>,\n resolve: (value: Promise<any>) => void,\n arguments_: any[]\n ): void => {\n // Queue the internal resolve function instead of the run function\n // to preserve the asynchronous execution context.\n new Promise<void>((internalResolve) => {\n queue.enqueue(internalResolve);\n }).then(run.bind(undefined, fn, resolve, arguments_));\n\n // Start processing immediately if we haven't reached the concurrency limit\n if (activeCount < concurrency) {\n resumeNext();\n }\n };\n\n const generator = (\n fn: (...args: any[]) => Promise<any>,\n ...arguments_: any[]\n ): Promise<any> =>\n new Promise<any>((resolve) => {\n enqueue(fn, resolve, arguments_);\n });\n\n Object.defineProperties(generator, {\n activeCount: {\n get: () => activeCount,\n },\n pendingCount: {\n get: () => queue.size,\n },\n clearQueue: {\n value() {\n queue.clear();\n notifyIdleIfNeeded();\n },\n },\n concurrency: {\n get: () => concurrency,\n\n set(newConcurrency: number) {\n validateConcurrency(newConcurrency);\n concurrency = newConcurrency;\n\n queueMicrotask(() => {\n while (activeCount < concurrency && queue.size > 0) {\n resumeNext();\n }\n });\n },\n },\n map: {\n async value<T, R>(\n array: T[],\n fn: (value: T, index: number) => Promise<R>\n ): Promise<R[]> {\n const promises = array.map((value, index) => this(fn, value, index));\n return Promise.all(promises);\n },\n },\n onIdle: {\n /**\n * Resolves when `activeCount === 0` and the queue is empty.\n * Use this to wait for completion without holding a list of Promises.\n */\n value(): Promise<void> {\n if (activeCount === 0 && queue.size === 0) return Promise.resolve();\n return new Promise<void>((resolve) => idleWaiters.push(resolve));\n },\n },\n });\n\n return generator;\n};\n\nconst validateConcurrency = (concurrency: number): void => {\n if (\n !(\n (Number.isInteger(concurrency) ||\n concurrency === Number.POSITIVE_INFINITY) &&\n concurrency > 0\n )\n ) {\n throw new TypeError('Expected `concurrency` to be a number from 1 and up');\n }\n};\n"],"mappings":"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"}