UNPKG

@pkerschbaum/code-oss-file-service

Version:

VS Code ([microsoft/vscode](https://github.com/microsoft/vscode)) includes a rich "`FileService`" and "`DiskFileSystemProvider`" abstraction built on top of Node.js core modules (`fs`, `path`) and Electron's `shell` module. This package allows to use that

1,376 lines 48.4 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __asyncValues = (this && this.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createCancelableAsyncIterable = exports.CancelableAsyncIterableObject = exports.AsyncIterableObject = exports.Promises = exports.DeferredPromise = exports.IntervalCounter = exports.TaskSequentializer = exports.retry = exports.IdleValue = exports.runWhenIdle = exports.ThrottledWorker = exports.RunOnceWorker = exports.RunOnceScheduler = exports.IntervalTimer = exports.TimeoutTimer = exports.ResourceQueue = exports.Queue = exports.Limiter = exports.firstParallel = exports.first = exports.sequence = exports.disposableTimeout = exports.timeout = exports.AutoOpenBarrier = exports.Barrier = exports.ThrottledDelayer = exports.Delayer = exports.MicrotaskDelay = exports.SequencerByKey = exports.Sequencer = exports.Throttler = exports.asPromise = exports.raceTimeout = exports.raceCancellablePromises = exports.raceCancellation = exports.createCancelablePromise = exports.isThenable = void 0; const cancellation_1 = require("../../base/common/cancellation"); const errors_1 = require("../../base/common/errors"); const event_1 = require("../../base/common/event"); const lifecycle_1 = require("../../base/common/lifecycle"); const resources_1 = require("../../base/common/resources"); const platform_1 = require("../../base/common/platform"); function isThenable(obj) { return !!obj && typeof obj.then === 'function'; } exports.isThenable = isThenable; function createCancelablePromise(callback) { const source = new cancellation_1.CancellationTokenSource(); const thenable = callback(source.token); const promise = new Promise((resolve, reject) => { const subscription = source.token.onCancellationRequested(() => { subscription.dispose(); source.dispose(); reject((0, errors_1.canceled)()); }); Promise.resolve(thenable).then(value => { subscription.dispose(); source.dispose(); resolve(value); }, err => { subscription.dispose(); source.dispose(); reject(err); }); }); return new class { cancel() { source.cancel(); } then(resolve, reject) { return promise.then(resolve, reject); } catch(reject) { return this.then(undefined, reject); } finally(onfinally) { return promise.finally(onfinally); } }; } exports.createCancelablePromise = createCancelablePromise; function raceCancellation(promise, token, defaultValue) { return Promise.race([promise, new Promise(resolve => token.onCancellationRequested(() => resolve(defaultValue)))]); } exports.raceCancellation = raceCancellation; /** * Returns as soon as one of the promises is resolved and cancels remaining promises */ function raceCancellablePromises(cancellablePromises) { return __awaiter(this, void 0, void 0, function* () { let resolvedPromiseIndex = -1; const promises = cancellablePromises.map((promise, index) => promise.then(result => { resolvedPromiseIndex = index; return result; })); const result = yield Promise.race(promises); cancellablePromises.forEach((cancellablePromise, index) => { if (index !== resolvedPromiseIndex) { cancellablePromise.cancel(); } }); return result; }); } exports.raceCancellablePromises = raceCancellablePromises; function raceTimeout(promise, timeout, onTimeout) { let promiseResolve = undefined; const timer = setTimeout(() => { promiseResolve === null || promiseResolve === void 0 ? void 0 : promiseResolve(undefined); onTimeout === null || onTimeout === void 0 ? void 0 : onTimeout(); }, timeout); return Promise.race([ promise.finally(() => clearTimeout(timer)), new Promise(resolve => promiseResolve = resolve) ]); } exports.raceTimeout = raceTimeout; function asPromise(callback) { return new Promise((resolve, reject) => { const item = callback(); if (isThenable(item)) { item.then(resolve, reject); } else { resolve(item); } }); } exports.asPromise = asPromise; /** * A helper to prevent accumulation of sequential async tasks. * * Imagine a mail man with the sole task of delivering letters. As soon as * a letter submitted for delivery, he drives to the destination, delivers it * and returns to his base. Imagine that during the trip, N more letters were submitted. * When the mail man returns, he picks those N letters and delivers them all in a * single trip. Even though N+1 submissions occurred, only 2 deliveries were made. * * The throttler implements this via the queue() method, by providing it a task * factory. Following the example: * * const throttler = new Throttler(); * const letters = []; * * function deliver() { * const lettersToDeliver = letters; * letters = []; * return makeTheTrip(lettersToDeliver); * } * * function onLetterReceived(l) { * letters.push(l); * throttler.queue(deliver); * } */ class Throttler { constructor() { this.activePromise = null; this.queuedPromise = null; this.queuedPromiseFactory = null; } queue(promiseFactory) { if (this.activePromise) { this.queuedPromiseFactory = promiseFactory; if (!this.queuedPromise) { const onComplete = () => { this.queuedPromise = null; const result = this.queue(this.queuedPromiseFactory); this.queuedPromiseFactory = null; return result; }; this.queuedPromise = new Promise(resolve => { this.activePromise.then(onComplete, onComplete).then(resolve); }); } return new Promise((resolve, reject) => { this.queuedPromise.then(resolve, reject); }); } this.activePromise = promiseFactory(); return new Promise((resolve, reject) => { this.activePromise.then((result) => { this.activePromise = null; resolve(result); }, (err) => { this.activePromise = null; reject(err); }); }); } } exports.Throttler = Throttler; class Sequencer { constructor() { this.current = Promise.resolve(null); } queue(promiseTask) { return this.current = this.current.then(() => promiseTask(), () => promiseTask()); } } exports.Sequencer = Sequencer; class SequencerByKey { constructor() { this.promiseMap = new Map(); } queue(key, promiseTask) { var _a; const runningPromise = (_a = this.promiseMap.get(key)) !== null && _a !== void 0 ? _a : Promise.resolve(); const newPromise = runningPromise .catch(() => { }) .then(promiseTask) .finally(() => { if (this.promiseMap.get(key) === newPromise) { this.promiseMap.delete(key); } }); this.promiseMap.set(key, newPromise); return newPromise; } } exports.SequencerByKey = SequencerByKey; const timeoutDeferred = (timeout, fn) => { let scheduled = true; const handle = setTimeout(() => { scheduled = false; fn(); }, timeout); return { isTriggered: () => scheduled, dispose: () => { clearTimeout(handle); scheduled = false; }, }; }; const microtaskDeferred = (fn) => { let scheduled = true; queueMicrotask(() => { if (scheduled) { scheduled = false; fn(); } }); return { isTriggered: () => scheduled, dispose: () => { scheduled = false; }, }; }; /** Can be passed into the Delayed to defer using a microtask */ exports.MicrotaskDelay = Symbol('MicrotaskDelay'); /** * A helper to delay (debounce) execution of a task that is being requested often. * * Following the throttler, now imagine the mail man wants to optimize the number of * trips proactively. The trip itself can be long, so he decides not to make the trip * as soon as a letter is submitted. Instead he waits a while, in case more * letters are submitted. After said waiting period, if no letters were submitted, he * decides to make the trip. Imagine that N more letters were submitted after the first * one, all within a short period of time between each other. Even though N+1 * submissions occurred, only 1 delivery was made. * * The delayer offers this behavior via the trigger() method, into which both the task * to be executed and the waiting period (delay) must be passed in as arguments. Following * the example: * * const delayer = new Delayer(WAITING_PERIOD); * const letters = []; * * function letterReceived(l) { * letters.push(l); * delayer.trigger(() => { return makeTheTrip(); }); * } */ class Delayer { constructor(defaultDelay) { this.defaultDelay = defaultDelay; this.deferred = null; this.completionPromise = null; this.doResolve = null; this.doReject = null; this.task = null; } trigger(task, delay = this.defaultDelay) { this.task = task; this.cancelTimeout(); if (!this.completionPromise) { this.completionPromise = new Promise((resolve, reject) => { this.doResolve = resolve; this.doReject = reject; }).then(() => { this.completionPromise = null; this.doResolve = null; if (this.task) { const task = this.task; this.task = null; return task(); } return undefined; }); } const fn = () => { var _a; this.deferred = null; (_a = this.doResolve) === null || _a === void 0 ? void 0 : _a.call(this, null); }; this.deferred = delay === exports.MicrotaskDelay ? microtaskDeferred(fn) : timeoutDeferred(delay, fn); return this.completionPromise; } isTriggered() { var _a; return !!((_a = this.deferred) === null || _a === void 0 ? void 0 : _a.isTriggered()); } cancel() { this.cancelTimeout(); if (this.completionPromise) { if (this.doReject) { this.doReject((0, errors_1.canceled)()); } this.completionPromise = null; } } cancelTimeout() { var _a; (_a = this.deferred) === null || _a === void 0 ? void 0 : _a.dispose(); this.deferred = null; } dispose() { this.cancel(); } } exports.Delayer = Delayer; /** * A helper to delay execution of a task that is being requested often, while * preventing accumulation of consecutive executions, while the task runs. * * The mail man is clever and waits for a certain amount of time, before going * out to deliver letters. While the mail man is going out, more letters arrive * and can only be delivered once he is back. Once he is back the mail man will * do one more trip to deliver the letters that have accumulated while he was out. */ class ThrottledDelayer { constructor(defaultDelay) { this.delayer = new Delayer(defaultDelay); this.throttler = new Throttler(); } trigger(promiseFactory, delay) { return this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay); } isTriggered() { return this.delayer.isTriggered(); } cancel() { this.delayer.cancel(); } dispose() { this.delayer.dispose(); } } exports.ThrottledDelayer = ThrottledDelayer; /** * A barrier that is initially closed and then becomes opened permanently. */ class Barrier { constructor() { this._isOpen = false; this._promise = new Promise((c, e) => { this._completePromise = c; }); } isOpen() { return this._isOpen; } open() { this._isOpen = true; this._completePromise(true); } wait() { return this._promise; } } exports.Barrier = Barrier; /** * A barrier that is initially closed and then becomes opened permanently after a certain period of * time or when open is called explicitly */ class AutoOpenBarrier extends Barrier { constructor(autoOpenTimeMs) { super(); this._timeout = setTimeout(() => this.open(), autoOpenTimeMs); } open() { clearTimeout(this._timeout); super.open(); } } exports.AutoOpenBarrier = AutoOpenBarrier; function timeout(millis, token) { if (!token) { return createCancelablePromise(token => timeout(millis, token)); } return new Promise((resolve, reject) => { const handle = setTimeout(() => { disposable.dispose(); resolve(); }, millis); const disposable = token.onCancellationRequested(() => { clearTimeout(handle); disposable.dispose(); reject((0, errors_1.canceled)()); }); }); } exports.timeout = timeout; function disposableTimeout(handler, timeout = 0) { const timer = setTimeout(handler, timeout); return (0, lifecycle_1.toDisposable)(() => clearTimeout(timer)); } exports.disposableTimeout = disposableTimeout; /** * Runs the provided list of promise factories in sequential order. The returned * promise will complete to an array of results from each promise. */ function sequence(promiseFactories) { const results = []; let index = 0; const len = promiseFactories.length; function next() { return index < len ? promiseFactories[index++]() : null; } function thenHandler(result) { if (result !== undefined && result !== null) { results.push(result); } const n = next(); if (n) { return n.then(thenHandler); } return Promise.resolve(results); } return Promise.resolve(null).then(thenHandler); } exports.sequence = sequence; function first(promiseFactories, shouldStop = t => !!t, defaultValue = null) { let index = 0; const len = promiseFactories.length; const loop = () => { if (index >= len) { return Promise.resolve(defaultValue); } const factory = promiseFactories[index++]; const promise = Promise.resolve(factory()); return promise.then(result => { if (shouldStop(result)) { return Promise.resolve(result); } return loop(); }); }; return loop(); } exports.first = first; function firstParallel(promiseList, shouldStop = t => !!t, defaultValue = null) { if (promiseList.length === 0) { return Promise.resolve(defaultValue); } let todo = promiseList.length; const finish = () => { var _a, _b; todo = -1; for (const promise of promiseList) { (_b = (_a = promise).cancel) === null || _b === void 0 ? void 0 : _b.call(_a); } }; return new Promise((resolve, reject) => { for (const promise of promiseList) { promise.then(result => { if (--todo >= 0 && shouldStop(result)) { finish(); resolve(result); } else if (todo === 0) { resolve(defaultValue); } }) .catch(err => { if (--todo >= 0) { finish(); reject(err); } }); } }); } exports.firstParallel = firstParallel; /** * A helper to queue N promises and run them all with a max degree of parallelism. The helper * ensures that at any time no more than M promises are running at the same time. */ class Limiter { constructor(maxDegreeOfParalellism) { this._size = 0; this.maxDegreeOfParalellism = maxDegreeOfParalellism; this.outstandingPromises = []; this.runningPromises = 0; this._onFinished = new event_1.Emitter(); } get onFinished() { return this._onFinished.event; } get size() { return this._size; } queue(factory) { this._size++; return new Promise((c, e) => { this.outstandingPromises.push({ factory, c, e }); this.consume(); }); } consume() { while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) { const iLimitedTask = this.outstandingPromises.shift(); this.runningPromises++; const promise = iLimitedTask.factory(); promise.then(iLimitedTask.c, iLimitedTask.e); promise.then(() => this.consumed(), () => this.consumed()); } } consumed() { this._size--; this.runningPromises--; if (this.outstandingPromises.length > 0) { this.consume(); } else { this._onFinished.fire(); } } dispose() { this._onFinished.dispose(); } } exports.Limiter = Limiter; /** * A queue is handles one promise at a time and guarantees that at any time only one promise is executing. */ class Queue extends Limiter { constructor() { super(1); } } exports.Queue = Queue; /** * A helper to organize queues per resource. The ResourceQueue makes sure to manage queues per resource * by disposing them once the queue is empty. */ class ResourceQueue { constructor() { this.queues = new Map(); this.drainers = new Set(); } whenDrained() { return __awaiter(this, void 0, void 0, function* () { if (this.isDrained()) { return; } const promise = new DeferredPromise(); this.drainers.add(promise); return promise.p; }); } isDrained() { for (const [, queue] of this.queues) { if (queue.size > 0) { return false; } } return true; } queueFor(resource, extUri = resources_1.extUri) { const key = extUri.getComparisonKey(resource); let queue = this.queues.get(key); if (!queue) { queue = new Queue(); event_1.Event.once(queue.onFinished)(() => { queue === null || queue === void 0 ? void 0 : queue.dispose(); this.queues.delete(key); this.onDidQueueFinish(); }); this.queues.set(key, queue); } return queue; } onDidQueueFinish() { if (!this.isDrained()) { return; // not done yet } this.releaseDrainers(); } releaseDrainers() { for (const drainer of this.drainers) { drainer.complete(); } this.drainers.clear(); } dispose() { for (const [, queue] of this.queues) { queue.dispose(); } this.queues.clear(); // Even though we might still have pending // tasks queued, after the queues have been // disposed, we can no longer track them, so // we release drainers to prevent hanging // promises when the resource queue is being // disposed. this.releaseDrainers(); } } exports.ResourceQueue = ResourceQueue; class TimeoutTimer { constructor(runner, timeout) { this._token = -1; if (typeof runner === 'function' && typeof timeout === 'number') { this.setIfNotSet(runner, timeout); } } dispose() { this.cancel(); } cancel() { if (this._token !== -1) { clearTimeout(this._token); this._token = -1; } } cancelAndSet(runner, timeout) { this.cancel(); this._token = setTimeout(() => { this._token = -1; runner(); }, timeout); } setIfNotSet(runner, timeout) { if (this._token !== -1) { // timer is already set return; } this._token = setTimeout(() => { this._token = -1; runner(); }, timeout); } } exports.TimeoutTimer = TimeoutTimer; class IntervalTimer { constructor() { this._token = -1; } dispose() { this.cancel(); } cancel() { if (this._token !== -1) { clearInterval(this._token); this._token = -1; } } cancelAndSet(runner, interval) { this.cancel(); this._token = setInterval(() => { runner(); }, interval); } } exports.IntervalTimer = IntervalTimer; class RunOnceScheduler { constructor(runner, delay) { this.timeoutToken = -1; this.runner = runner; this.timeout = delay; this.timeoutHandler = this.onTimeout.bind(this); } /** * Dispose RunOnceScheduler */ dispose() { this.cancel(); this.runner = null; } /** * Cancel current scheduled runner (if any). */ cancel() { if (this.isScheduled()) { clearTimeout(this.timeoutToken); this.timeoutToken = -1; } } /** * Cancel previous runner (if any) & schedule a new runner. */ schedule(delay = this.timeout) { this.cancel(); this.timeoutToken = setTimeout(this.timeoutHandler, delay); } get delay() { return this.timeout; } set delay(value) { this.timeout = value; } /** * Returns true if scheduled. */ isScheduled() { return this.timeoutToken !== -1; } onTimeout() { this.timeoutToken = -1; if (this.runner) { this.doRun(); } } doRun() { if (this.runner) { this.runner(); } } } exports.RunOnceScheduler = RunOnceScheduler; class RunOnceWorker extends RunOnceScheduler { constructor(runner, timeout) { super(runner, timeout); this.units = []; } work(unit) { this.units.push(unit); if (!this.isScheduled()) { this.schedule(); } } doRun() { const units = this.units; this.units = []; if (this.runner) { this.runner(units); } } dispose() { this.units = []; super.dispose(); } } exports.RunOnceWorker = RunOnceWorker; /** * The `ThrottledWorker` will accept units of work `T` * to handle. The contract is: * * there is a maximum of units the worker can handle at once (via `chunkSize`) * * after having handled units, the worker needs to rest (via `throttleDelay`) */ class ThrottledWorker extends lifecycle_1.Disposable { constructor(maxWorkChunkSize, maxPendingWork, throttleDelay, handler) { super(); this.maxWorkChunkSize = maxWorkChunkSize; this.maxPendingWork = maxPendingWork; this.throttleDelay = throttleDelay; this.handler = handler; this.pendingWork = []; this.throttler = this._register(new lifecycle_1.MutableDisposable()); this.disposed = false; } /** * The number of work units that are pending to be processed. */ get pending() { return this.pendingWork.length; } /** * Add units to be worked on. Use `pending` to figure out * how many units are not yet processed after this method * was called. * * @returns whether the work was accepted or not. If the * worker is disposed, it will not accept any more work. * If the number of pending units would become larger * than `maxPendingWork`, more work will also not be accepted. */ work(units) { if (this.disposed) { return false; // work not accepted: disposed } // Check for reaching maximum of pending work if (typeof this.maxPendingWork === 'number') { // Throttled: simple check if pending + units exceeds max pending if (this.throttler.value) { if (this.pending + units.length > this.maxPendingWork) { return false; // work not accepted: too much pending work } } // Unthrottled: same as throttled, but account for max chunk getting // worked on directly without being pending else { if (this.pending + units.length - this.maxWorkChunkSize > this.maxPendingWork) { return false; // work not accepted: too much pending work } } } // Add to pending units first this.pendingWork.push(...units); // If not throttled, start working directly // Otherwise, when the throttle delay has // past, pending work will be worked again. if (!this.throttler.value) { this.doWork(); } return true; // work accepted } doWork() { // Extract chunk to handle and handle it this.handler(this.pendingWork.splice(0, this.maxWorkChunkSize)); // If we have remaining work, schedule it after a delay if (this.pendingWork.length > 0) { this.throttler.value = new RunOnceScheduler(() => { this.throttler.clear(); this.doWork(); }, this.throttleDelay); this.throttler.value.schedule(); } } dispose() { super.dispose(); this.disposed = true; } } exports.ThrottledWorker = ThrottledWorker; (function () { if (typeof requestIdleCallback !== 'function' || typeof cancelIdleCallback !== 'function') { exports.runWhenIdle = (runner) => { (0, platform_1.setTimeout0)(() => { if (disposed) { return; } const end = Date.now() + 15; // one frame at 64fps runner(Object.freeze({ didTimeout: true, timeRemaining() { return Math.max(0, end - Date.now()); } })); }); let disposed = false; return { dispose() { if (disposed) { return; } disposed = true; } }; }; } else { exports.runWhenIdle = (runner, timeout) => { const handle = requestIdleCallback(runner, typeof timeout === 'number' ? { timeout } : undefined); let disposed = false; return { dispose() { if (disposed) { return; } disposed = true; cancelIdleCallback(handle); } }; }; } })(); /** * An implementation of the "idle-until-urgent"-strategy as introduced * here: https://philipwalton.com/articles/idle-until-urgent/ */ class IdleValue { constructor(executor) { this._didRun = false; this._executor = () => { try { this._value = executor(); } catch (err) { this._error = err; } finally { this._didRun = true; } }; this._handle = (0, exports.runWhenIdle)(() => this._executor()); } dispose() { this._handle.dispose(); } get value() { if (!this._didRun) { this._handle.dispose(); this._executor(); } if (this._error) { throw this._error; } return this._value; } get isInitialized() { return this._didRun; } } exports.IdleValue = IdleValue; //#endregion function retry(task, delay, retries) { return __awaiter(this, void 0, void 0, function* () { let lastError; for (let i = 0; i < retries; i++) { try { return yield task(); } catch (error) { lastError = error; yield timeout(delay); } } throw lastError; }); } exports.retry = retry; class TaskSequentializer { hasPending(taskId) { if (!this._pending) { return false; } if (typeof taskId === 'number') { return this._pending.taskId === taskId; } return !!this._pending; } get pending() { return this._pending ? this._pending.promise : undefined; } cancelPending() { var _a; (_a = this._pending) === null || _a === void 0 ? void 0 : _a.cancel(); } setPending(taskId, promise, onCancel) { this._pending = { taskId, cancel: () => onCancel === null || onCancel === void 0 ? void 0 : onCancel(), promise }; promise.then(() => this.donePending(taskId), () => this.donePending(taskId)); return promise; } donePending(taskId) { if (this._pending && taskId === this._pending.taskId) { // only set pending to done if the promise finished that is associated with that taskId this._pending = undefined; // schedule the next task now that we are free if we have any this.triggerNext(); } } triggerNext() { if (this._next) { const next = this._next; this._next = undefined; // Run next task and complete on the associated promise next.run().then(next.promiseResolve, next.promiseReject); } } setNext(run) { // this is our first next task, so we create associated promise with it // so that we can return a promise that completes when the task has // completed. if (!this._next) { let promiseResolve; let promiseReject; const promise = new Promise((resolve, reject) => { promiseResolve = resolve; promiseReject = reject; }); this._next = { run, promise, promiseResolve: promiseResolve, promiseReject: promiseReject }; } // we have a previous next task, just overwrite it else { this._next.run = run; } return this._next.promise; } } exports.TaskSequentializer = TaskSequentializer; //#endregion //#region /** * The `IntervalCounter` allows to count the number * of calls to `increment()` over a duration of * `interval`. This utility can be used to conditionally * throttle a frequent task when a certain threshold * is reached. */ class IntervalCounter { constructor(interval, nowFn = () => Date.now()) { this.interval = interval; this.nowFn = nowFn; this.lastIncrementTime = 0; this.value = 0; } increment() { const now = this.nowFn(); // We are outside of the range of `interval` and as such // start counting from 0 and remember the time if (now - this.lastIncrementTime > this.interval) { this.lastIncrementTime = now; this.value = 0; } this.value++; return this.value; } } exports.IntervalCounter = IntervalCounter; /** * Creates a promise whose resolution or rejection can be controlled imperatively. */ class DeferredPromise { constructor() { this.rejected = false; this.resolved = false; this.p = new Promise((c, e) => { this.completeCallback = c; this.errorCallback = e; }); } get isRejected() { return this.rejected; } get isResolved() { return this.resolved; } get isSettled() { return this.rejected || this.resolved; } complete(value) { return new Promise(resolve => { this.completeCallback(value); this.resolved = true; resolve(); }); } error(err) { return new Promise(resolve => { this.errorCallback(err); this.rejected = true; resolve(); }); } cancel() { new Promise(resolve => { this.errorCallback((0, errors_1.canceled)()); this.rejected = true; resolve(); }); } } exports.DeferredPromise = DeferredPromise; //#endregion //#region Promises var Promises; (function (Promises) { /** * A drop-in replacement for `Promise.all` with the only difference * that the method awaits every promise to either fulfill or reject. * * Similar to `Promise.all`, only the first error will be returned * if any. */ function settled(promises) { return __awaiter(this, void 0, void 0, function* () { let firstError = undefined; const result = yield Promise.all(promises.map(promise => promise.then(value => value, error => { if (!firstError) { firstError = error; } return undefined; // do not rethrow so that other promises can settle }))); if (typeof firstError !== 'undefined') { throw firstError; } return result; // cast is needed and protected by the `throw` above }); } Promises.settled = settled; /** * A helper to create a new `Promise<T>` with a body that is a promise * itself. By default, an error that raises from the async body will * end up as a unhandled rejection, so this utility properly awaits the * body and rejects the promise as a normal promise does without async * body. * * This method should only be used in rare cases where otherwise `async` * cannot be used (e.g. when callbacks are involved that require this). */ function withAsyncBody(bodyFn) { // eslint-disable-next-line no-async-promise-executor return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { yield bodyFn(resolve, reject); } catch (error) { reject(error); } })); } Promises.withAsyncBody = withAsyncBody; })(Promises = exports.Promises || (exports.Promises = {})); //#endregion //#region var AsyncIterableSourceState; (function (AsyncIterableSourceState) { AsyncIterableSourceState[AsyncIterableSourceState["Initial"] = 0] = "Initial"; AsyncIterableSourceState[AsyncIterableSourceState["DoneOK"] = 1] = "DoneOK"; AsyncIterableSourceState[AsyncIterableSourceState["DoneError"] = 2] = "DoneError"; })(AsyncIterableSourceState || (AsyncIterableSourceState = {})); /** * A rich implementation for an `AsyncIterable<T>`. */ class AsyncIterableObject { constructor(executor) { this._state = 0 /* Initial */; this._results = []; this._error = null; this._onStateChanged = new event_1.Emitter(); queueMicrotask(() => __awaiter(this, void 0, void 0, function* () { const writer = { emitOne: (item) => this.emitOne(item), emitMany: (items) => this.emitMany(items), reject: (error) => this.reject(error) }; try { yield Promise.resolve(executor(writer)); this.resolve(); } catch (err) { this.reject(err); } finally { writer.emitOne = undefined; writer.emitMany = undefined; writer.reject = undefined; } })); } static fromArray(items) { return new AsyncIterableObject((writer) => { writer.emitMany(items); }); } static fromPromise(promise) { return new AsyncIterableObject((emitter) => __awaiter(this, void 0, void 0, function* () { emitter.emitMany(yield promise); })); } static fromPromises(promises) { return new AsyncIterableObject((emitter) => __awaiter(this, void 0, void 0, function* () { yield Promise.all(promises.map((p) => __awaiter(this, void 0, void 0, function* () { return emitter.emitOne(yield p); }))); })); } static merge(iterables) { return new AsyncIterableObject((emitter) => __awaiter(this, void 0, void 0, function* () { yield Promise.all(iterables.map((iterable) => { var iterable_1, iterable_1_1; return __awaiter(this, void 0, void 0, function* () { var e_1, _a; try { for (iterable_1 = __asyncValues(iterable); iterable_1_1 = yield iterable_1.next(), !iterable_1_1.done;) { const item = iterable_1_1.value; emitter.emitOne(item); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (iterable_1_1 && !iterable_1_1.done && (_a = iterable_1.return)) yield _a.call(iterable_1); } finally { if (e_1) throw e_1.error; } } }); })); })); } [Symbol.asyncIterator]() { let i = 0; return { next: () => __awaiter(this, void 0, void 0, function* () { do { if (this._state === 2 /* DoneError */) { throw this._error; } if (i < this._results.length) { return { done: false, value: this._results[i++] }; } if (this._state === 1 /* DoneOK */) { return { done: true, value: undefined }; } yield event_1.Event.toPromise(this._onStateChanged.event); } while (true); }) }; } static map(iterable, mapFn) { return new AsyncIterableObject((emitter) => __awaiter(this, void 0, void 0, function* () { var e_2, _a; try { for (var iterable_2 = __asyncValues(iterable), iterable_2_1; iterable_2_1 = yield iterable_2.next(), !iterable_2_1.done;) { const item = iterable_2_1.value; emitter.emitOne(mapFn(item)); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (iterable_2_1 && !iterable_2_1.done && (_a = iterable_2.return)) yield _a.call(iterable_2); } finally { if (e_2) throw e_2.error; } } })); } map(mapFn) { return AsyncIterableObject.map(this, mapFn); } static filter(iterable, filterFn) { return new AsyncIterableObject((emitter) => __awaiter(this, void 0, void 0, function* () { var e_3, _a; try { for (var iterable_3 = __asyncValues(iterable), iterable_3_1; iterable_3_1 = yield iterable_3.next(), !iterable_3_1.done;) { const item = iterable_3_1.value; if (filterFn(item)) { emitter.emitOne(item); } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (iterable_3_1 && !iterable_3_1.done && (_a = iterable_3.return)) yield _a.call(iterable_3); } finally { if (e_3) throw e_3.error; } } })); } filter(filterFn) { return AsyncIterableObject.filter(this, filterFn); } static coalesce(iterable) { return AsyncIterableObject.filter(iterable, item => !!item); } coalesce() { return AsyncIterableObject.coalesce(this); } static toPromise(iterable) { var iterable_4, iterable_4_1; var e_4, _a; return __awaiter(this, void 0, void 0, function* () { const result = []; try { for (iterable_4 = __asyncValues(iterable); iterable_4_1 = yield iterable_4.next(), !iterable_4_1.done;) { const item = iterable_4_1.value; result.push(item); } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (iterable_4_1 && !iterable_4_1.done && (_a = iterable_4.return)) yield _a.call(iterable_4); } finally { if (e_4) throw e_4.error; } } return result; }); } toPromise() { return AsyncIterableObject.toPromise(this); } /** * The value will be appended at the end. * * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect. */ emitOne(value) { if (this._state !== 0 /* Initial */) { return; } // it is important to add new values at the end, // as we may have iterators already running on the array this._results.push(value); this._onStateChanged.fire(); } /** * The values will be appended at the end. * * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect. */ emitMany(values) { if (this._state !== 0 /* Initial */) { return; } // it is important to add new values at the end, // as we may have iterators already running on the array this._results = this._results.concat(values); this._onStateChanged.fire(); } /** * Calling `resolve()` will mark the result array as complete. * * **NOTE** `resolve()` must be called, otherwise all consumers of this iterable will hang indefinitely, similar to a non-resolved promise. * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect. */ resolve() { if (this._state !== 0 /* Initial */) { return; } this._state = 1 /* DoneOK */; this._onStateChanged.fire(); } /** * Writing an error will permanently invalidate this iterable. * The current users will receive an error thrown, as will all future users. * * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect. */ reject(error) { if (this._state !== 0 /* Initial */) { return; } this._state = 2 /* DoneError */; this._error = error; this._onStateChanged.fire(); } } exports.AsyncIterableObject = AsyncIterableObject; AsyncIterableObject.EMPTY = AsyncIterableObject.fromArray([]); class CancelableAsyncIterableObject extends AsyncIterableObject { constructor(_source, executor) { super(executor); this._source = _source; } cancel() { this._source.cancel(); } } exports.CancelableAsyncIterableObject = CancelableAsyncIterableObject; function createCancelableAsyncIterable(callback) { const source = new cancellation_1.CancellationTokenSource(); const innerIterable = callback(source.token); return new CancelableAsyncIterableObject(source, (emitter) => __awaiter(this, void 0, void 0, function* () { var e_5, _a; const subscription = source.token.onCancellationRequested(() => { subscription.dispose(); source.dispose(); emitter.reject((0, errors_1.canceled)()); }); try { try { for (var innerIterable_1 = __asyncValues(innerIterable), innerIterable_1_1; innerIterable_1_1 = yield innerIterable_1.next(), !innerIterable_1_1.done;) { const item = innerIterable_1_1.value; if (source.token.isCancellationRequested) { // canceled in the meantime return; } emitter.emitOne(item); } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (innerIterable_1_1 && !innerIterable_1_1.done && (_a = innerIterable_1.return)) yield _a.call(innerIterable_1); } finally { if (e_5) throw e_5.error; } } subscription.dispose(); source.dispose(); } catch (err) { subscription.dispose(); source.dispose(); emitter.reject(err); } })); } exports.createCancelableAsyncIterable = createCancelableAsyncIterable; //#endregion //# sourceMappingURL=async.js.map