import {
objectOrFunction, isFunction
} from './utils';
import instrument from './instrument';
import { config } from './config';
function noop() {}
var PENDING = void 0; var FULFILLED = 1; var REJECTED = 2;
var GET_THEN_ERROR = new ErrorObject();
function getThen(promise) {
try { return promise.then; } catch(error) { GET_THEN_ERROR.error = error; return GET_THEN_ERROR; }
}
function tryThen(then, value, fulfillmentHandler, rejectionHandler) {
try { then.call(value, fulfillmentHandler, rejectionHandler); } catch(e) { return e; }
}
function handleForeignThenable(promise, thenable, then) {
config.async(function(promise) { var sealed = false; var error = tryThen(then, thenable, function(value) { if (sealed) { return; } sealed = true; if (thenable !== value) { resolve(promise, value); } else { fulfill(promise, value); } }, function(reason) { if (sealed) { return; } sealed = true; reject(promise, reason); }, 'Settle: ' + (promise._label || ' unknown promise')); if (!sealed && error) { sealed = true; reject(promise, error); } }, promise);
}
function handleOwnThenable(promise, thenable) {
if (thenable._state === FULFILLED) { fulfill(promise, thenable._result); } else if (promise._state === REJECTED) { reject(promise, thenable._result); } else { subscribe(thenable, undefined, function(value) { if (thenable !== value) { resolve(promise, value); } else { fulfill(promise, value); } }, function(reason) { reject(promise, reason); }); }
}
function handleMaybeThenable(promise, maybeThenable) {
if (maybeThenable.constructor === promise.constructor) { handleOwnThenable(promise, maybeThenable); } else { var then = getThen(maybeThenable); if (then === GET_THEN_ERROR) { reject(promise, GET_THEN_ERROR.error); } else if (then === undefined) { fulfill(promise, maybeThenable); } else if (isFunction(then)) { handleForeignThenable(promise, maybeThenable, then); } else { fulfill(promise, maybeThenable); } }
}
function resolve(promise, value) {
if (promise === value) { fulfill(promise, value); } else if (objectOrFunction(value)) { handleMaybeThenable(promise, value); } else { fulfill(promise, value); }
}
function publishRejection(promise) {
if (promise._onerror) { promise._onerror(promise._result); } publish(promise);
}
function fulfill(promise, value) {
if (promise._state !== PENDING) { return; } promise._result = value; promise._state = FULFILLED; if (promise._subscribers.length === 0) { if (config.instrument) { instrument('fulfilled', promise); } } else { config.async(publish, promise); }
}
function reject(promise, reason) {
if (promise._state !== PENDING) { return; } promise._state = REJECTED; promise._result = reason; config.async(publishRejection, promise);
}
function subscribe(parent, child, onFulfillment, onRejection) {
var subscribers = parent._subscribers; var length = subscribers.length; parent._onerror = null; subscribers[length] = child; subscribers[length + FULFILLED] = onFulfillment; subscribers[length + REJECTED] = onRejection; if (length === 0 && parent._state) { config.async(publish, parent); }
}
function publish(promise) {
var subscribers = promise._subscribers; var settled = promise._state; if (config.instrument) { instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); } if (subscribers.length === 0) { return; } var child, callback, detail = promise._result; for (var i = 0; i < subscribers.length; i += 3) { child = subscribers[i]; callback = subscribers[i + settled]; if (child) { invokeCallback(settled, child, callback, detail); } else { callback(detail); } } promise._subscribers.length = 0;
}
function ErrorObject() {
this.error = null;
}
var TRY_CATCH_ERROR = new ErrorObject();
function tryCatch(callback, detail) {
try { return callback(detail); } catch(e) { TRY_CATCH_ERROR.error = e; return TRY_CATCH_ERROR; }
}
function invokeCallback(settled, promise, callback, detail) {
var hasCallback = isFunction(callback), value, error, succeeded, failed; if (hasCallback) { value = tryCatch(callback, detail); if (value === TRY_CATCH_ERROR) { failed = true; error = value.error; value = null; } else { succeeded = true; } if (promise === value) { reject(promise, new TypeError('A promises callback cannot return that same promise.')); return; } } else { value = detail; succeeded = true; } if (promise._state !== PENDING) { // noop } else if (hasCallback && succeeded) { resolve(promise, value); } else if (failed) { reject(promise, error); } else if (settled === FULFILLED) { fulfill(promise, value); } else if (settled === REJECTED) { reject(promise, value); }
}
function initializePromise(promise, resolver) {
try { resolver(function resolvePromise(value){ resolve(promise, value); }, function rejectPromise(reason) { reject(promise, reason); }); } catch(e) { reject(promise, e); }
}
export {
noop, resolve, reject, fulfill, subscribe, publish, publishRejection, initializePromise, invokeCallback, FULFILLED, REJECTED, PENDING
};