import nextTick = require ( './nextTick' ) ; type Callback = ( ... args : any [ ] ) => void ; function isPromise ( value ) { return value && typeof value . then === 'function' ; } function runCallbacks ( callbacks , ... args ) { for ( var i = 0 , callback ; callback = callbacks [ i ] ; ++ i ) { callback . apply ( null , args ) ; } } /**
 * A Promise represents the result of an asynchronous operation. When writing a function that performs an asynchronous
 * operation, instead of writing the function to accept a callback function, you should instead write it to return a
 * Promise that is fulfilled once the asynchronous operation is completed. Returning a promise instead of accepting
 * a callback provides a standard mechanism for handling asynchronous operations that offers the following benefits
 * over a normal callback function:
 *
 * 1. Multiple callbacks can be added for a single function invocation;
 * 2. Other asynchronous operations can be easily chained to the response, avoiding callback pyramids;
 * 3. Asynchronous operations can be canceled in flight in a standard way if their results are no longer needed by the
 *    rest of the application.
 *
 * The Promise class is a modified, extended version of standard EcmaScript 6 promises. This implementation
 * intentionally deviates from the ES6 2014-05-22 draft in the following ways:
 *
 * 1. `Promise.race` is a worthless API with one use case, so is not implemented.
 * 2. `Promise.all` accepts an object in addition to an array.
 * 3. Asynchronous operations can transmit partial progress information through a third `progress` method passed to the
 *    initializer. Progress listeners can be added by passing a third `onProgress` callback to `then`, or through the
 *    extra `progress` method exposed on promises.
 * 4. Promises can be canceled by calling the `cancel` method of a promise.
 */ class Promise < T > { example example static all < T > ( iterable ) ; static all < T > ( iterable ) ; static all ( iterable ) { return new this ( function ( resolve , reject , progress , setCanceler ) { setCanceler ( function ( reason ) { walkIterable ( function ( key , value ) { if ( value && value . cancel ) { value . cancel ( reason ) ; } } ) ; throw reason ; } ) ; function fulfill ( key , value ) { values [ key ] = value ; progress ( values ) ; ++ complete ; finish ( ) ; } function finish ( ) { if ( populating || complete < total ) { return ; } resolve ( values ) ; } function processItem ( key , value ) { ++ total ; if ( isPromise ( value ) ) { value . then ( fulfill . bind ( null , key ) , reject ) ; } else { fulfill ( key , value ) ; } } function walkIterable ( callback ) { if ( Array . isArray ( iterable ) ) { for ( var i = 0 , j = iterable . length ; i < j ; ++ i ) { if ( i in iterable ) { callback ( String ( i ) , iterable [ i ] ) ; } } } else { for ( var key in iterable ) { callback ( key , iterable [ key ] ) ; } } } var values = Array . isArray ( iterable ) ? [ ] : { } ; var complete = 0 ; var total = 0 ; var populating = true ; walkIterable ( processItem ) ; populating = false ; finish ( ) ; } ) ; } /**
     * Creates a new promise that is pre-rejected with the given error.
     */ static reject ( error ? ) { return new this < any > ( function ( resolve , reject ) { reject ( error ) ; } ) ; } /**
     * Creates a new promise that is pre-resolved with the given value. If the passed value is already a promise, it
     * will be returned as-is.
     */ static resolve < T > ( value ? ) { if ( value instanceof Promise ) { return value ; } return new this < T > ( function ( resolve ) { resolve ( value ) ; } ) ; } constructor param initializer constructor ( initializer ) { /**
         * The current state of this promise.
         */ var state = Promise . State . PENDING ; Object . defineProperty ( this , 'state' , { get : function ( ) { return state ; } } ) ; /**
         * Whether or not this promise is in a resolved state.
         */ function isResolved ( ) { return state !== Promise . State . PENDING || isChained ; } /**
         * If true, the resolution of this promise is chained to another promise.
         */ var isChained = false ; /**
         * The resolved value for this promise.
         */ var resolvedValue ; /**
         * Callbacks that should be invoked once the asynchronous operation has completed.
         */ var callbacks = [ ] ; var whenFinished = function ( callback ) { callbacks . push ( callback ) ; } ; /**
         * Callbacks that should be invoked when the asynchronous operation has progressed.
         */ var progressCallbacks = [ ] ; var whenProgress = function ( callback ) { progressCallbacks . push ( callback ) ; } ; /**
         * A canceler function that will be used to cancel resolution of this promise.
         */ var canceler ; method param callback var enqueue = ( function ( ) { function originalSchedule ( ) { schedule = function ( ) { } ; nextTick ( function run ( ) { try { var callback ; while ( ( callback = queue . shift ( ) ) ) { callback ( ) ; } } finally { if ( queue . length ) { run ( ) ; } else { schedule = originalSchedule ; } } } ) ; } var queue = [ ] ; var schedule = originalSchedule ; return function ( callback ) { queue . push ( callback ) ; schedule ( ) ; } ; } ) ( ) ; param newState param { T | Error } value var resolve = function ( newState , value ) { if ( isResolved ( ) ) { return ; } if ( isPromise ( value ) ) { if ( value === this ) { settle ( Promise . State . REJECTED , new TypeError ( 'Cannot chain a promise to itself' ) ) ; return ; } try { value . then ( settle . bind ( null , Promise . State . FULFILLED ) , settle . bind ( null , Promise . State . REJECTED ) ) ; isChained = true ; canceler = value . cancel ; } catch ( error ) { settle ( Promise . State . REJECTED , error ) ; return ; } } else { settle ( newState , value ) ; } } . bind ( this ) ; param newState param { T | Error } value function settle ( newState , value ) { if ( state !== Promise . State . PENDING ) { return ; } state = newState ; resolvedValue = value ; whenFinished = enqueue ; whenProgress = function ( ) { } ; enqueue ( function ( ) { runCallbacks ( callbacks ) ; callbacks = progressCallbacks = null ; } ) ; } this . cancel = function ( reason ? ) { if ( state !== Promise . State . PENDING ) { return ; } if ( ! reason ) { reason = new Error ( 'Cancelled' ) ; reason . name = 'CancelError' ; } if ( ! canceler ) { settle ( Promise . State . REJECTED , reason ) ; return Promise . reject ( reason ) ; } try { resolve ( Promise . State . FULFILLED , canceler ( reason ) ) ; } catch ( error ) { settle ( Promise . State . REJECTED , error ) ; return Promise . reject ( error ) ; } } ; this . then = function < U > ( onFulfilled ? , onRejected ? , onProgress ? ) : Promise < U > { return new Promise < U > ( function ( resolve , reject , progress , setCanceler ) { setCanceler ( function ( reason ) { if ( canceler ) { resolve ( canceler ( reason ) ) ; } else { throw reason ; } } ) ; whenProgress ( function ( data ) { try { if ( typeof onProgress === 'function' ) { progress ( onProgress ( data ) ) ; } else { progress ( data ) ; } } catch ( error ) { if ( error . name !== 'StopProgressPropagation' ) { throw error ; } } } ) ; whenFinished ( function ( ) { var callback = state === Promise . State . REJECTED ? onRejected : onFulfilled ; if ( typeof callback === 'function' ) { try { resolve ( callback ( resolvedValue ) ) ; } catch ( error ) { reject ( error ) ; } } else if ( state === Promise . State . REJECTED ) { reject ( < Error > resolvedValue ) ; } else { resolve ( < any > resolvedValue ) ; } } ) ; } ) ; } ; try { initializer ( resolve . bind ( null , Promise . State . FULFILLED ) , resolve . bind ( null , Promise . State . REJECTED ) , function ( data ) { if ( state === Promise . State . PENDING ) { enqueue ( runCallbacks . bind ( null , progressCallbacks , data ) ) ; } } , function ( value ) { if ( ! isResolved ( ) ) { canceler = value ; } } ) ; } catch ( error ) { settle ( Promise . State . REJECTED , error ) ; } } readonly state : Promise . State ; method param reason cancel : ( reason ? : Error , source ? : Promise < any > ) => void ; /**
     * Adds a callback to the promise to be invoked when the asynchronous operation throws an error.
     */ catch < U > ( onRejected ) { return this . then < U > ( null , onRejected ) ; } /**
     * Adds a callback to the promise to be invoked regardless of whether or not the asynchronous operation completed
     * successfully. The callback can throw or return a new value to replace the original value, or if it returns
     * undefined, the original value or error will be passed through.
     */ finally < U > ( onFulfilledOrRejected ) { function getFinalValue ( defaultCallback ) { var returnValue = onFulfilledOrRejected ( ) ; if ( returnValue === undefined ) { return defaultCallback ( ) ; } else if ( returnValue && ( < Promise . Thenable < U > > returnValue ) . then ) { return ( < Promise . Thenable < U > > returnValue ) . then ( function ( returnValue ) { return returnValue !== undefined ? returnValue : defaultCallback ( ) ; } ) ; } else { return returnValue ; } } return this . then < U > ( function ( value ) { return getFinalValue ( function ( ) : any { return value ; } ) ; } , function ( error ) { return getFinalValue ( function ( ) : any { throw error ; } ) ; } ) ; } /**
     * Adds a callback to the promise to be invoked when progress occurs within the asynchronous operation.
     */ progress ( onProgress ) { return this . then < T > ( null , null , onProgress ) ; } /**
     * Adds a callback to the promise to be invoked when the asynchronous operation completes successfully.
     */ then : < U > ( onFulfilled ? : ( value ? : T ) => Promise . Thenable < U > | U , onRejected ? : ( error ? : Error ) => Promise . Thenable < U > | U , onProgress ? : ( data ? : any ) => any ) => Promise < U > ; } module Promise { export interface Canceler { ( reason ) : any ; } /**
     * The Deferred class unwraps a promise in order to expose its internal state management functions.
     */ export class Deferred < T > { /**
         * The underlying promise for the Deferred.
         */ promise : Promise < T > ; constructor ( canceler ? ) { this . promise = new Promise < T > ( ( resolve , reject , progress , setCanceler ) => { this . progress = progress ; this . reject = reject ; this . resolve = resolve ; canceler && setCanceler ( canceler ) ; } ) ; } method param data progress : ( data ? : any ) => void ; method param error reject : ( error ? : Error ) => void ; method param value resolve : ( value ? : Promise . Thenable < T > | T ) => void ; } /**
     * The State enum represents the possible states of a promise.
     */ export enum State { PENDING , FULFILLED , REJECTED } export interface Thenable < T > { then < U > ( onFulfilled ? , onRejected ? ) : Promise . Thenable < U > ; } } export = Promise ;