import { getCurrentActionContext , getNextActionId , getParentActionContext , IMiddlewareEventType , runWithActionContext } from "./action" ; import { argsToArray , setImmediateWithFallback , fail } from "../utils" ; hidden export type FlowReturn < R > = R extends Promise < infer T > ? T : R ; returns export function flow < R , Args extends any [ ] > ( generator ) { return createFlowSpawner ( generator . name , generator ) as any ; } deprecated param val returns export function castFlowReturn < T > ( val ) { return val as any ; } experimental export function toGeneratorFunction < R , Args extends any [ ] > ( p ) { return function * ( ... args ) { return ( yield p ( ... args ) ) as R ; } ; } experimental export function * toGenerator < R > ( p ) { return ( yield p ) as R ; } internal hidden export function createFlowSpawner ( name , generator ) { const spawner = function flowSpawner ( this ) { const runId = getNextActionId ( ) ; const parentContext = getCurrentActionContext ( ) ! ; if ( ! parentContext ) { throw fail ( "a mst flow must always have a parent context" ) ; } const parentActionContext = getParentActionContext ( parentContext ) ; if ( ! parentActionContext ) { throw fail ( "a mst flow must always have a parent action context" ) ; } const contextBase = { name , id : runId , tree : parentContext . tree , context : parentContext . context , parentId : parentContext . id , allParentIds : [ ... parentContext . allParentIds , parentContext . id ] , rootId : parentContext . rootId , parentEvent : parentContext , parentActionEvent : parentActionContext } ; const args = arguments ; function wrap ( fn , type , arg ) { fn . $mst_middleware = ( spawner as any ) . $mst_middleware ; runWithActionContext ( { ... contextBase , type , args : [ arg ] } , fn ) ; } return new Promise ( function ( resolve , reject ) { let gen ; const init = function asyncActionInit ( ) { gen = generator . apply ( null , arguments ) ; onFulfilled ( undefined ) ; } ; ( init as any ) . $mst_middleware = ( spawner as any ) . $mst_middleware ; runWithActionContext ( { ... contextBase , type : "flow_spawn" , args : argsToArray ( args ) } , init ) ; function onFulfilled ( res ) { let ret ; try { wrap ( ( r ) => { ret = gen . next ( r ) ; } , "flow_resume" , res ) ; } catch ( e ) { setImmediateWithFallback ( ( ) => { wrap ( ( r ) => { reject ( e ) ; } , "flow_throw" , e ) ; } ) ; return ; } next ( ret ) ; return ; } function onRejected ( err ) { let ret ; try { wrap ( ( r ) => { ret = gen . throw ( r ) ; } , "flow_resume_error" , err ) ; } catch ( e ) { setImmediateWithFallback ( ( ) => { wrap ( ( r ) => { reject ( e ) ; } , "flow_throw" , e ) ; } ) ; return ; } next ( ret ) ; } function next ( ret ) { if ( ret . done ) { setImmediateWithFallback ( ( ) => { wrap ( ( r ) => { resolve ( r ) ; } , "flow_return" , ret . value ) ; } ) ; return ; } if ( ! ret . value || typeof ret . value . then !== "function" ) { throw fail ( "Only promises can be yielded to `async`, got: " + ret ) ; } return ret . value . then ( onFulfilled , onRejected ) ; } } ) ; } ; return spawner ; }