Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
d99bffe
Support transition functions WIP
davidkpiano Mar 13, 2025
1c1de5e
Enqueue actions WIP
davidkpiano Mar 13, 2025
5fb99ab
Guards
davidkpiano Mar 15, 2025
b4631d3
Move enqueue obj
davidkpiano Mar 22, 2025
5224ffd
More tests
davidkpiano Mar 25, 2025
98ac2d5
Add children to action arg, More tests
davidkpiano Mar 28, 2025
06cd686
Merge branch 'main' into v6
davidkpiano Mar 28, 2025
8f0d641
Add evaluateCandidate, next set of tests
davidkpiano Mar 30, 2025
6fdd543
Add guards
davidkpiano Mar 30, 2025
fa0cc07
Add more v6 tests
davidkpiano Apr 8, 2025
5492fb5
Move id counter to be per-system, add children to transition function
davidkpiano Apr 10, 2025
050fa9b
Reenter
davidkpiano Apr 12, 2025
8611632
WIP
davidkpiano Apr 12, 2025
30086a1
Add some missing impls
davidkpiano Apr 14, 2025
b9d13d4
Add test
davidkpiano Apr 15, 2025
b572c3d
Add invoke v6 tests
davidkpiano Apr 16, 2025
f545e7c
Add invoke v6 tests
davidkpiano Apr 16, 2025
c5345a9
Update snapshot
davidkpiano Apr 16, 2025
d7c7f9e
More tests
davidkpiano Apr 17, 2025
9572d90
More tests
davidkpiano Apr 21, 2025
2ec7f75
Rehydration tests WIP
davidkpiano Apr 21, 2025
d3c40cf
Support for emitted events as actions and enq.action(fn, ...args)
davidkpiano Apr 27, 2025
a18159d
Make sure to return new snapshot for transient transitions that updat…
davidkpiano Apr 27, 2025
4218bf7
Add more test files
davidkpiano Apr 27, 2025
4ae4f82
Add state.v6.test.ts
davidkpiano May 11, 2025
5b64c4f
Merge branch 'main' into v6
davidkpiano May 17, 2025
29088dd
Refactor state machine transition functions to use concise syntax
davidkpiano May 26, 2025
d4744da
Refactor cont'd
davidkpiano May 26, 2025
62ff9ed
Fix test
davidkpiano May 26, 2025
288d4f6
WIP
davidkpiano Jun 6, 2025
903c786
Merge branch 'main' into v6
davidkpiano Jun 8, 2025
44e52db
WIP
davidkpiano Jun 14, 2025
d5a7e6c
Actions WIP
davidkpiano Jun 17, 2025
600e6fb
Use vitest
davidkpiano Jun 17, 2025
a0d4a6e
Update assert tests
davidkpiano Jun 17, 2025
ac6321a
Merge branch 'main' into v6
davidkpiano Jun 29, 2025
39a155b
WIP
davidkpiano Jun 29, 2025
7cbd09c
Merge branch 'main' into v6
davidkpiano Jul 10, 2025
d1d13d2
Merge branch 'main' into v6
davidkpiano Jul 11, 2025
681e967
Convert after tests
davidkpiano Jul 12, 2025
3722fb9
Remove assign.v6.tests.ts
davidkpiano Jul 12, 2025
d3a07e7
Migrate tests
davidkpiano Jul 13, 2025
c11f3b3
More tests
davidkpiano Jul 13, 2025
0099005
Guards
davidkpiano Jul 13, 2025
dc795e5
WIP
davidkpiano Jul 14, 2025
fa349ef
Fix test (pardon the dust)
davidkpiano Jul 14, 2025
a645d31
Interpretertest
davidkpiano Jul 15, 2025
14fa951
Invoke
davidkpiano Jul 16, 2025
f10f326
Logger
davidkpiano Jul 16, 2025
da339c5
Refactor log
davidkpiano Jul 16, 2025
d76c5cb
sendTo WIP
davidkpiano Jul 16, 2025
f0d634f
Meta
davidkpiano Jul 17, 2025
28f7f6d
Parallel & order
davidkpiano Jul 17, 2025
d944db7
Spawn, spawnChild, state
davidkpiano Jul 17, 2025
8aa2f7f
stateIn, tags
davidkpiano Jul 17, 2025
641d070
Remove assign WIP
davidkpiano Jul 18, 2025
4147fe1
Replace createMachine WIP
davidkpiano Jul 27, 2025
d3aa151
WIP
davidkpiano Jul 27, 2025
1a1f089
schema.event-> schema.events
davidkpiano Jul 27, 2025
a6bc6ba
enq.action(…) -> enq(…)
davidkpiano Jul 27, 2025
77dcd8a
Removing enqueueActions WIP
davidkpiano Jul 27, 2025
b469a9f
Cleanup & wip
davidkpiano Jul 28, 2025
760e92d
Introduce src: ({ actors }) => …
davidkpiano Jul 30, 2025
f95094b
Cleanup; remove xstate-immer package
davidkpiano Jul 30, 2025
08c420c
Remove forwardTo
davidkpiano Jul 30, 2025
54bbfce
Remove sendParent
davidkpiano Jul 30, 2025
c4af0b8
WIP
davidkpiano Jul 31, 2025
cbb7793
WIP: make actions tests pass
davidkpiano Aug 1, 2025
febcb5c
WIP actions tests
davidkpiano Aug 1, 2025
ba2025f
WIP
davidkpiano Aug 3, 2025
329e41f
WIP
davidkpiano Aug 7, 2025
f63a398
WIP
davidkpiano Aug 7, 2025
0ab59cc
WIP remove createMachine
davidkpiano Aug 7, 2025
7731a0d
WIP
davidkpiano Aug 7, 2025
d7946a5
WIP fix tests
davidkpiano Aug 8, 2025
7103fdf
WIP fix tests
davidkpiano Aug 8, 2025
89b7cbe
WIP
davidkpiano Aug 8, 2025
18b97b4
WIP: built-in actions
davidkpiano Aug 9, 2025
d48df8a
Fix delayed transitions
davidkpiano Aug 11, 2025
3d80649
WIP state schema
davidkpiano Aug 11, 2025
6fca2d5
Merge branch 'main' into v6
davidkpiano Sep 5, 2025
0dcf003
Some test fixes
davidkpiano Sep 6, 2025
0a0e189
Merge branch 'main' into v6
davidkpiano Sep 7, 2025
fefd3b6
Skip rehydration, fix transient algo (WIP)
davidkpiano Sep 7, 2025
a5c5526
Simplify inspection
davidkpiano Sep 9, 2025
62c5dfb
Update tests
davidkpiano Sep 11, 2025
74d9f1d
Fix initial transitions
davidkpiano Sep 12, 2025
5cd7dc2
Cleanup
davidkpiano Sep 12, 2025
327d746
Get all tests passing (WIP)
davidkpiano Sep 20, 2025
0f560d9
Remove assign and enqueueActions
davidkpiano Sep 21, 2025
825a4de
Fix typeHelpers.test.ts
davidkpiano Sep 21, 2025
1f16ae3
Remove setup
davidkpiano Sep 24, 2025
5ec8fb8
Remove raise WIP
davidkpiano Sep 24, 2025
1feefec
Merge branch 'main' into v6
davidkpiano Sep 24, 2025
4a735c2
Bulldozing action code
davidkpiano Sep 25, 2025
5b5c1af
Remove raise!
davidkpiano Sep 26, 2025
b6b6e1d
Delete send action
davidkpiano Sep 26, 2025
9cbe2a6
Delete more actions (WIP cancel)
davidkpiano Sep 26, 2025
5c84883
Remove guards
davidkpiano Sep 27, 2025
761fb77
Remove all actions
davidkpiano Sep 28, 2025
e71a0d8
Action logic cleanup
davidkpiano Sep 28, 2025
40996a2
WIP cleanup
davidkpiano Sep 28, 2025
03a21be
More cleanup
davidkpiano Sep 28, 2025
b23c68c
More cleanup
davidkpiano Sep 28, 2025
9adae3f
Type cleanup
davidkpiano Sep 28, 2025
7094e06
Merge branch 'main' into v6
davidkpiano Oct 17, 2025
f3f1151
Fix test + package.json
davidkpiano Oct 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ Special thanks to the sponsors who support this open-source project:
</picture>
</a>


