Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] Enqueue all the things #4875

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,16 +181,16 @@ Read [📽 the slides](http://slides.com/davidkhourshid/finite-state-machines) (

## Packages

| Package | Description |
| --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| 🤖 `xstate` | Core finite state machine and statecharts library + interpreter |
| [📉 `@xstate/graph`](https://github.com/statelyai/xstate/tree/main/packages/xstate-graph) | Graph traversal and model-based testing utilities using XState |
| [⚛️ `@xstate/react`](https://github.com/statelyai/xstate/tree/main/packages/xstate-react) | React hooks and utilities for using XState in React applications |
| [💚 `@xstate/vue`](https://github.com/statelyai/xstate/tree/main/packages/xstate-vue) | Vue composition functions and utilities for using XState in Vue applications |
| [🎷 `@xstate/svelte`](https://github.com/statelyai/xstate/tree/main/packages/xstate-svelte) | Svelte utilities for using XState in Svelte applications |
| [🥏 `@xstate/solid`](https://github.com/statelyai/xstate/tree/main/packages/xstate-solid) | Solid hooks and utilities for using XState in Solid applications |
| [🔍 `@statelyai/inspect`](https://github.com/statelyai/inspect) | Inspection utilities for XState |
| [🏪 `@xstate/store`](https://github.com/statelyai/xstate/tree/main/packages/xstate-store) | Small library for simple state management |
| Package | Description |
| ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| 🤖 `xstate` | Core finite state machine and statecharts library + interpreter |
| [📉 `@xstate/graph`](https://github.com/statelyai/xstate/tree/main/packages/xstate-graph) | Graph traversal and model-based testing utilities using XState |
| [⚛️ `@xstate/react`](https://github.com/statelyai/xstate/tree/main/packages/xstate-react) | React hooks and utilities for using XState in React applications |
| [💚 `@xstate/vue`](https://github.com/statelyai/xstate/tree/main/packages/xstate-vue) | Vue composition functions and utilities for using XState in Vue applications |
| [🎷 `@xstate/svelte`](https://github.com/statelyai/xstate/tree/main/packages/xstate-svelte) | Svelte utilities for using XState in Svelte applications |
| [🥏 `@xstate/solid`](https://github.com/statelyai/xstate/tree/main/packages/xstate-solid) | Solid hooks and utilities for using XState in Solid applications |
| [🔍 `@statelyai/inspect`](https://github.com/statelyai/inspect) | Inspection utilities for XState |
| [🏪 `@xstate/store`](https://github.com/statelyai/xstate/tree/main/packages/xstate-store) | Small library for simple state management |

## Finite State Machines

Expand Down
23 changes: 12 additions & 11 deletions packages/core/src/actions/spawnChild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,17 +172,18 @@ type SpawnArguments<
TExpressionEvent extends EventObject,
TEvent extends EventObject,
TActor extends ProvidedActor
> = IsLiteralString<TActor['src']> extends true
? DistributeActors<TContext, TExpressionEvent, TEvent, TActor>
: [
src: string | AnyActorLogic,
options?: {
id?: ResolvableActorId<TContext, TExpressionEvent, TEvent, string>;
systemId?: string;
input?: unknown;
syncSnapshot?: boolean;
}
];
> =
IsLiteralString<TActor['src']> extends true
? DistributeActors<TContext, TExpressionEvent, TEvent, TActor>
: [
src: string | AnyActorLogic,
options?: {
id?: ResolvableActorId<TContext, TExpressionEvent, TEvent, string>;
systemId?: string;
input?: unknown;
syncSnapshot?: boolean;
}
];

export function spawnChild<
TContext extends MachineContext,
Expand Down
6 changes: 1 addition & 5 deletions packages/core/src/actors/transition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,7 @@ export function fromTransition<
transition: (snapshot, event, actorScope) => {
return {
...snapshot,
context: transition(
snapshot.context,
event,
actorScope as any
)
context: transition(snapshot.context, event, actorScope as any)
};
},
getInitialSnapshot: (_, input) => {
Expand Down
16 changes: 8 additions & 8 deletions packages/core/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export function setup<
TEvent extends AnyEventObject, // TODO: consider using a stricter `EventObject` here
TActors extends Record<string, UnknownActorLogic> = {},
TChildrenMap extends Record<string, string> = {},
TActions extends Record<
TActionParams extends Record<
string,
ParameterizedObject['params'] | undefined
> = {},
Expand Down Expand Up @@ -115,13 +115,13 @@ export function setup<
: never;
};
actions?: {
[K in keyof TActions]: ActionFunction<
[K in keyof TActionParams]: ActionFunction<
TContext,
TEvent, // Expression event
TEvent,
TEvent,
TActions[K],
TActionParams[K],
ToProvidedActor<TChildrenMap, TActors>,
ToParameterizedObject<TActions>,
ToParameterizedObject<TActionParams>,
ToParameterizedObject<TGuards>,
TDelay,
TEmitted
Expand All @@ -139,7 +139,7 @@ export function setup<
[K in TDelay]: DelayConfig<
TContext,
TEvent,
ToParameterizedObject<TActions>['params'],
ToParameterizedObject<TActionParams>['params'],
TEvent
>;
};
Expand All @@ -151,7 +151,7 @@ export function setup<
TContext,
TEvent,
ToProvidedActor<TChildrenMap, TActors>,
ToParameterizedObject<TActions>,
ToParameterizedObject<TActionParams>,
ToParameterizedObject<TGuards>,
TDelay,
TTag,
Expand All @@ -170,7 +170,7 @@ export function setup<
Record<string, AnyActorRef | undefined>
>,
ToProvidedActor<TChildrenMap, TActors>,
ToParameterizedObject<TActions>,
ToParameterizedObject<TActionParams>,
ToParameterizedObject<TGuards>,
TDelay,
ToStateValue<TConfig>,
Expand Down
54 changes: 51 additions & 3 deletions packages/core/src/stateUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import isDevelopment from '#is-development';
import { MachineSnapshot, cloneMachineSnapshot } from './State.ts';
import type { StateNode } from './StateNode.ts';
import { raise } from './actions.ts';
import { assign, raise, sendTo } from './actions.ts';
import { createAfterEvent, createDoneStateEvent } from './eventUtils.ts';
import { cancel } from './actions/cancel.ts';
import { spawnChild } from './actions/spawnChild.ts';
Expand Down Expand Up @@ -37,7 +37,9 @@
ActionFunction,
AnyTransitionConfig,
ProvidedActor,
AnyActorScope
AnyActorScope,
ActionFunctionEnqueuer,
AnyActorRef

Check failure on line 42 in packages/core/src/stateUtils.ts

View workflow job for this annotation

GitHub Actions / build

'AnyActorRef' is defined but never used. Allowed unused vars must match /^_/u
} from './types.ts';
import {
resolveOutput,
Expand Down Expand Up @@ -1550,17 +1552,63 @@
params: actionParams
}
});
const actions: UnknownAction[] = [];
const enq: ActionFunctionEnqueuer<
any,
any,
any,
any,
any,
any,
any,
any
> = {
assign: (...args) => {
actions.push(assign(...args) as UnknownAction);
},
action: (actionFn) => {
actions.push(actionFn);
},
raise: (...args) => {
actions.push(raise(...args) as UnknownAction);
},
sendTo: (...args) => {
actions.push(sendTo(...args) as UnknownAction);
},
check: (guard) =>
evaluateGuard(
guard,
intermediateSnapshot.context,
event,
intermediateSnapshot
)
};
try {
executingCustomAction = resolvedAction;
resolvedAction(actionArgs, actionParams);
resolvedAction(actionArgs, actionParams, enq);
} finally {
executingCustomAction = false;
}

if (actions.length) {
intermediateSnapshot = resolveAndExecuteActionsWithContext(
intermediateSnapshot,
event,
actorScope,
actions,
extra,
retries
);

return intermediateSnapshot;
}
}

if (!('resolve' in resolvedAction)) {
if (actorScope.self._processingStatus === ProcessingStatus.Running) {
executeAction();
} else if (resolvedAction.length === 3) {
executeAction();
} else {
actorScope.defer(() => {
executeAction();
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ export function createSystem<T extends ActorSystemInfo>(
...event,
rootId: rootActor.sessionId
};
inspectionObservers.forEach(
(observer) => observer.next?.(resolvedInspectionEvent)
inspectionObservers.forEach((observer) =>
observer.next?.(resolvedInspectionEvent)
);
};

Expand Down
69 changes: 67 additions & 2 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import type { MachineSnapshot } from './State.ts';
import type { StateMachine } from './StateMachine.ts';
import type { StateNode } from './StateNode.ts';
import { AssignArgs } from './actions/assign.ts';
import { AssignArgs, assign } from './actions/assign.ts';
import { PromiseActorLogic } from './actors/promise.ts';
import { Guard, GuardPredicate, UnknownGuard } from './guards.ts';
import type { Actor, ProcessingStatus } from './createActor.ts';
import { Spawner } from './spawn.ts';
import { AnyActorSystem, Clock } from './system.js';
import { InspectionEvent } from './inspection.ts';
import type { raise, sendTo } from './actions.ts';

export type Identity<T> = { [K in keyof T]: T[K] };

Expand Down Expand Up @@ -169,6 +170,57 @@
? (TSnapshot & { status: 'done' })['output']
: never;

export interface ActionFunctionEnqueuer<
TContext extends MachineContext,
TExpressionEvent extends EventObject,
TEvent extends EventObject,
TActor extends ProvidedActor,

Check failure on line 177 in packages/core/src/types.ts

View workflow job for this annotation

GitHub Actions / build

'TActor' is defined but never used. Allowed unused vars must match /^_/u
TAction extends ParameterizedObject,
TGuard extends ParameterizedObject,
TDelay extends string,
TEmitted extends EventObject

Check failure on line 181 in packages/core/src/types.ts

View workflow job for this annotation

GitHub Actions / build

'TEmitted' is defined but never used. Allowed unused vars must match /^_/u
> {
assign: (
...args: Parameters<
typeof assign<TContext, TExpressionEvent, any, TEvent, any>
>
) => void;
raise: (
...args: Parameters<
typeof raise<
TContext,
TExpressionEvent,
TEvent,
undefined,
TDelay,
TDelay
>
>
) => void;
action: (
actionFn:
| NoRequiredParams<TAction>
| WithDynamicParams<TContext, TExpressionEvent, TAction>
| ((args: ActionArgs<TContext, TExpressionEvent, TEvent>) => void)
) => void;
check: (
guard: Guard<TContext, TExpressionEvent, undefined, TGuard>
) => boolean;
sendTo: <TTargetActor extends AnyActorRef>(
...args: Parameters<
typeof sendTo<
TContext,
TExpressionEvent,
undefined,
TTargetActor,
TEvent,
TDelay,
TDelay
>
>
) => void;
}

export type ActionFunction<
TContext extends MachineContext,
TExpressionEvent extends EventObject,
Expand All @@ -180,7 +232,20 @@
TDelay extends string,
TEmitted extends EventObject
> = {
(args: ActionArgs<TContext, TExpressionEvent, TEvent>, params: TParams): void;
(
args: ActionArgs<TContext, TExpressionEvent, TEvent>,
params: TParams,
enqueue: ActionFunctionEnqueuer<
TContext,
TExpressionEvent,
TEvent,
TActor,
TAction,
TGuard,
TDelay,
TEmitted
>
): void;
_out_TEvent?: TEvent; // TODO: it feels like we should be able to remove this since now `TEvent` is "observable" by `self`
_out_TActor?: TActor;
_out_TAction?: TAction;
Expand Down
Loading
Loading