import { Applicative } from "@siteimprove/alfa-applicative" ; import { Array } from "@siteimprove/alfa-array" ; import { Callback } from "@siteimprove/alfa-callback" ; import { Continuation } from "@siteimprove/alfa-continuation" ; import { Functor } from "@siteimprove/alfa-functor" ; import { Iterable } from "@siteimprove/alfa-iterable" ; import { Mapper } from "@siteimprove/alfa-mapper" ; import { Monad } from "@siteimprove/alfa-monad" ; import { Thenable } from "@siteimprove/alfa-thenable" ; import { Thunk } from "@siteimprove/alfa-thunk" ; /**
 *  http public export abstract class Future < T > implements Functor < T > , Applicative < T > , Monad < T > , Thenable < T > , AsyncIterable < T > { protected abstract step ( ) ; public then ( callback ) { let step = this ; while ( true ) { const next = step . step ( ) ; if ( step !== next ) { step = next ; } else { return next . then ( callback ) ; } } } public get ( ) { let step = this ; while ( true ) { const next = step . step ( ) ; if ( step !== next ) { step = next ; } else { return next . get ( ) ; } } } public abstract isNow ( ) ; public abstract isDeferred ( ) ; public abstract isSuspended ( ) ; public map < U > ( mapper ) { return this . flatMap ( ( value ) => Now . of ( mapper ( value ) ) ) ; } public apply < U > ( mapper ) { return mapper . flatMap ( ( mapper ) => this . map ( mapper ) ) ; } public abstract flatMap < U > ( mapper ) ; public flatten < T > ( this ) { return this . flatMap ( ( future ) => future ) ; } public tee ( callback ) { return this . map ( ( value ) => { callback ( value ) ; return value ; } ) ; } public async * asyncIterator ( ) { yield this . toPromise ( ) ; } public [ Symbol . asyncIterator ] ( ) { return this . asyncIterator ( ) ; } public toPromise ( ) { return new Promise ( ( resolve ) => this . then ( resolve ) ) ; } } public export namespace Future { export type Maybe < T > = T | Future < T > ; export function isFuture < T > ( value ) ; export function isFuture < T > ( value ) ; export function isFuture < T > ( value ) { return value instanceof Future ; } export function empty ( ) { return now ( undefined ) ; } export function now < T > ( value ) { return Now . of ( value ) ; } export function defer < T > ( continuation ) { return Defer . of ( continuation ) ; } export function suspend < T > ( thunk ) { return Suspend . of ( thunk ) ; } export function delay < T > ( thunk ) { return suspend ( ( ) => now ( thunk ( ) ) ) ; } export function from < T > ( promise ) { return Future . defer ( ( callback ) => ( typeof promise === "function" ? promise ( ) : promise ) . then ( callback ) ) ; } export function traverse < T , U > ( values , mapper ) { return Iterable . reduce ( values , ( values , value , i ) => values . flatMap ( ( values ) => mapper ( value , i ) . map ( ( value ) => Array . append ( values , value ) ) ) , now ( Array . empty ( ) ) ) ; } export function sequence < T > ( futures ) { return traverse ( futures , ( value ) => value ) ; } } class Now < T > extends Future < T > { public static of < T > ( value ) { return new Now ( value ) ; } private readonly _value : T ; private constructor ( value ) { super ( ) ; this . _value = value ; } protected step ( ) { return this ; } public then ( callback ) { callback ( this . _value ) ; } public get ( ) { return this . _value ; } public isNow ( ) { return true ; } public isDeferred ( ) { return false ; } public isSuspended ( ) { return false ; } public map < U > ( mapper ) { return new Now ( mapper ( this . _value ) ) ; } public flatMap < U > ( mapper ) { return Suspend . of ( ( ) => mapper ( this . _value ) ) ; } } class Defer < T > extends Future < T > { public static of < T > ( continuation ) { return new Defer ( continuation ) ; } private readonly _continuation : Continuation < T > ; private constructor ( continuation ) { super ( ) ; this . _continuation = continuation ; } protected step ( ) { return this ; } public then ( callback ) { this . _continuation ( ( value ) => defer ( ( ) => callback ( value ) ) ) ; } public get ( ) { throw new Error ( "Attempted to .get() from deferred future" ) ; } public isNow ( ) { return false ; } public isDeferred ( ) { return true ; } public isSuspended ( ) { return false ; } public flatMap < U > ( mapper ) { return Defer . Bind . of ( this . _continuation , mapper ) ; } } namespace Defer { export class Bind < S , T > extends Future < T > { public static of < S , T > ( continuation , mapper ) { return new Bind ( continuation , mapper ) ; } private readonly _continuation : Continuation < S > ; private readonly _mapper : Mapper < S , Future < T > > ; private constructor ( continuation , mapper ) { super ( ) ; this . _continuation = continuation ; this . _mapper = mapper ; } protected step ( ) { return this ; } public then ( callback ) { this . _continuation ( ( value ) => defer ( ( ) => this . _mapper ( value ) . then ( callback ) ) ) ; } public get ( ) { throw new Error ( "Attempted to .get() from deferred future" ) ; } public isNow ( ) { return false ; } public isDeferred ( ) { return true ; } public isSuspended ( ) { return false ; } public flatMap < U > ( mapper ) { return Suspend . of ( ( ) => Bind . of ( this . _continuation , ( value ) => this . _mapper ( value ) . flatMap ( mapper ) ) ) ; } } } class Suspend < T > extends Future < T > { public static of < T > ( thunk ) { return new Suspend ( thunk ) ; } private readonly _thunk : Thunk < Future < T > > ; private constructor ( thunk ) { super ( ) ; this . _thunk = thunk ; } protected step ( ) { return this . _thunk ( ) ; } public isNow ( ) { return false ; } public isDeferred ( ) { return false ; } public isSuspended ( ) { return true ; } public flatMap < U > ( mapper ) { return Suspend . Bind . of ( this . _thunk , mapper ) ; } } namespace Suspend { export class Bind < S , T > extends Future < T > { public static of < S , T > ( thunk , mapper ) { return new Bind ( thunk , mapper ) ; } private readonly _thunk : Thunk < Future < S > > ; private readonly _mapper : Mapper < S , Future < T > > ; private constructor ( thunk , mapper ) { super ( ) ; this . _thunk = thunk ; this . _mapper = mapper ; } protected step ( ) { return this . _thunk ( ) . flatMap ( this . _mapper ) ; } public isNow ( ) { return false ; } public isDeferred ( ) { return false ; } public isSuspended ( ) { return true ; } public flatMap < U > ( mapper ) { return Suspend . of ( ( ) => Bind . of ( this . _thunk , ( value ) => this . _mapper ( value ) . flatMap ( mapper ) ) ) ; } } } async function defer < T > ( thunk ) { return Promise . resolve ( ) . then ( thunk ) ; }