@@ -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 > ;
@@ -77,6 +78,7 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
7778 this . functions = this . serverless . service . functions ;
7879 this . variables = this . serverless . service . custom ?. stepFunctionsOffline ;
7980 this . cliLog = this . serverless . cli . log . bind ( this . serverless . cli ) ;
81+ this . contexts = { } ;
8082 this . commands = {
8183 'step-functions-offline' : {
8284 usage : 'Will run your step function locally' ,
@@ -293,36 +295,26 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
293295 if ( ! this . stateDefinition ?. StartAt ) {
294296 throw new Error ( 'Missing `startAt` in definition' ) ;
295297 }
296- this . contextObject = this . createContextObject (
297- this . stateDefinition . States ,
298- this . stateDefinition . StartAt ,
299- event ,
300- false
301- ) ;
298+ this . addContextObject ( this . stateDefinition . States , this . stateDefinition . StartAt , event ) ;
302299 this . states = this . stateDefinition . States ;
303- return this . process ( this . states [ this . stateDefinition . StartAt ] , this . stateDefinition . StartAt , event , false ) ;
300+ return this . process ( this . states [ this . stateDefinition . StartAt ] , this . stateDefinition . StartAt , event ) ;
304301 }
305302
306303 async buildSubStepWorkFlow (
307304 stateDefinition : StateMachine ,
308305 event : Event
309306 ) : Promise < ReturnType < StepFunctionsOfflinePlugin [ 'process' ] > > {
310307 this . cliLog ( 'Building Iterator StepWorkFlow' ) ;
311- this . subContextObject = this . createContextObject ( stateDefinition . States , stateDefinition . StartAt , event , true ) ;
308+ this . addContextObject ( stateDefinition . States , stateDefinition . StartAt , event ) ;
312309
313310 if ( ! stateDefinition . States ) return ;
314311 const state = stateDefinition . States [ stateDefinition . StartAt ] ;
315- const result = await this . process ( state , stateDefinition . StartAt , event , true ) ;
316- this . subContextObject = null ;
312+ const result = await this . process ( state , stateDefinition . StartAt , event ) ;
313+ this . contexts [ stateDefinition . StartAt ] = null ;
317314 return result ;
318315 }
319316
320- process (
321- state : State ,
322- stateName : string ,
323- event : Event ,
324- isSubContext : boolean
325- ) : void | Promise < void | Callback > | Callback {
317+ process ( state : State , stateName : string , event : Event ) : void | Promise < void | Callback > | Callback {
326318 if ( state && state . Type === 'Parallel' ) {
327319 this . eventForParallelExecution = event ;
328320 }
@@ -338,7 +330,8 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
338330 if ( stateIsChoiceConditional ( data ) && data . choice ) {
339331 return this . _runChoice ( data , event ) ;
340332 } else if ( ! stateIsChoiceConditional ( data ) ) {
341- return this . _run ( data . f ( event ) , event , isSubContext ) ;
333+ const callback = data . f ( event ) ;
334+ return this . _run ( callback , event , stateName ) ;
342335 }
343336 }
344337
@@ -357,12 +350,12 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
357350 _run (
358351 func : Callback | Promise < void | AsyncCallback > ,
359352 event : Event ,
360- isSubContext : boolean
353+ name : string
361354 ) : void | Promise < void | Callback > | Callback {
362355 if ( ! func ) return ; // end of states
363356 this . executionLog ( `~~~~~~~~~~~~~~~~~~~~~~~~~~~ ${ this . currentStateName } started ~~~~~~~~~~~~~~~~~~~~~~~~~~~` ) ;
364357
365- const contextObject = isSubContext ? this . subContextObject : this . contextObject ;
358+ const contextObject = this . contexts [ name ] ;
366359 if ( contextObject ) {
367360 if ( func instanceof Promise ) {
368361 return func . then ( async mod => {
@@ -434,7 +427,7 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
434427 this . mapResults = [ ] ;
435428
436429 if ( currentState . Next ) {
437- await this . process ( this . states [ currentState . Next ] , currentState . Next , event , true ) ;
430+ await this . process ( this . states [ currentState . Next ] , currentState . Next , event ) ;
438431 }
439432 return Promise . resolve ( ) ;
440433 } ) ;
@@ -469,11 +462,11 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
469462 _ . forEach ( currentState . Branches , branch => {
470463 this . parallelBranch = branch ;
471464 return this . eventForParallelExecution
472- ? this . process ( branch . States [ branch . StartAt ] , branch . StartAt , this . eventForParallelExecution , true )
465+ ? this . process ( branch . States [ branch . StartAt ] , branch . StartAt , this . eventForParallelExecution )
473466 : null ;
474467 } ) ;
475468 if ( currentState . Next ) {
476- this . process ( this . states [ currentState . Next ] , currentState . Next , this . eventParallelResult , false ) ;
469+ this . process ( this . states [ currentState . Next ] , currentState . Next , this . eventParallelResult ) ;
477470 }
478471 delete this . parallelBranch ;
479472 this . eventParallelResult = [ ] ;
@@ -607,13 +600,13 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
607600 const isConditionTrue = choice . checkFunction ( functionResultValue , choice . compareWithValue ) ;
608601 if ( isConditionTrue && choice . choiceFunction ) {
609602 existsAnyMatches = true ;
610- return this . process ( this . states [ choice . choiceFunction ] , choice . choiceFunction , result , true ) ;
603+ return this . process ( this . states [ choice . choiceFunction ] , choice . choiceFunction , result ) ;
611604 }
612605 }
613606 } ) ;
614607 if ( ! existsAnyMatches && data . defaultFunction ) {
615608 const fName = data . defaultFunction ;
616- return this . process ( this . states [ fName ] , fName , result , false ) ;
609+ return this . process ( this . states [ fName ] , fName , result ) ;
617610 }
618611 }
619612
@@ -664,12 +657,13 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
664657 return waitTimer ;
665658 }
666659
667- createContextObject (
668- states : StateMachine [ 'States' ] ,
669- name : string ,
670- originalEvent : Event ,
671- isSubContext : boolean
672- ) : ContextObject {
660+ addContextObject ( states : StateMachine [ 'States' ] , name : string , event : Event ) : void {
661+ if ( this . contexts [ name ] ) return ;
662+ const contextObject = this . createContextObject ( states , name , event ) ;
663+ this . contexts [ name ] = contextObject ;
664+ }
665+
666+ createContextObject ( states : StateMachine [ 'States' ] , name : string , originalEvent : Event ) : ContextObject {
673667 let attempt = 0 ;
674668 const cb = ( err : Maybe < Error > , result ?: Event ) => {
675669 if ( ! notEmpty ( this . currentState ) ) return ;
@@ -683,16 +677,17 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
683677 if ( ! matchingError ) throw `Error in function "${ this . currentStateName } ": ${ JSON . stringify ( err ) } ` ;
684678 attempt += 1 ;
685679 if ( attempt < ( matchingError . MaxAttempts ?? 0 ) ) {
680+ this . addContextObject ( states , name , originalEvent ) ;
686681 if ( matchingError . IntervalSeconds !== undefined && matchingError . IntervalSeconds !== 0 ) {
687682 const backoffRate = matchingError ?. BackoffRate ?? 2 ;
688683 const fullDelay =
689684 attempt === 1
690685 ? matchingError . IntervalSeconds
691686 : matchingError . IntervalSeconds * ( attempt - 1 ) * backoffRate ;
692687 console . log ( `Delaying ${ fullDelay } seconds for execution #${ attempt + 1 } of state ${ name } ` ) ;
693- return delay ( fullDelay ) . then ( ( ) => this . process ( states [ name ] , name , originalEvent , isSubContext ) ) ;
688+ return delay ( fullDelay ) . then ( ( ) => this . process ( states [ name ] , name , originalEvent ) ) ;
694689 }
695- return this . process ( states [ name ] , name , originalEvent , isSubContext ) ;
690+ return this . process ( states [ name ] , name , originalEvent ) ;
696691 }
697692 const newErr = `Error in function "${ this . currentStateName } " after ${ attempt } attempts: ${ JSON . stringify (
698693 this . currentState
@@ -713,11 +708,13 @@ export default class StepFunctionsOfflinePlugin implements Plugin {
713708 this . mapResults . push ( result ) ;
714709 }
715710 if ( this . currentState ?. Next ) {
716- return this . process ( state [ this . currentState . Next ] , this . currentState . Next , result ?? { } , isSubContext ) ;
711+ this . addContextObject ( states , this . currentState . Next , originalEvent ) ;
712+ return this . process ( state [ this . currentState . Next ] , this . currentState . Next , result ?? { } ) ;
717713 }
718714 } ;
719715
720716 return {
717+ name,
721718 attempt,
722719 cb,
723720 done : cb ,
0 commit comments