@@ -37,60 +37,48 @@ interface Statecharts {
3737}
3838
3939function getActionTransitions (
40- key : string ,
40+ actionName : string ,
4141 charts : Statecharts ,
4242 state : { states : Array < ( string | number ) [ ] > }
4343) {
44- const transitions : ( string | boolean ) [ ] = [ ]
45- state . states . forEach ( ( statePath ) => {
44+ const transitions : Array < { index : number , target ?: string } > = [ ]
45+
46+ state . states . forEach ( ( statePath , index ) => {
4647 const path = statePath . slice ( )
4748
4849 while ( path . length ) {
4950 const target = getStateTarget ( charts , path )
5051
51- if ( target . entry === key ) {
52- transitions . push ( 'entry' )
53- return
54- }
55- if ( target . exit === key ) {
56- transitions . push ( 'exit' )
52+ if ( target . on &&
53+ target . on [ actionName ] === null
54+ ) {
55+ transitions . push ( { index} )
5756 return
5857 }
59- if ( target . on && target . on [ key ] === null ) {
60- transitions . push ( true )
61- return
62- }
63- if ( target . on && typeof target . on [ key ] === 'string' ) {
64- // If we have already transition to this path it means
65- // we are moving away from multiple paths (parallel)
66- if ( transitions . includes ( target . on [ key ] ) ) {
67- return
68- }
69- transitions . push ( target . on [ key ] )
58+
59+ if ( target . on && typeof target . on [ actionName ] === 'string' && ! transitions . find ( ( transition ) => transition . target === target . on [ actionName ] ) ) {
60+ transitions . push ( { index, target : target . on [ actionName ] } )
7061 return
7162 }
72- if ( target . on && target . on [ key ] && target . on [ key ] . condition ( state ) ) {
73- transitions . push ( target . on [ key ] . target )
63+
64+ if ( target . on && target . on [ actionName ] && target . on [ actionName ] . target && ! transitions . find ( ( transition ) => transition . target === target . on [ actionName ] . target ) && target . on [ actionName ] . condition ( state ) ) {
65+ transitions . push ( {
66+ index,
67+ target : target . on [ actionName ] . target
68+ } )
7469 return
7570 }
7671
7772 path . pop ( )
7873 }
79-
80- transitions . push ( false )
8174 } )
8275
8376 return transitions
8477}
8578
86- // We check if any transitions returned are not "false",
87- // which means any entry, exit or state transition should occur on
88- // any of existing state paths active
8979function getCanTransitionActions ( actions , charts , state ) {
9080 return Object . keys ( actions || { } ) . reduce ( ( aggr , key ) => {
91- aggr [ key ] = getActionTransitions ( key , charts , state ) . some (
92- ( transition ) => transition !== false
93- )
81+ aggr [ key ] = Boolean ( getActionTransitions ( key , charts , state ) . length )
9482
9583 return aggr
9684 } , { } )
@@ -242,20 +230,17 @@ export function statecharts<C extends IConfiguration, Charts extends Statecharts
242230 context . state ,
243231 context . execution . namespacePath
244232 )
245- const actions = getTarget (
246- context . actions ,
247- context . execution . namespacePath
248- )
249233
250234 const statePaths = stateTarget . states . slice ( )
251235
236+ // Run entry actions of initial state
252237 statePaths . forEach ( ( statePath ) => {
253238 const state = statePath . slice ( )
254239 while ( state . length ) {
255240 const target = getStateTarget ( charts , state )
256241
257- if ( target . entry ) {
258- actions [ target . entry ] ( )
242+ if ( config . actions && config . actions [ target . entry ] ) {
243+ config . actions [ target . entry ] ( context )
259244 }
260245
261246 state . pop ( )
@@ -276,8 +261,7 @@ export function statecharts<C extends IConfiguration, Charts extends Statecharts
276261 } ) as any ,
277262 state : Object . assign ( state , {
278263 states : getInitialStates ( charts ) ,
279- actions : ( ( state ) =>
280- getCanTransitionActions ( actions , charts , state ) ) as any ,
264+ actions : ( ( state ) => getCanTransitionActions ( actions , charts , state ) ) as any ,
281265 matches : ( state ) => ( match ) => {
282266 const matchPaths = getMatchPaths ( match )
283267
@@ -312,42 +296,39 @@ export function statecharts<C extends IConfiguration, Charts extends Statecharts
312296 const stateTarget = getTarget ( state , execution . namespacePath )
313297
314298 return {
315- transitions : getActionTransitions ( key , charts , stateTarget ) ,
299+ canTransition : stateTarget . actions [ key ] ,
316300 payload,
317301 }
318302 } ) ,
319- filter ( function canTransition ( _ , { transitions } ) {
320- return transitions . some ( ( transition ) => transition !== false )
303+ filter ( function canTransition ( _ , { canTransition } ) {
304+ return canTransition
321305 } ) ,
322- mutate ( function runAction ( context : any , { transitions , payload } ) {
306+ mutate ( function runAction ( context : any , { payload } ) {
323307 const stateTarget = getTarget (
324308 context . state ,
325309 context . execution . namespacePath
326310 )
327- const actionsTarget = getTarget (
328- context . actions ,
329- context . execution . namespacePath
330- )
311+ const transitionActions = getActionTransitions ( key , charts , stateTarget )
331312
332- const resolvedActions = getTarget (
333- context . actions ,
334- context . execution . namespacePath
335- )
336- const newStates : Array < ( string | number ) [ ] > = [ ]
337-
338- if ( transitions . includes ( 'entry' ) || transitions . includes ( 'exit' ) ) {
339- actionsTarget [ ACTIONS ] [ key ] ( payload )
313+ // If there are no new transition target, just drop moving on, just run the action
314+ if ( ! transitionActions . some ( ( transitionAction ) => transitionAction . target ) ) {
315+ if ( config . actions ) {
316+ config . actions [ key ] ( context , payload )
317+ }
318+ return
340319 }
341320
342- const actionsToRun = transitions . reduce ( ( aggr , transition , index ) => {
343- const oldStatePath = stateTarget . states [ index ] . slice ( )
321+ const exitActions : string [ ] = [ ]
322+ const entryActions : string [ ] = [ ]
323+ const newStates : Array < string [ ] > = [ ]
344324
345- if ( transition === 'entry' || transition === 'exit' ) {
346- newStates . push ( oldStatePath )
347- return aggr
325+ transitionActions . forEach ( ( transitionAction ) => {
326+ // It is an action that does not cause a transition
327+ if ( ! transitionAction . target ) {
328+ return
348329 }
349330
350- const currentStatePath = stateTarget . states [ index ] . slice ( )
331+ const currentStatePath = stateTarget . states [ transitionAction . index ] . slice ( )
351332 const stateTransitions = currentStatePath . map ( ( ) => null )
352333
353334 // Build new transition path
@@ -367,20 +348,22 @@ export function statecharts<C extends IConfiguration, Charts extends Statecharts
367348 stateTarget . states ,
368349 stateTransitions ,
369350 charts ,
370- index
351+ transitionAction . index
371352 )
372353
373354 // Go down old path and trigger exits where the state has changed
374- const traverseOldPath = oldStatePath . slice ( )
355+ const traverseOldPath = stateTarget . states [ transitionAction . index ] . slice ( )
356+
375357 while ( traverseOldPath . length ) {
376358 const target = getStateTarget ( charts , traverseOldPath )
377359
378360 if (
379361 target . exit &&
380362 newStatePath [ traverseOldPath . length - 1 ] !==
381- oldStatePath [ traverseOldPath . length - 1 ]
363+ traverseOldPath [ traverseOldPath . length - 1 ]
382364 ) {
383- resolvedActions [ target . exit ] ( )
365+
366+ exitActions . push ( target . exit )
384367 }
385368
386369 traverseOldPath . pop ( )
@@ -396,26 +379,37 @@ export function statecharts<C extends IConfiguration, Charts extends Statecharts
396379 if (
397380 target . entry &&
398381 newStatePath [ traverseNewPath . length - 1 ] !==
399- oldStatePath [ traverseNewPath . length - 1 ]
382+ traverseNewPath [ traverseNewPath . length - 1 ]
400383 ) {
401- resolvedActions [ target . entry ] ( )
384+ entryActions . push ( target . entry )
402385 }
403386
404387 traverseNewPath . pop ( )
405388 }
406389
407-
408- if ( transition ) {
409- return aggr . concat ( ( ) => actionsTarget [ ACTIONS ] [ key ] ( payload ) )
410- }
411-
412- return aggr
413- } , [ ] as Function [ ] )
414-
415- // Actually change what has changed
390+ } )
391+
392+ // Run exits
393+ exitActions . forEach ( ( exitAction ) => {
394+ if ( config . actions ) {
395+ config . actions [ exitAction ] ( context , payload )
396+ }
397+ } )
398+
399+ // Transition to new state
416400 stateTarget . states = newStates
417401
418- actionsToRun . forEach ( ( action ) => action ( ) )
402+ if ( config . actions ) {
403+ config . actions [ key ] ( context , payload )
404+ }
405+
406+ // Run enters
407+
408+ entryActions . forEach ( ( entryAction ) => {
409+ if ( config . actions ) {
410+ config . actions [ entryAction ] ( context , payload )
411+ }
412+ } )
419413
420414 if ( process . env . NODE_ENV === 'development' && currentInstance . devtools ) {
421415 currentInstance . devtools . send ( {
0 commit comments