## Templates

Get started by forking one of these templates on CodeSandbox:
Expand Down Expand Up @@ -565,7 +564,6 @@ actor.send({ type: 'PREVIOUS' });
</tbody>
</table>


## SemVer Policy

We understand the importance of the public contract and do not intend to release any breaking changes to the **runtime** API in a minor or patch release. We consider this with any changes we make to the XState libraries and aim to minimize their effects on existing users.
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"preinstall": "node ./scripts/ensure-pnpm.js",
"postinstall": "manypkg check && preconstruct dev",
"build": "preconstruct build",
"watch": "preconstruct watch",
"fix": "manypkg fix",
"lint": "eslint --cache --quiet",
"typecheck": "tsc",
Expand Down Expand Up @@ -55,7 +56,7 @@
"@changesets/cli": "^2.29.5",
"@eslint/js": "^9.26.0",
"@manypkg/cli": "^0.21.4",
"@preconstruct/cli": "^2.8.1",
"@preconstruct/cli": "^2.8.12",
"@types/node": "^20.14.13",
"babel-preset-solid": "^1.8.4",
"eslint": "^9.26.0",
Expand Down
33 changes: 2 additions & 31 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,6 @@
"import": "./dist/xstate.cjs.mjs",
"default": "./dist/xstate.cjs.js"
},
"./guards": {
"types": {
"import": "./guards/dist/xstate-guards.cjs.mjs",
"default": "./guards/dist/xstate-guards.cjs.js"
},
"development": {
"module": "./guards/dist/xstate-guards.development.esm.js",
"import": "./guards/dist/xstate-guards.development.cjs.mjs",
"default": "./guards/dist/xstate-guards.development.cjs.js"
},
"module": "./guards/dist/xstate-guards.esm.js",
"import": "./guards/dist/xstate-guards.cjs.mjs",
"default": "./guards/dist/xstate-guards.cjs.js"
},
"./actions": {
"types": {
"import": "./actions/dist/xstate-actions.cjs.mjs",
"default": "./actions/dist/xstate-actions.cjs.js"
},
"development": {
"module": "./actions/dist/xstate-actions.development.esm.js",
"import": "./actions/dist/xstate-actions.development.cjs.mjs",
"default": "./actions/dist/xstate-actions.development.cjs.js"
},
"module": "./actions/dist/xstate-actions.esm.js",
"import": "./actions/dist/xstate-actions.cjs.mjs",
"default": "./actions/dist/xstate-actions.cjs.js"
},
"./dev": {
"types": {
"import": "./dev/dist/xstate-dev.cjs.mjs",
Expand Down Expand Up @@ -138,15 +110,14 @@
"ajv": "^8.12.0",
"pkg-up": "^3.1.0",
"rxjs": "^7.8.1",
"xml-js": "^1.6.11"
"xml-js": "^1.6.11",
"zod": "^3.25.51"
},
"preconstruct": {
"umdName": "XState",
"entrypoints": [
"./index.ts",
"./actions.ts",
"./actors/index.ts",
"./guards.ts",
"./dev/index.ts",
"./graph/index.ts"
]
Expand Down
26 changes: 21 additions & 5 deletions packages/core/src/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import isDevelopment from '#is-development';
import { $$ACTOR_TYPE } from './createActor.ts';
import type { StateNode } from './StateNode.ts';
import type { StateMachine } from './StateMachine.ts';
import { getStateValue } from './stateUtils.ts';
import { getStateValue, getTransitionResult, hasEffect } from './stateUtils.ts';
import type {
ProvidedActor,
AnyMachineSnapshot,
Expand All @@ -20,9 +20,12 @@ import type {
StateSchema,
StateId,
SnapshotStatus,
PersistedHistoryValue
PersistedHistoryValue,
TODO
} from './types.ts';
import { matchesState } from './utils.ts';
import { createSystem } from './system.ts';
import { createEmptyActor } from './actors/index.ts';

type ToTestStateValue<TStateValue extends StateValue> =
TStateValue extends string
Expand Down Expand Up @@ -71,7 +74,10 @@ interface MachineSnapshotBase<
TOutput,
EventObject, // TEmitted
any, // TMeta
TStateSchema
TStateSchema,
TODO, // TActionMap
TODO, // TActorMap
TODO // TGuardMap
>;
/** The tags of the active state nodes that represent the current state value. */
tags: Set<string>;
Expand Down Expand Up @@ -312,12 +318,22 @@ const machineSnapshotCan = function can(
);
}

const transitionData = this.machine.getTransitionData(this, event);
const transitionData = this.machine.getTransitionData(this, event, {} as any);

return (
!!transitionData?.length &&
// Check that at least one transition is not forbidden
transitionData.some((t) => t.target !== undefined || t.actions.length)
transitionData.some((t) => {
const res = getTransitionResult(t, this, event, createEmptyActor(), {
system: createSystem(createEmptyActor(), {})
} as any);
return (
t.target !== undefined ||
res.targets?.length ||
res.context ||
hasEffect(t, this.context, event, this, {} as any)
);
})
);
};

Expand Down
111 changes: 59 additions & 52 deletions packages/core/src/StateMachine.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import isDevelopment from '#is-development';
import { assign } from './actions.ts';
import { $$ACTOR_TYPE, createActor } from './createActor.ts';
import { createInitEvent } from './eventUtils.ts';
import { createSpawner } from './spawn.ts';
import {
createMachineSnapshot,
getPersistedSnapshot,
Expand All @@ -17,7 +17,7 @@
isStateId,
macrostep,
microstep,
resolveActionsAndContext,
resolveAndExecuteActionsWithContext,
resolveStateValue,
transitionNode
} from './stateUtils.ts';
Expand All @@ -29,15 +29,11 @@
AnyActorRef,
AnyActorScope,
AnyEventObject,
DoNotInfer,
Equals,
EventDescriptor,
EventObject,
HistoryValue,
InternalMachineImplementations,
MachineConfig,
MachineContext,
MachineImplementationsSimplified,
MetaObject,
ParameterizedObject,
ProvidedActor,
Expand All @@ -46,10 +42,10 @@
StateMachineDefinition,
StateValue,
TransitionDefinition,
ResolvedStateMachineTypes,
StateSchema,
SnapshotStatus
} from './types.ts';
import { Implementations, Next_MachineConfig } from './types.v6.ts';
import { resolveReferencedActor, toStatePath } from './utils.ts';

