export type PromiseMaker = ( ) => Promise < any > ; class Task { dependencies : Task [ ] ; promiseMaker : PromiseMaker ; constructor ( dependencies , promiseMaker ) { this . dependencies = dependencies ; this . promiseMaker = promiseMaker ; } } class TaskInstance { task : Task ; promise : Promise < any > ; constructor ( task ) { this . task = task ; this . promise = null ; } makePromise ( ) { if ( this . promise ) { return this . promise ; } return this . promise = this . task . promiseMaker ( ) ; } } class GulpySession { private gulpy : Gulpy ; private tasks : Map < Task , TaskInstance > = new Map ( ) ; constructor ( gulpy ) { this . gulpy = gulpy ; } ensureInstance ( task ) { let instance = this . tasks . get ( task ) ; if ( instance ) { return instance ; } instance = new TaskInstance ( task ) ; this . tasks . set ( task , instance ) ; return instance ; } async runInstance ( instance ) { const dependencies = instance . task . dependencies . map ( x => this . ensureInstance ( x ) ) ; await Promise . all ( dependencies . map ( x => this . runInstance ( x ) ) ) ; return instance . makePromise ( ) ; } async run ( task ) { return this . runInstance ( this . ensureInstance ( task ) ) ; } } export class Gulpy { private tasks : { [ name ] : Task ; } = { } ; private session : GulpySession ; task ( name , fn ) ; task ( name , dependencies , fn ? ) ; task ( name , a , b ? ) { let dependencies = [ ] ; let fn = null ; if ( arguments . length === 3 ) { dependencies = a as string [ ] ; fn = b ; } else if ( arguments . length === 2 ) { if ( Array . isArray ( a ) ) { dependencies = a as string [ ] ; fn = b || ( ( ) => { } ) as PromiseMaker ; } else { fn = a as PromiseMaker ; } } this . tasks [ name ] = new Task ( dependencies . map ( x => this . tasks [ x ] ) , fn ) ; } series ( tasks ) { return null ; } parallel ( tasks ) { return null ; } hasTask ( name ) { return name in this . tasks ; } async run ( name ) { const session = new GulpySession ( this ) ; await session . run ( this . tasks [ name ] ) ; } }