travel/admin/node_modules/synchronous-promise/index.js

474 lines
11 KiB
JavaScript

/* jshint node: true */
"use strict";
function makeArrayFrom(obj) {
return Array.prototype.slice.apply(obj);
}
var
PENDING = "pending",
RESOLVED = "resolved",
REJECTED = "rejected";
function SynchronousPromise(handler) {
this.status = PENDING;
this._continuations = [];
this._parent = null;
this._paused = false;
if (handler) {
handler.call(
this,
this._continueWith.bind(this),
this._failWith.bind(this)
);
}
}
function looksLikeAPromise(obj) {
return obj && typeof (obj.then) === "function";
}
function passThrough(value) {
return value;
}
SynchronousPromise.prototype = {
then: function (nextFn, catchFn) {
var next = SynchronousPromise.unresolved()._setParent(this);
if (this._isRejected()) {
if (this._paused) {
this._continuations.push({
promise: next,
nextFn: nextFn,
catchFn: catchFn
});
return next;
}
if (catchFn) {
try {
var catchResult = catchFn(this._error);
if (looksLikeAPromise(catchResult)) {
this._chainPromiseData(catchResult, next);
return next;
} else {
return SynchronousPromise.resolve(catchResult)._setParent(this);
}
} catch (e) {
return SynchronousPromise.reject(e)._setParent(this);
}
}
return SynchronousPromise.reject(this._error)._setParent(this);
}
this._continuations.push({
promise: next,
nextFn: nextFn,
catchFn: catchFn
});
this._runResolutions();
return next;
},
catch: function (handler) {
if (this._isResolved()) {
return SynchronousPromise.resolve(this._data)._setParent(this);
}
var next = SynchronousPromise.unresolved()._setParent(this);
this._continuations.push({
promise: next,
catchFn: handler
});
this._runRejections();
return next;
},
finally: function (callback) {
var ran = false;
function runFinally(result, err) {
if (!ran) {
ran = true;
if (!callback) {
callback = passThrough;
}
var callbackResult = callback(result);
if (looksLikeAPromise(callbackResult)) {
return callbackResult.then(function () {
if (err) {
throw err;
}
return result;
});
} else {
return result;
}
}
}
return this
.then(function (result) {
return runFinally(result);
})
.catch(function (err) {
return runFinally(null, err);
});
},
pause: function () {
this._paused = true;
return this;
},
resume: function () {
var firstPaused = this._findFirstPaused();
if (firstPaused) {
firstPaused._paused = false;
firstPaused._runResolutions();
firstPaused._runRejections();
}
return this;
},
_findAncestry: function () {
return this._continuations.reduce(function (acc, cur) {
if (cur.promise) {
var node = {
promise: cur.promise,
children: cur.promise._findAncestry()
};
acc.push(node);
}
return acc;
}, []);
},
_setParent: function (parent) {
if (this._parent) {
throw new Error("parent already set");
}
this._parent = parent;
return this;
},
_continueWith: function (data) {
var firstPending = this._findFirstPending();
if (firstPending) {
firstPending._data = data;
firstPending._setResolved();
}
},
_findFirstPending: function () {
return this._findFirstAncestor(function (test) {
return test._isPending && test._isPending();
});
},
_findFirstPaused: function () {
return this._findFirstAncestor(function (test) {
return test._paused;
});
},
_findFirstAncestor: function (matching) {
var test = this;
var result;
while (test) {
if (matching(test)) {
result = test;
}
test = test._parent;
}
return result;
},
_failWith: function (error) {
var firstRejected = this._findFirstPending();
if (firstRejected) {
firstRejected._error = error;
firstRejected._setRejected();
}
},
_takeContinuations: function () {
return this._continuations.splice(0, this._continuations.length);
},
_runRejections: function () {
if (this._paused || !this._isRejected()) {
return;
}
var
error = this._error,
continuations = this._takeContinuations(),
self = this;
continuations.forEach(function (cont) {
if (cont.catchFn) {
try {
var catchResult = cont.catchFn(error);
self._handleUserFunctionResult(catchResult, cont.promise);
} catch (e) {
cont.promise.reject(e);
}
} else {
cont.promise.reject(error);
}
});
},
_runResolutions: function () {
if (this._paused || !this._isResolved() || this._isPending()) {
return;
}
var continuations = this._takeContinuations();
var data = this._data;
var self = this;
continuations.forEach(function (cont) {
if (cont.nextFn) {
try {
var result = cont.nextFn(data);
self._handleUserFunctionResult(result, cont.promise);
} catch (e) {
self._handleResolutionError(e, cont);
}
} else if (cont.promise) {
cont.promise.resolve(data);
}
});
if (looksLikeAPromise(this._data)) {
return this._handleWhenResolvedDataIsPromise(this._data);
}
},
_handleResolutionError: function (e, continuation) {
this._setRejected();
if (continuation.catchFn) {
try {
continuation.catchFn(e);
return;
} catch (e2) {
e = e2;
}
}
if (continuation.promise) {
continuation.promise.reject(e);
}
},
_handleWhenResolvedDataIsPromise: function (data) {
var self = this;
return data.then(function (result) {
self._data = result;
self._runResolutions();
}).catch(function (error) {
self._error = error;
self._setRejected();
self._runRejections();
});
},
_handleUserFunctionResult: function (data, nextSynchronousPromise) {
if (looksLikeAPromise(data)) {
this._chainPromiseData(data, nextSynchronousPromise);
} else {
nextSynchronousPromise.resolve(data);
}
},
_chainPromiseData: function (promiseData, nextSynchronousPromise) {
promiseData.then(function (newData) {
nextSynchronousPromise.resolve(newData);
}).catch(function (newError) {
nextSynchronousPromise.reject(newError);
});
},
_setResolved: function () {
this.status = RESOLVED;
if (!this._paused) {
this._runResolutions();
}
},
_setRejected: function () {
this.status = REJECTED;
if (!this._paused) {
this._runRejections();
}
},
_isPending: function () {
return this.status === PENDING;
},
_isResolved: function () {
return this.status === RESOLVED;
},
_isRejected: function () {
return this.status === REJECTED;
}
};
SynchronousPromise.resolve = function (result) {
return new SynchronousPromise(function (resolve, reject) {
if (looksLikeAPromise(result)) {
result.then(function (newResult) {
resolve(newResult);
}).catch(function (error) {
reject(error);
});
} else {
resolve(result);
}
});
};
SynchronousPromise.reject = function (result) {
return new SynchronousPromise(function (resolve, reject) {
reject(result);
});
};
SynchronousPromise.unresolved = function () {
return new SynchronousPromise(function (resolve, reject) {
this.resolve = resolve;
this.reject = reject;
});
};
SynchronousPromise.all = function () {
var args = makeArrayFrom(arguments);
if (Array.isArray(args[0])) {
args = args[0];
}
if (!args.length) {
return SynchronousPromise.resolve([]);
}
return new SynchronousPromise(function (resolve, reject) {
var
allData = [],
numResolved = 0,
doResolve = function () {
if (numResolved === args.length) {
resolve(allData);
}
},
rejected = false,
doReject = function (err) {
if (rejected) {
return;
}
rejected = true;
reject(err);
};
args.forEach(function (arg, idx) {
SynchronousPromise.resolve(arg).then(function (thisResult) {
allData[idx] = thisResult;
numResolved += 1;
doResolve();
}).catch(function (err) {
doReject(err);
});
});
});
};
function createAggregateErrorFrom(errors) {
/* jshint ignore:start */
if (typeof window !== "undefined" && "AggregateError" in window) {
return new window.AggregateError(errors);
}
/* jshint ignore:end */
return { errors: errors };
}
SynchronousPromise.any = function () {
var args = makeArrayFrom(arguments);
if (Array.isArray(args[0])) {
args = args[0];
}
if (!args.length) {
return SynchronousPromise.reject(createAggregateErrorFrom([]));
}
return new SynchronousPromise(function (resolve, reject) {
var
allErrors = [],
numRejected = 0,
doReject = function () {
if (numRejected === args.length) {
reject(createAggregateErrorFrom(allErrors));
}
},
resolved = false,
doResolve = function (result) {
if (resolved) {
return;
}
resolved = true;
resolve(result);
};
args.forEach(function (arg, idx) {
SynchronousPromise.resolve(arg).then(function (thisResult) {
doResolve(thisResult);
}).catch(function (err) {
allErrors[idx] = err;
numRejected += 1;
doReject();
});
});
});
};
SynchronousPromise.allSettled = function () {
var args = makeArrayFrom(arguments);
if (Array.isArray(args[0])) {
args = args[0];
}
if (!args.length) {
return SynchronousPromise.resolve([]);
}
return new SynchronousPromise(function (resolve) {
var
allData = [],
numSettled = 0,
doSettled = function () {
numSettled += 1;
if (numSettled === args.length) {
resolve(allData);
}
};
args.forEach(function (arg, idx) {
SynchronousPromise.resolve(arg).then(function (thisResult) {
allData[idx] = {
status: "fulfilled",
value: thisResult
};
doSettled();
}).catch(function (err) {
allData[idx] = {
status: "rejected",
reason: err
};
doSettled();
});
});
});
};
/* jshint ignore:start */
if (Promise === SynchronousPromise) {
throw new Error("Please use SynchronousPromise.installGlobally() to install globally");
}
var RealPromise = Promise;
SynchronousPromise.installGlobally = function (__awaiter) {
if (Promise === SynchronousPromise) {
return __awaiter;
}
var result = patchAwaiterIfRequired(__awaiter);
Promise = SynchronousPromise;
return result;
};
SynchronousPromise.uninstallGlobally = function () {
if (Promise === SynchronousPromise) {
Promise = RealPromise;
}
};
function patchAwaiterIfRequired(__awaiter) {
if (typeof (__awaiter) === "undefined" || __awaiter.__patched) {
return __awaiter;
}
var originalAwaiter = __awaiter;
__awaiter = function () {
var Promise = RealPromise;
originalAwaiter.apply(this, makeArrayFrom(arguments));
};
__awaiter.__patched = true;
return __awaiter;
}
/* jshint ignore:end */
module.exports = {
SynchronousPromise: SynchronousPromise
};