@@ -51,8 +51,9 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
5151 private eventForParallelExecution ?: Event ;
5252 private currentStateName : Maybe < string > ;
5353 private currentState : Maybe < State > ;
54- private contextObject : Maybe < ContextObject > ;
55- private subContextObject : Maybe < ContextObject > ;
54+ private contexts : {
55+ [ key : string ] : Maybe < ContextObject > ;
56+ } ;
5657 private subStates : StateMachine [ 'States' ] = { } ;
5758 private states : StateMachine [ 'States' ] = { } ;
5859 private parallelBranch : Maybe < Branch > ;
@@ -76,6 +77,7 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
7677 this . functions = this . serverless . service . functions ;
7778 this . variables = this . serverless . service . custom ?. stepFunctionsOffline ;
7879 this . cliLog = this . serverless . cli . log . bind ( this . serverless . cli ) ;
80+ this . contexts = { } ;
7981 this . commands = {
8082 'step-functions-offline' : {
8183 usage : 'Will run your step function locally' ,
@@ -286,36 +288,26 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
286288 if ( ! this . stateDefinition ?. StartAt ) {
287289 throw new Error ( 'Missing `startAt` in definition' ) ;
288290 }
289- this . contextObject = this . createContextObject (
290- this . stateDefinition . States ,
291- this . stateDefinition . StartAt ,
292- event ,
293- false
294- ) ;
291+ this . addContextObject ( this . stateDefinition . States , this . stateDefinition . StartAt , event ) ;
295292 this . states = this . stateDefinition . States ;
296- return this . process ( this . states [ this . stateDefinition . StartAt ] , this . stateDefinition . StartAt , event , false ) ;
293+ return this . process ( this . states [ this . stateDefinition . StartAt ] , this . stateDefinition . StartAt , event ) ;
297294 }
298295
299296 async buildSubStepWorkFlow (
300297 stateDefinition : StateMachine ,
301298 event : Event
302299 ) : Promise < ReturnType < StepFunctionsOfflinePlugin [ 'process' ] > > {
303300 this . cliLog ( 'Building Iterator StepWorkFlow' ) ;
304- this . subContextObject = this . createContextObject ( stateDefinition . States , stateDefinition . StartAt , event , true ) ;
301+ this . addContextObject ( stateDefinition . States , stateDefinition . StartAt , event ) ;
305302
306303 if ( ! stateDefinition . States ) return ;
307304 const state = stateDefinition . States [ stateDefinition . StartAt ] ;
308- const result = await this . process ( state , stateDefinition . StartAt , event , true ) ;
309- this . subContextObject = null ;
305+ const result = await this . process ( state , stateDefinition . StartAt , event ) ;
306+ this . contexts [ stateDefinition . StartAt ] = null ;
310307 return result ;
311308 }
312309
313- process (
314- state : State ,
315- stateName : string ,
316- event : Event ,
317- isSubContext : boolean
318- ) : void | Promise < void | Callback > | Callback {
310+ process ( state : State , stateName : string , event : Event ) : void | Promise < void | Callback > | Callback {
319311 if ( state && state . Type === 'Parallel' ) {
320312 this . eventForParallelExecution = event ;
321313 }
@@ -331,7 +323,8 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
331323 if ( stateIsChoiceConditional ( data ) && data . choice ) {
332324 return this . _runChoice ( data , event ) ;
333325 } else if ( ! stateIsChoiceConditional ( data ) ) {
334- return this . _run ( data . f ( event ) , event , isSubContext ) ;
326+ const callback = data . f ( event ) ;
327+ return this . _run ( callback , event , stateName ) ;
335328 }
336329 }
337330
@@ -350,12 +343,12 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
350343 _run (
351344 func : Callback | Promise < void | AsyncCallback > ,
352345 event : Event ,
353- isSubContext : boolean
346+ name : string
354347 ) : void | Promise < void | Callback > | Callback {
355348 if ( ! func ) return ; // end of states
356349 this . executionLog ( `~~~~~~~~~~~~~~~~~~~~~~~~~~~ ${ this . currentStateName } started ~~~~~~~~~~~~~~~~~~~~~~~~~~~` ) ;
357350
358- const contextObject = isSubContext ? this . subContextObject : this . contextObject ;
351+ const contextObject = this . contexts [ name ] ;
359352 if ( contextObject ) {
360353 if ( func instanceof Promise ) {
361354 return func . then ( async mod => {
@@ -427,7 +420,7 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
427420 this . mapResults = [ ] ;
428421
429422 if ( currentState . Next ) {
430- await this . process ( this . states [ currentState . Next ] , currentState . Next , event , true ) ;
423+ await this . process ( this . states [ currentState . Next ] , currentState . Next , event ) ;
431424 }
432425 return Promise . resolve ( ) ;
433426 } ) ;
@@ -462,11 +455,11 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
462455 _ . forEach ( currentState . Branches , branch => {
463456 this . parallelBranch = branch ;
464457 return this . eventForParallelExecution
465- ? this . process ( branch . States [ branch . StartAt ] , branch . StartAt , this . eventForParallelExecution , true )
458+ ? this . process ( branch . States [ branch . StartAt ] , branch . StartAt , this . eventForParallelExecution )
466459 : null ;
467460 } ) ;
468461 if ( currentState . Next ) {
469- this . process ( this . states [ currentState . Next ] , currentState . Next , this . eventParallelResult , false ) ;
462+ this . process ( this . states [ currentState . Next ] , currentState . Next , this . eventParallelResult ) ;
470463 }
471464 delete this . parallelBranch ;
472465 this . eventParallelResult = [ ] ;
@@ -600,13 +593,13 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
600593 const isConditionTrue = choice . checkFunction ( functionResultValue , choice . compareWithValue ) ;
601594 if ( isConditionTrue && choice . choiceFunction ) {
602595 existsAnyMatches = true ;
603- return this . process ( this . states [ choice . choiceFunction ] , choice . choiceFunction , result , true ) ;
596+ return this . process ( this . states [ choice . choiceFunction ] , choice . choiceFunction , result ) ;
604597 }
605598 }
606599 } ) ;
607600 if ( ! existsAnyMatches && data . defaultFunction ) {
608601 const fName = data . defaultFunction ;
609- return this . process ( this . states [ fName ] , fName , result , false ) ;
602+ return this . process ( this . states [ fName ] , fName , result ) ;
610603 }
611604 }
612605
@@ -657,12 +650,13 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
657650 return waitTimer ;
658651 }
659652
660- createContextObject (
661- states : StateMachine [ 'States' ] ,
662- name : string ,
663- originalEvent : Event ,
664- isSubContext : boolean
665- ) : ContextObject {
653+ addContextObject ( states : StateMachine [ 'States' ] , name : string , event : Event ) : void {
654+ if ( this . contexts [ name ] ) return ;
655+ const contextObject = this . createContextObject ( states , name , event ) ;
656+ this . contexts [ name ] = contextObject ;
657+ }
658+
659+ createContextObject ( states : StateMachine [ 'States' ] , name : string , originalEvent : Event ) : ContextObject {
666660 let attempt = 0 ;
667661 const cb = ( err : Maybe < Error > , result ?: Event ) => {
668662 if ( ! notEmpty ( this . currentState ) ) return ;
@@ -676,16 +670,17 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
676670 if ( ! matchingError ) throw `Error in function "${ this . currentStateName } ": ${ JSON . stringify ( err ) } ` ;
677671 attempt += 1 ;
678672 if ( attempt < ( matchingError . MaxAttempts ?? 0 ) ) {
673+ this . addContextObject ( states , name , originalEvent ) ;
679674 if ( matchingError . IntervalSeconds !== undefined && matchingError . IntervalSeconds !== 0 ) {
680675 const backoffRate = matchingError ?. BackoffRate ?? 2 ;
681676 const fullDelay =
682677 attempt === 1
683678 ? matchingError . IntervalSeconds
684679 : matchingError . IntervalSeconds * ( attempt - 1 ) * backoffRate ;
685680 console . log ( `Delaying ${ fullDelay } seconds for execution #${ attempt + 1 } of state ${ name } ` ) ;
686- return delay ( fullDelay ) . then ( ( ) => this . process ( states [ name ] , name , originalEvent , isSubContext ) ) ;
681+ return delay ( fullDelay ) . then ( ( ) => this . process ( states [ name ] , name , originalEvent ) ) ;
687682 }
688- return this . process ( states [ name ] , name , originalEvent , isSubContext ) ;
683+ return this . process ( states [ name ] , name , originalEvent ) ;
689684 }
690685 const newErr = `Error in function "${ this . currentStateName } " after ${ attempt } attempts: ${ JSON . stringify (
691686 this . currentState
@@ -706,11 +701,13 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
706701 this . mapResults . push ( result ) ;
707702 }
708703 if ( this . currentState ?. Next ) {
709- return this . process ( state [ this . currentState . Next ] , this . currentState . Next , result ?? { } , isSubContext ) ;
704+ this . addContextObject ( states , this . currentState . Next , originalEvent ) ;
705+ return this . process ( state [ this . currentState . Next ] , this . currentState . Next , result ?? { } ) ;
710706 }
711707 } ;
712708
713709 return {
710+ name,
714711 attempt,
715712 cb,
716713 done : cb ,
0 commit comments