This repository has been archived on 2025-03-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
boilerplate/node_modules/@wailsio/runtime/dist/cancellable.js
2025-03-07 07:16:20 -08:00

793 lines
34 KiB
JavaScript

/*
_ __ _ __
| | / /___ _(_) /____
| | /| / / __ `/ / / ___/
| |/ |/ / /_/ / / (__ )
|__/|__/\__,_/_/_/____/
The electron alternative for Go
(c) Lea Anthony 2019-present
*/
var _a;
import isCallable from "./callable.js";
/**
* Exception class that will be used as rejection reason
* in case a {@link CancellablePromise} is cancelled successfully.
*
* The value of the {@link name} property is the string `"CancelError"`.
* The value of the {@link cause} property is the cause passed to the cancel method, if any.
*/
export class CancelError extends Error {
/**
* Constructs a new `CancelError` instance.
* @param message - The error message.
* @param options - Options to be forwarded to the Error constructor.
*/
constructor(message, options) {
super(message, options);
this.name = "CancelError";
}
}
/**
* Exception class that will be reported as an unhandled rejection
* in case a {@link CancellablePromise} rejects after being cancelled,
* or when the `oncancelled` callback throws or rejects.
*
* The value of the {@link name} property is the string `"CancelledRejectionError"`.
* The value of the {@link cause} property is the reason the promise rejected with.
*
* Because the original promise was cancelled,
* a wrapper promise will be passed to the unhandled rejection listener instead.
* The {@link promise} property holds a reference to the original promise.
*/
export class CancelledRejectionError extends Error {
/**
* Constructs a new `CancelledRejectionError` instance.
* @param promise - The promise that caused the error originally.
* @param reason - The rejection reason.
* @param info - An optional informative message specifying the circumstances in which the error was thrown.
* Defaults to the string `"Unhandled rejection in cancelled promise."`.
*/
constructor(promise, reason, info) {
super((info !== null && info !== void 0 ? info : "Unhandled rejection in cancelled promise.") + " Reason: " + errorMessage(reason), { cause: reason });
this.promise = promise;
this.name = "CancelledRejectionError";
}
}
// Private field names.
const barrierSym = Symbol("barrier");
const cancelImplSym = Symbol("cancelImpl");
const species = (_a = Symbol.species) !== null && _a !== void 0 ? _a : Symbol("speciesPolyfill");
/**
* A promise with an attached method for cancelling long-running operations (see {@link CancellablePromise#cancel}).
* Cancellation can optionally be bound to an {@link AbortSignal}
* for better composability (see {@link CancellablePromise#cancelOn}).
*
* Cancelling a pending promise will result in an immediate rejection
* with an instance of {@link CancelError} as reason,
* but whoever started the promise will be responsible
* for actually aborting the underlying operation.
* To this purpose, the constructor and all chaining methods
* accept optional cancellation callbacks.
*
* If a `CancellablePromise` still resolves after having been cancelled,
* the result will be discarded. If it rejects, the reason
* will be reported as an unhandled rejection,
* wrapped in a {@link CancelledRejectionError} instance.
* To facilitate the handling of cancellation requests,
* cancelled `CancellablePromise`s will _not_ report unhandled `CancelError`s
* whose `cause` field is the same as the one with which the current promise was cancelled.
*
* All usual promise methods are defined and return a `CancellablePromise`
* whose cancel method will cancel the parent operation as well, propagating the cancellation reason
* upwards through promise chains.
* Conversely, cancelling a promise will not automatically cancel dependent promises downstream:
* ```ts
* let root = new CancellablePromise((resolve, reject) => { ... });
* let child1 = root.then(() => { ... });
* let child2 = child1.then(() => { ... });
* let child3 = root.catch(() => { ... });
* child1.cancel(); // Cancels child1 and root, but not child2 or child3
* ```
* Cancelling a promise that has already settled is safe and has no consequence.
*
* The `cancel` method returns a promise that _always fulfills_
* after the whole chain has processed the cancel request
* and all attached callbacks up to that moment have run.
*
* All ES2024 promise methods (static and instance) are defined on CancellablePromise,
* but actual availability may vary with OS/webview version.
*
* In line with the proposal at https://github.com/tc39/proposal-rm-builtin-subclassing,
* `CancellablePromise` does not support transparent subclassing.
* Extenders should take care to provide their own method implementations.
* This might be reconsidered in case the proposal is retired.
*
* CancellablePromise is a wrapper around the DOM Promise object
* and is compliant with the [Promises/A+ specification](https://promisesaplus.com/)
* (it passes the [compliance suite](https://github.com/promises-aplus/promises-tests))
* if so is the underlying implementation.
*/
export class CancellablePromise extends Promise {
/**
* Creates a new `CancellablePromise`.
*
* @param executor - A callback used to initialize the promise. This callback is passed two arguments:
* a `resolve` callback used to resolve the promise with a value
* or the result of another promise (possibly cancellable),
* and a `reject` callback used to reject the promise with a provided reason or error.
* If the value provided to the `resolve` callback is a thenable _and_ cancellable object
* (it has a `then` _and_ a `cancel` method),
* cancellation requests will be forwarded to that object and the oncancelled will not be invoked anymore.
* If any one of the two callbacks is called _after_ the promise has been cancelled,
* the provided values will be cancelled and resolved as usual,
* but their results will be discarded.
* However, if the resolution process ultimately ends up in a rejection
* that is not due to cancellation, the rejection reason
* will be wrapped in a {@link CancelledRejectionError}
* and bubbled up as an unhandled rejection.
* @param oncancelled - It is the caller's responsibility to ensure that any operation
* started by the executor is properly halted upon cancellation.
* This optional callback can be used to that purpose.
* It will be called _synchronously_ with a cancellation cause
* when cancellation is requested, _after_ the promise has already rejected
* with a {@link CancelError}, but _before_
* any {@link then}/{@link catch}/{@link finally} callback runs.
* If the callback returns a thenable, the promise returned from {@link cancel}
* will only fulfill after the former has settled.
* Unhandled exceptions or rejections from the callback will be wrapped
* in a {@link CancelledRejectionError} and bubbled up as unhandled rejections.
* If the `resolve` callback is called before cancellation with a cancellable promise,
* cancellation requests on this promise will be diverted to that promise,
* and the original `oncancelled` callback will be discarded.
*/
constructor(executor, oncancelled) {
let resolve;
let reject;
super((res, rej) => { resolve = res; reject = rej; });
if (this.constructor[species] !== Promise) {
throw new TypeError("CancellablePromise does not support transparent subclassing. Please refrain from overriding the [Symbol.species] static property.");
}
let promise = {
promise: this,
resolve,
reject,
get oncancelled() { return oncancelled !== null && oncancelled !== void 0 ? oncancelled : null; },
set oncancelled(cb) { oncancelled = cb !== null && cb !== void 0 ? cb : undefined; }
};
const state = {
get root() { return state; },
resolving: false,
settled: false
};
// Setup cancellation system.
void Object.defineProperties(this, {
[barrierSym]: {
configurable: false,
enumerable: false,
writable: true,
value: null
},
[cancelImplSym]: {
configurable: false,
enumerable: false,
writable: false,
value: cancellerFor(promise, state)
}
});
// Run the actual executor.
const rejector = rejectorFor(promise, state);
try {
executor(resolverFor(promise, state), rejector);
}
catch (err) {
if (state.resolving) {
console.log("Unhandled exception in CancellablePromise executor.", err);
}
else {
rejector(err);
}
}
}
/**
* Cancels immediately the execution of the operation associated with this promise.
* The promise rejects with a {@link CancelError} instance as reason,
* with the {@link CancelError#cause} property set to the given argument, if any.
*
* Has no effect if called after the promise has already settled;
* repeated calls in particular are safe, but only the first one
* will set the cancellation cause.
*
* The `CancelError` exception _need not_ be handled explicitly _on the promises that are being cancelled:_
* cancelling a promise with no attached rejection handler does not trigger an unhandled rejection event.
* Therefore, the following idioms are all equally correct:
* ```ts
* new CancellablePromise((resolve, reject) => { ... }).cancel();
* new CancellablePromise((resolve, reject) => { ... }).then(...).cancel();
* new CancellablePromise((resolve, reject) => { ... }).then(...).catch(...).cancel();
* ```
* Whenever some cancelled promise in a chain rejects with a `CancelError`
* with the same cancellation cause as itself, the error will be discarded silently.
* However, the `CancelError` _will still be delivered_ to all attached rejection handlers
* added by {@link then} and related methods:
* ```ts
* let cancellable = new CancellablePromise((resolve, reject) => { ... });
* cancellable.then(() => { ... }).catch(console.log);
* cancellable.cancel(); // A CancelError is printed to the console.
* ```
* If the `CancelError` is not handled downstream by the time it reaches
* a _non-cancelled_ promise, it _will_ trigger an unhandled rejection event,
* just like normal rejections would:
* ```ts
* let cancellable = new CancellablePromise((resolve, reject) => { ... });
* let chained = cancellable.then(() => { ... }).then(() => { ... }); // No catch...
* cancellable.cancel(); // Unhandled rejection event on chained!
* ```
* Therefore, it is important to either cancel whole promise chains from their tail,
* as shown in the correct idioms above, or take care of handling errors everywhere.
*
* @returns A cancellable promise that _fulfills_ after the cancel callback (if any)
* and all handlers attached up to the call to cancel have run.
* If the cancel callback returns a thenable, the promise returned by `cancel`
* will also wait for that thenable to settle.
* This enables callers to wait for the cancelled operation to terminate
* without being forced to handle potential errors at the call site.
* ```ts
* cancellable.cancel().then(() => {
* // Cleanup finished, it's safe to do something else.
* }, (err) => {
* // Unreachable: the promise returned from cancel will never reject.
* });
* ```
* Note that the returned promise will _not_ handle implicitly any rejection
* that might have occurred already in the cancelled chain.
* It will just track whether registered handlers have been executed or not.
* Therefore, unhandled rejections will never be silently handled by calling cancel.
*/
cancel(cause) {
return new CancellablePromise((resolve) => {
// INVARIANT: the result of this[cancelImplSym] and the barrier do not ever reject.
// Unfortunately macOS High Sierra does not support Promise.allSettled.
Promise.all([
this[cancelImplSym](new CancelError("Promise cancelled.", { cause })),
currentBarrier(this)
]).then(() => resolve(), () => resolve());
});
}
/**
* Binds promise cancellation to the abort event of the given {@link AbortSignal}.
* If the signal has already aborted, the promise will be cancelled immediately.
* When either condition is verified, the cancellation cause will be set
* to the signal's abort reason (see {@link AbortSignal#reason}).
*
* Has no effect if called (or if the signal aborts) _after_ the promise has already settled.
* Only the first signal to abort will set the cancellation cause.
*
* For more details about the cancellation process,
* see {@link cancel} and the `CancellablePromise` constructor.
*
* This method enables `await`ing cancellable promises without having
* to store them for future cancellation, e.g.:
* ```ts
* await longRunningOperation().cancelOn(signal);
* ```
* instead of:
* ```ts
* let promiseToBeCancelled = longRunningOperation();
* await promiseToBeCancelled;
* ```
*
* @returns This promise, for method chaining.
*/
cancelOn(signal) {
if (signal.aborted) {
void this.cancel(signal.reason);
}
else {
signal.addEventListener('abort', () => void this.cancel(signal.reason), { capture: true });
}
return this;
}
/**
* Attaches callbacks for the resolution and/or rejection of the `CancellablePromise`.
*
* The optional `oncancelled` argument will be invoked when the returned promise is cancelled,
* with the same semantics as the `oncancelled` argument of the constructor.
* When the parent promise rejects or is cancelled, the `onrejected` callback will run,
* _even after the returned promise has been cancelled:_
* in that case, should it reject or throw, the reason will be wrapped
* in a {@link CancelledRejectionError} and bubbled up as an unhandled rejection.
*
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A `CancellablePromise` for the completion of whichever callback is executed.
* The returned promise is hooked up to propagate cancellation requests up the chain, but not down:
*
* - if the parent promise is cancelled, the `onrejected` handler will be invoked with a `CancelError`
* and the returned promise _will resolve regularly_ with its result;
* - conversely, if the returned promise is cancelled, _the parent promise is cancelled too;_
* the `onrejected` handler will still be invoked with the parent's `CancelError`,
* but its result will be discarded
* and the returned promise will reject with a `CancelError` as well.
*
* The promise returned from {@link cancel} will fulfill only after all attached handlers
* up the entire promise chain have been run.
*
* If either callback returns a cancellable promise,
* cancellation requests will be diverted to it,
* and the specified `oncancelled` callback will be discarded.
*/
then(onfulfilled, onrejected, oncancelled) {
if (!(this instanceof CancellablePromise)) {
throw new TypeError("CancellablePromise.prototype.then called on an invalid object.");
}
// NOTE: TypeScript's built-in type for then is broken,
// as it allows specifying an arbitrary TResult1 != T even when onfulfilled is not a function.
// We cannot fix it if we want to CancellablePromise to implement PromiseLike<T>.
if (!isCallable(onfulfilled)) {
onfulfilled = identity;
}
if (!isCallable(onrejected)) {
onrejected = thrower;
}
if (onfulfilled === identity && onrejected == thrower) {
// Shortcut for trivial arguments.
return new CancellablePromise((resolve) => resolve(this));
}
const barrier = {};
this[barrierSym] = barrier;
return new CancellablePromise((resolve, reject) => {
void super.then((value) => {
var _a;
if (this[barrierSym] === barrier) {
this[barrierSym] = null;
}
(_a = barrier.resolve) === null || _a === void 0 ? void 0 : _a.call(barrier);
try {
resolve(onfulfilled(value));
}
catch (err) {
reject(err);
}
}, (reason) => {
var _a;
if (this[barrierSym] === barrier) {
this[barrierSym] = null;
}
(_a = barrier.resolve) === null || _a === void 0 ? void 0 : _a.call(barrier);
try {
resolve(onrejected(reason));
}
catch (err) {
reject(err);
}
});
}, async (cause) => {
//cancelled = true;
try {
return oncancelled === null || oncancelled === void 0 ? void 0 : oncancelled(cause);
}
finally {
await this.cancel(cause);
}
});
}
/**
* Attaches a callback for only the rejection of the Promise.
*
* The optional `oncancelled` argument will be invoked when the returned promise is cancelled,
* with the same semantics as the `oncancelled` argument of the constructor.
* When the parent promise rejects or is cancelled, the `onrejected` callback will run,
* _even after the returned promise has been cancelled:_
* in that case, should it reject or throw, the reason will be wrapped
* in a {@link CancelledRejectionError} and bubbled up as an unhandled rejection.
*
* It is equivalent to
* ```ts
* cancellablePromise.then(undefined, onrejected, oncancelled);
* ```
* and the same caveats apply.
*
* @returns A Promise for the completion of the callback.
* Cancellation requests on the returned promise
* will propagate up the chain to the parent promise,
* but not in the other direction.
*
* The promise returned from {@link cancel} will fulfill only after all attached handlers
* up the entire promise chain have been run.
*
* If `onrejected` returns a cancellable promise,
* cancellation requests will be diverted to it,
* and the specified `oncancelled` callback will be discarded.
* See {@link then} for more details.
*/
catch(onrejected, oncancelled) {
return this.then(undefined, onrejected, oncancelled);
}
/**
* Attaches a callback that is invoked when the CancellablePromise is settled (fulfilled or rejected). The
* resolved value cannot be accessed or modified from the callback.
* The returned promise will settle in the same state as the original one
* after the provided callback has completed execution,
* unless the callback throws or returns a rejecting promise,
* in which case the returned promise will reject as well.
*
* The optional `oncancelled` argument will be invoked when the returned promise is cancelled,
* with the same semantics as the `oncancelled` argument of the constructor.
* Once the parent promise settles, the `onfinally` callback will run,
* _even after the returned promise has been cancelled:_
* in that case, should it reject or throw, the reason will be wrapped
* in a {@link CancelledRejectionError} and bubbled up as an unhandled rejection.
*
* This method is implemented in terms of {@link then} and the same caveats apply.
* It is polyfilled, hence available in every OS/webview version.
*
* @returns A Promise for the completion of the callback.
* Cancellation requests on the returned promise
* will propagate up the chain to the parent promise,
* but not in the other direction.
*
* The promise returned from {@link cancel} will fulfill only after all attached handlers
* up the entire promise chain have been run.
*
* If `onfinally` returns a cancellable promise,
* cancellation requests will be diverted to it,
* and the specified `oncancelled` callback will be discarded.
* See {@link then} for more details.
*/
finally(onfinally, oncancelled) {
if (!(this instanceof CancellablePromise)) {
throw new TypeError("CancellablePromise.prototype.finally called on an invalid object.");
}
if (!isCallable(onfinally)) {
return this.then(onfinally, onfinally, oncancelled);
}
return this.then((value) => CancellablePromise.resolve(onfinally()).then(() => value), (reason) => CancellablePromise.resolve(onfinally()).then(() => { throw reason; }), oncancelled);
}
/**
* We use the `[Symbol.species]` static property, if available,
* to disable the built-in automatic subclassing features from {@link Promise}.
* It is critical for performance reasons that extenders do not override this.
* Once the proposal at https://github.com/tc39/proposal-rm-builtin-subclassing
* is either accepted or retired, this implementation will have to be revised accordingly.
*
* @ignore
* @internal
*/
static get [species]() {
return Promise;
}
static all(values) {
let collected = Array.from(values);
const promise = collected.length === 0
? CancellablePromise.resolve(collected)
: new CancellablePromise((resolve, reject) => {
void Promise.all(collected).then(resolve, reject);
}, (cause) => cancelAll(promise, collected, cause));
return promise;
}
static allSettled(values) {
let collected = Array.from(values);
const promise = collected.length === 0
? CancellablePromise.resolve(collected)
: new CancellablePromise((resolve, reject) => {
void Promise.allSettled(collected).then(resolve, reject);
}, (cause) => cancelAll(promise, collected, cause));
return promise;
}
static any(values) {
let collected = Array.from(values);
const promise = collected.length === 0
? CancellablePromise.resolve(collected)
: new CancellablePromise((resolve, reject) => {
void Promise.any(collected).then(resolve, reject);
}, (cause) => cancelAll(promise, collected, cause));
return promise;
}
static race(values) {
let collected = Array.from(values);
const promise = new CancellablePromise((resolve, reject) => {
void Promise.race(collected).then(resolve, reject);
}, (cause) => cancelAll(promise, collected, cause));
return promise;
}
/**
* Creates a new cancelled CancellablePromise for the provided cause.
*
* @group Static Methods
*/
static cancel(cause) {
const p = new CancellablePromise(() => { });
p.cancel(cause);
return p;
}
/**
* Creates a new CancellablePromise that cancels
* after the specified timeout, with the provided cause.
*
* If the {@link AbortSignal.timeout} factory method is available,
* it is used to base the timeout on _active_ time rather than _elapsed_ time.
* Otherwise, `timeout` falls back to {@link setTimeout}.
*
* @group Static Methods
*/
static timeout(milliseconds, cause) {
const promise = new CancellablePromise(() => { });
if (AbortSignal && typeof AbortSignal === 'function' && AbortSignal.timeout && typeof AbortSignal.timeout === 'function') {
AbortSignal.timeout(milliseconds).addEventListener('abort', () => void promise.cancel(cause));
}
else {
setTimeout(() => void promise.cancel(cause), milliseconds);
}
return promise;
}
static sleep(milliseconds, value) {
return new CancellablePromise((resolve) => {
setTimeout(() => resolve(value), milliseconds);
});
}
/**
* Creates a new rejected CancellablePromise for the provided reason.
*
* @group Static Methods
*/
static reject(reason) {
return new CancellablePromise((_, reject) => reject(reason));
}
static resolve(value) {
if (value instanceof CancellablePromise) {
// Optimise for cancellable promises.
return value;
}
return new CancellablePromise((resolve) => resolve(value));
}
/**
* Creates a new CancellablePromise and returns it in an object, along with its resolve and reject functions
* and a getter/setter for the cancellation callback.
*
* This method is polyfilled, hence available in every OS/webview version.
*
* @group Static Methods
*/
static withResolvers() {
let result = { oncancelled: null };
result.promise = new CancellablePromise((resolve, reject) => {
result.resolve = resolve;
result.reject = reject;
}, (cause) => { var _a; (_a = result.oncancelled) === null || _a === void 0 ? void 0 : _a.call(result, cause); });
return result;
}
}
/**
* Returns a callback that implements the cancellation algorithm for the given cancellable promise.
* The promise returned from the resulting function does not reject.
*/
function cancellerFor(promise, state) {
let cancellationPromise = undefined;
return (reason) => {
if (!state.settled) {
state.settled = true;
state.reason = reason;
promise.reject(reason);
// Attach an error handler that ignores this specific rejection reason and nothing else.
// In theory, a sane underlying implementation at this point
// should always reject with our cancellation reason,
// hence the handler will never throw.
void Promise.prototype.then.call(promise.promise, undefined, (err) => {
if (err !== reason) {
throw err;
}
});
}
// If reason is not set, the promise resolved regularly, hence we must not call oncancelled.
// If oncancelled is unset, no need to go any further.
if (!state.reason || !promise.oncancelled) {
return;
}
cancellationPromise = new Promise((resolve) => {
try {
resolve(promise.oncancelled(state.reason.cause));
}
catch (err) {
Promise.reject(new CancelledRejectionError(promise.promise, err, "Unhandled exception in oncancelled callback."));
}
}).catch((reason) => {
Promise.reject(new CancelledRejectionError(promise.promise, reason, "Unhandled rejection in oncancelled callback."));
});
// Unset oncancelled to prevent repeated calls.
promise.oncancelled = null;
return cancellationPromise;
};
}
/**
* Returns a callback that implements the resolution algorithm for the given cancellable promise.
*/
function resolverFor(promise, state) {
return (value) => {
if (state.resolving) {
return;
}
state.resolving = true;
if (value === promise.promise) {
if (state.settled) {
return;
}
state.settled = true;
promise.reject(new TypeError("A promise cannot be resolved with itself."));
return;
}
if (value != null && (typeof value === 'object' || typeof value === 'function')) {
let then;
try {
then = value.then;
}
catch (err) {
state.settled = true;
promise.reject(err);
return;
}
if (isCallable(then)) {
try {
let cancel = value.cancel;
if (isCallable(cancel)) {
const oncancelled = (cause) => {
Reflect.apply(cancel, value, [cause]);
};
if (state.reason) {
// If already cancelled, propagate cancellation.
// The promise returned from the canceller algorithm does not reject
// so it can be discarded safely.
void cancellerFor(Object.assign(Object.assign({}, promise), { oncancelled }), state)(state.reason);
}
else {
promise.oncancelled = oncancelled;
}
}
}
catch (_a) { }
const newState = {
root: state.root,
resolving: false,
get settled() { return this.root.settled; },
set settled(value) { this.root.settled = value; },
get reason() { return this.root.reason; }
};
const rejector = rejectorFor(promise, newState);
try {
Reflect.apply(then, value, [resolverFor(promise, newState), rejector]);
}
catch (err) {
rejector(err);
}
return; // IMPORTANT!
}
}
if (state.settled) {
return;
}
state.settled = true;
promise.resolve(value);
};
}
/**
* Returns a callback that implements the rejection algorithm for the given cancellable promise.
*/
function rejectorFor(promise, state) {
return (reason) => {
if (state.resolving) {
return;
}
state.resolving = true;
if (state.settled) {
try {
if (reason instanceof CancelError && state.reason instanceof CancelError && Object.is(reason.cause, state.reason.cause)) {
// Swallow late rejections that are CancelErrors whose cancellation cause is the same as ours.
return;
}
}
catch (_a) { }
void Promise.reject(new CancelledRejectionError(promise.promise, reason));
}
else {
state.settled = true;
promise.reject(reason);
}
};
}
/**
* Cancels all values in an array that look like cancellable thenables.
* Returns a promise that fulfills once all cancellation procedures for the given values have settled.
*/
function cancelAll(parent, values, cause) {
const results = [];
for (const value of values) {
let cancel;
try {
if (!isCallable(value.then)) {
continue;
}
cancel = value.cancel;
if (!isCallable(cancel)) {
continue;
}
}
catch (_a) {
continue;
}
let result;
try {
result = Reflect.apply(cancel, value, [cause]);
}
catch (err) {
Promise.reject(new CancelledRejectionError(parent, err, "Unhandled exception in cancel method."));
continue;
}
if (!result) {
continue;
}
results.push((result instanceof Promise ? result : Promise.resolve(result)).catch((reason) => {
Promise.reject(new CancelledRejectionError(parent, reason, "Unhandled rejection in cancel method."));
}));
}
return Promise.all(results);
}
/**
* Returns its argument.
*/
function identity(x) {
return x;
}
/**
* Throws its argument.
*/
function thrower(reason) {
throw reason;
}
/**
* Attempts various strategies to convert an error to a string.
*/
function errorMessage(err) {
try {
if (err instanceof Error || typeof err !== 'object' || err.toString !== Object.prototype.toString) {
return "" + err;
}
}
catch (_a) { }
try {
return JSON.stringify(err);
}
catch (_b) { }
try {
return Object.prototype.toString.call(err);
}
catch (_c) { }
return "<could not convert error to string>";
}
/**
* Gets the current barrier promise for the given cancellable promise. If necessary, initialises the barrier.
*/
function currentBarrier(promise) {
var _a;
let pwr = (_a = promise[barrierSym]) !== null && _a !== void 0 ? _a : {};
if (!('promise' in pwr)) {
Object.assign(pwr, promiseWithResolvers());
}
if (promise[barrierSym] == null) {
pwr.resolve();
promise[barrierSym] = pwr;
}
return pwr.promise;
}
// Polyfill Promise.withResolvers.
let promiseWithResolvers = Promise.withResolvers;
if (promiseWithResolvers && typeof promiseWithResolvers === 'function') {
promiseWithResolvers = promiseWithResolvers.bind(Promise);
}
else {
promiseWithResolvers = function () {
let resolve;
let reject;
const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
return { promise, resolve, reject };
};
}