@@ -2724,64 +2724,102 @@ export interface CompiledExecutionPlan {
27242724
27252725const executionPlanCache = new WeakMap < Machine . Any , CompiledExecutionPlan > ( )
27262726
2727+ const makeActiveExecutionPlan = ( machine : Machine . Any ) : CompiledExecutionPlan => ( {
2728+ fromConfiguration : ( configuration ) => configuration ,
2729+ toConfiguration : ( state ) => state as ActiveConfiguration ,
2730+ snapshot : ( state ) => snapshotFromConfiguration ( machine , state as ActiveConfiguration ) ,
2731+ plan : ( state , event ) => planConfiguration ( machine as any , state as ActiveConfiguration , event as any )
2732+ } )
2733+
2734+ const makeIndexedExecutionPlan = (
2735+ machine : Machine . Any ,
2736+ indexed : IndexedExecutionDescriptor
2737+ ) : CompiledExecutionPlan => ( {
2738+ fromConfiguration : ( configuration ) => indexedConfigurationFromActive ( indexed , configuration ) ,
2739+ toConfiguration : ( state ) => activeConfigurationFromIndexed ( indexed , state as IndexedConfiguration ) ,
2740+ snapshot : ( state ) => snapshotFromIndexed ( indexed , state as IndexedConfiguration ) ,
2741+ plan : ( state , event ) => planIndexedConfiguration ( machine , indexed , state as IndexedConfiguration , event ) ,
2742+ initial : ( args ) => {
2743+ const inputArgs = machine . input === undefined
2744+ ? args
2745+ : args . length === 0
2746+ ? ( decodeInputSync ( machine , machine . input , undefined ) , args )
2747+ : [ decodeInputSync ( machine , machine . input , args [ 0 ] ) ]
2748+ const initial = machine . initial ( ...inputArgs as any )
2749+ const active = normalizeConfigurationSync ( machine , initial as Machine . Snapshot < any > )
2750+ validateInitialConfiguration ( machine , active )
2751+ const completed = completeConfigurationSync ( machine , active , InitialEvent ) . configuration
2752+ const configuration = indexedConfigurationFromActive ( indexed , completed )
2753+ const state = snapshotFromIndexed ( indexed , configuration )
2754+ const done = isActiveFinalConfiguration ( machine , completed )
2755+ if ( ! done ) {
2756+ return {
2757+ state,
2758+ configuration,
2759+ activeConfiguration : completed ,
2760+ initialEntryPaths : getInitialEntryPaths ( machine , completed ) ,
2761+ done : false ,
2762+ output : undefined
2763+ }
2764+ }
2765+ const root = getRootPath ( machine , completed )
2766+ if ( ! completed . outputs . has ( root ) ) {
2767+ throw new Error ( "Machine reached a terminal configuration without a completed root output" )
2768+ }
2769+ return {
2770+ state,
2771+ configuration,
2772+ activeConfiguration : completed ,
2773+ initialEntryPaths : getInitialEntryPaths ( machine , completed ) ,
2774+ done : true ,
2775+ output : completed . outputs . get ( root )
2776+ }
2777+ }
2778+ } )
2779+
2780+ export type ExecutionPlanStrategy = "generic" | "indexed-flat" | "indexed-hierarchical" | "auto"
2781+
2782+ export interface SelectedExecutionPlan {
2783+ readonly strategy : Exclude < ExecutionPlanStrategy , "auto" >
2784+ readonly plan : CompiledExecutionPlan
2785+ }
2786+
2787+ const selectExecutionPlan = (
2788+ machine : Machine . Any ,
2789+ strategy : ExecutionPlanStrategy
2790+ ) : SelectedExecutionPlan => {
2791+ if ( strategy === "generic" ) {
2792+ return { strategy, plan : makeActiveExecutionPlan ( machine ) }
2793+ }
2794+ const indexed = compileIndexedExecutionDescriptor ( machine )
2795+ if ( indexed === undefined ) {
2796+ if ( strategy === "auto" ) {
2797+ return { strategy : "generic" , plan : makeActiveExecutionPlan ( machine ) }
2798+ }
2799+ throw new Error ( `Machine cannot compile the requested ${ strategy } execution plan` )
2800+ }
2801+ const selected = indexed . flat ? "indexed-flat" : "indexed-hierarchical"
2802+ if ( strategy !== "auto" && strategy !== selected ) {
2803+ throw new Error ( `Machine compiled ${ selected } , not the requested ${ strategy } execution plan` )
2804+ }
2805+ return { strategy : selected , plan : makeIndexedExecutionPlan ( machine , indexed ) }
2806+ }
2807+
2808+ /** @internal Test-only uncached strategy selection. */
2809+ export const selectExecutionPlanForTesting = (
2810+ machine : Machine . Any ,
2811+ strategy : ExecutionPlanStrategy
2812+ ) : SelectedExecutionPlan => selectExecutionPlan ( machine , strategy )
2813+
27272814export const compileExecutionPlan = ( machine : Machine . Any ) : CompiledExecutionPlan => {
27282815 const cached = executionPlanCache . get ( machine )
27292816 if ( cached !== undefined ) {
27302817 return cached
27312818 }
27322819 const indexed = compileIndexedExecutionDescriptor ( machine )
2733- const activePlan = (
2734- plan : ( configuration : ActiveConfiguration , event : unknown ) => MacrostepPlan < ActiveConfiguration , any , any , any , any >
2735- ) : CompiledExecutionPlan => ( {
2736- fromConfiguration : ( configuration ) => configuration ,
2737- toConfiguration : ( state ) => state as ActiveConfiguration ,
2738- snapshot : ( state ) => snapshotFromConfiguration ( machine , state as ActiveConfiguration ) ,
2739- plan : ( state , event ) => plan ( state as ActiveConfiguration , event )
2740- } )
2741- const compiled : CompiledExecutionPlan = indexed !== undefined
2742- ? {
2743- fromConfiguration : ( configuration ) => indexedConfigurationFromActive ( indexed , configuration ) ,
2744- toConfiguration : ( state ) => activeConfigurationFromIndexed ( indexed , state as IndexedConfiguration ) ,
2745- snapshot : ( state ) => snapshotFromIndexed ( indexed , state as IndexedConfiguration ) ,
2746- plan : ( state , event ) => planIndexedConfiguration ( machine , indexed , state as IndexedConfiguration , event ) ,
2747- initial : ( args ) => {
2748- const inputArgs = machine . input === undefined
2749- ? args
2750- : args . length === 0
2751- ? ( decodeInputSync ( machine , machine . input , undefined ) , args )
2752- : [ decodeInputSync ( machine , machine . input , args [ 0 ] ) ]
2753- const initial = machine . initial ( ...inputArgs as any )
2754- const active = normalizeConfigurationSync ( machine , initial as Machine . Snapshot < any > )
2755- validateInitialConfiguration ( machine , active )
2756- const completed = completeConfigurationSync ( machine , active , InitialEvent ) . configuration
2757- const configuration = indexedConfigurationFromActive ( indexed , completed )
2758- const state = snapshotFromIndexed ( indexed , configuration )
2759- const done = isActiveFinalConfiguration ( machine , completed )
2760- if ( ! done ) {
2761- return {
2762- state,
2763- configuration,
2764- activeConfiguration : completed ,
2765- initialEntryPaths : getInitialEntryPaths ( machine , completed ) ,
2766- done : false ,
2767- output : undefined
2768- }
2769- }
2770- const root = getRootPath ( machine , completed )
2771- if ( ! completed . outputs . has ( root ) ) {
2772- throw new Error ( "Machine reached a terminal configuration without a completed root output" )
2773- }
2774- return {
2775- state,
2776- configuration,
2777- activeConfiguration : completed ,
2778- initialEntryPaths : getInitialEntryPaths ( machine , completed ) ,
2779- done : true ,
2780- output : completed . outputs . get ( root )
2781- }
2782- }
2783- }
2784- : activePlan ( ( configuration , event ) => planConfiguration ( machine as any , configuration , event as any ) )
2820+ const compiled = indexed === undefined
2821+ ? makeActiveExecutionPlan ( machine )
2822+ : makeIndexedExecutionPlan ( machine , indexed )
27852823 executionPlanCache . set ( machine , compiled )
27862824 return compiled
27872825}
0 commit comments