const STATE_IDENTIFIER = '#';
Expand All @@ -68,7 +64,8 @@
TOutput,
TEmitted extends EventObject,
TMeta extends MetaObject,
TConfig extends StateSchema
TConfig extends StateSchema,
TImplementations extends Implementations

Check failure on line 68 in packages/core/src/StateMachine.ts

View workflow job for this annotation

GitHub Actions / build

'TImplementations' is defined but never used. Allowed unused vars must match /^_/u
> implements
ActorLogic<
MachineSnapshot<
Expand All @@ -92,7 +89,7 @@

public schemas: unknown;

public implementations: MachineImplementationsSimplified<TContext, TEvent>;
public implementations: Implementations;

/** @internal */
public __xstatenode = true as const;
Expand All @@ -109,29 +106,28 @@

constructor(
/** The raw config used to create the machine. */
public config: MachineConfig<
TContext,
TEvent,
public config: Next_MachineConfig<
any,
any,
any,
any,
any,
any,
TOutput,
any, // TEmitted
any // TMeta
any,
any,
any
> & {
schemas?: unknown;
},
implementations?: MachineImplementationsSimplified<TContext, TEvent>
implementations?: Implementations
) {
this.id = config.id || '(machine)';
this.implementations = {
actors: implementations?.actors ?? {},
actions: implementations?.actions ?? {},
delays: implementations?.delays ?? {},
guards: implementations?.guards ?? {}
actors: config.actors ?? {},
actions: config.actions ?? {},
delays: config.delays ?? {},
guards: config.guards ?? {},
...implementations
};
this.version = this.config.version;
this.schemas = this.config.schemas;
Expand Down Expand Up @@ -172,20 +168,11 @@
* recursively merge with the existing options.
* @returns A new `StateMachine` instance with the provided implementations.
*/
public provide(
implementations: InternalMachineImplementations<
ResolvedStateMachineTypes<
TContext,
DoNotInfer<TEvent>,
TActor,
TAction,
TGuard,
TDelay,
TTag,
TEmitted
>
>
): StateMachine<
public provide(implementations: {
actions?: Partial<TActionMap>;
actors?: Partial<TActorMap>;
guards?: Partial<TGuardMap>;
}): StateMachine<
TContext,
TEvent,
TChildren,
Expand All @@ -199,7 +186,10 @@
TOutput,
TEmitted,
TMeta,
TConfig
TConfig,
TActionMap,
TActorMap,
TGuardMap
> {
const { actions, guards, actors, delays } = this.implementations;

Expand Down Expand Up @@ -342,9 +332,12 @@
TMeta,
TConfig
>,
event: TEvent
event: TEvent,
self: AnyActorRef
): Array<TransitionDefinition<TContext, TEvent>> {
return transitionNode(this.root, snapshot.value, snapshot, event) || [];
return (
transitionNode(this.root, snapshot.value, snapshot, event, self) || []
);
}

/**
Expand All @@ -354,7 +347,7 @@
private getPreInitialState(
actorScope: AnyActorScope,
initEvent: any,
internalQueue: AnyEventObject[]

Check failure on line 350 in packages/core/src/StateMachine.ts

View workflow job for this annotation

GitHub Actions / build

'internalQueue' is defined but never used. Allowed unused args must match /^_/u
): MachineSnapshot<
TContext,
TEvent,
Expand All @@ -379,16 +372,30 @@
);

if (typeof context === 'function') {
const assignment = ({ spawn, event, self }: any) =>
context({ spawn, input: event.input, self });
return resolveActionsAndContext(
const children = {};
const spawn = createSpawner(actorScope, preInitial, initEvent, children);
const resolvedContext = context({
spawn,
input: initEvent.input,
self: actorScope.self,
actors: this.implementations.actors
});
const nextState = resolveAndExecuteActionsWithContext(
preInitial,
initEvent,
actorScope,
[assign(assignment)],
internalQueue,
undefined
[]
) as SnapshotFrom<this>;
if (resolvedContext) {
nextState.context = resolvedContext;
}
if (Object.keys(children).length > 0) {
nextState.children = {
...nextState.children,
...children
};
}
return nextState;
}

return preInitial as SnapshotFrom<this>;
Expand Down Expand Up @@ -439,8 +446,7 @@
source: this.root,
reenter: true,
actions: [],
eventType: null as any,
toJSON: null as any // TODO: fix
eventType: null as any
}
],
preInitialState,
Expand All @@ -461,7 +467,7 @@
}

public start(
snapshot: MachineSnapshot<

Check failure on line 470 in packages/core/src/StateMachine.ts

View workflow job for this annotation

GitHub Actions / build

'snapshot' is defined but never used. Allowed unused args must match /^_/u
TContext,
TEvent,
TChildren,
Expand All @@ -472,13 +478,14 @@
TConfig
>
): void {
Object.values(snapshot.children as Record<string, AnyActorRef>).forEach(
(child: any) => {
if (child.getSnapshot().status === 'active') {
child.start();
}
}
);
// if (snapshot.children)
// Object.values(snapshot.children as Record<string, AnyActorRef>).forEach(
// (child: any) => {
// if (child.getSnapshot().status === 'active') {
// child.start();
// }
// }
// );
}

public getStateNodeById(stateId: string): StateNode<TContext, TEvent> {
Expand Down
Loading