Skip to content

Commit

Permalink
Refactor how builtin actions are structured and how all actions are s…
Browse files Browse the repository at this point in the history
…tored and resolved (#4127)

* Refactor builtin actions in order to remove the fake callable signature

* Declassify the builtin actions

* Fix and cleanup types

* add extra type tests to raise

* Provide `action` to action implementations again

* Bring back .type for builtins

* Convert string action to an object form when creating action args

* Temporarily serialize~ actions in machine definition to pass JSON schema test

* Fixed `.after` cancellation

* Hoist `toSerializableActon`

* add changeset

* Remove outdated comment
  • Loading branch information
Andarist committed Jul 10, 2023
1 parent d860f8e commit cdaddc2
Show file tree
Hide file tree
Showing 39 changed files with 1,197 additions and 1,603 deletions.
17 changes: 17 additions & 0 deletions .changeset/chatty-parrots-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'xstate': major
---

IDs for delayed events are no longer derived from event types so this won't work automatically:

```ts
entry: raise({ type: 'TIMER' }, { delay: 200 });
exit: cancel('TIMER');
```

Please use explicit IDs:

```ts
entry: raise({ type: 'TIMER' }, { delay: 200, id: 'myTimer' });
exit: cancel('myTimer');
```
5 changes: 5 additions & 0 deletions .changeset/forty-apples-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'xstate': major
---

All builtin action creators (`assign`, `sendTo`, etc) are now returning _functions_. They exact shape of those is considered an implementation detail of XState and users are meant to only pass around the returned values.
42 changes: 0 additions & 42 deletions packages/core/actions/dynamicAction.ts

This file was deleted.

6 changes: 3 additions & 3 deletions packages/core/src/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type {
StateConfig,
StateValue
} from './types.ts';
import { flatten, isString, matchesState } from './utils.ts';
import { flatten, matchesState } from './utils.ts';

export function isStateConfig<
TContext extends MachineContext,
Expand Down Expand Up @@ -141,7 +141,7 @@ export class State<
* @param delimiter The character(s) that separate each subpath in the string state node path.
*/
public toStrings(stateValue: StateValue = this.value): string[] {
if (isString(stateValue)) {
if (typeof stateValue === 'string') {
return [stateValue];
}
const valueKeys = Object.keys(stateValue);
Expand Down Expand Up @@ -218,7 +218,7 @@ export class State<
});
}

public get meta() {
public get meta(): Record<string, any> {
return this.configuration.reduce((acc, stateNode) => {
if (stateNode.meta !== undefined) {
acc[stateNode.id] = stateNode.meta;
Expand Down
113 changes: 64 additions & 49 deletions packages/core/src/StateNode.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,61 @@
import type { State } from './State.ts';
import type { StateMachine } from './StateMachine.ts';
import * as actionTypes from './constantPrefixes.ts';
import { NULL_EVENT, STATE_DELIMITER } from './constants.ts';
import { evaluateGuard } from './guards.ts';
import { memo } from './memo.ts';
import {
mapValues,
flatten,
toArray,
isString,
toInvokeConfig,
toTransitionConfigArray,
createInvokeId
} from './utils.ts';
formatInitialTransition,
formatTransition,
formatTransitions,
getCandidates,
getDelayedTransitions
} from './stateUtils.ts';
import type {
EventObject,
HistoryStateNodeConfig,
StateNodeDefinition,
TransitionDefinition,
Action,
AnyActorLogic,
DelayedTransitionDefinition,
StateNodeConfig,
StatesDefinition,
StateNodesConfig,
EventObject,
FinalStateNodeConfig,
HistoryStateNodeConfig,
InitialTransitionDefinition,
InvokeDefinition,
MachineContext,
Mapper,
PropertyMapper,
TransitionDefinitionMap,
InitialTransitionDefinition,
MachineContext,
BaseActionObject,
AnyActorLogic
StateNodeConfig,
StateNodeDefinition,
StateNodesConfig,
StatesDefinition,
TransitionDefinition,
TransitionDefinitionMap
} from './types.ts';
import type { State } from './State.ts';
import * as actionTypes from './actionTypes.ts';
import { toActionObjects } from './actions.ts';
import { formatInitialTransition, formatTransition } from './stateUtils.ts';
import {
getDelayedTransitions,
formatTransitions,
getCandidates
} from './stateUtils.ts';
import { evaluateGuard } from './guards.ts';
import type { StateMachine } from './StateMachine.ts';
import { memo } from './memo.ts';
import { NULL_EVENT, STATE_DELIMITER } from './constants.ts';
createInvokeId,
flatten,
mapValues,
toArray,
toInvokeConfig,
toTransitionConfigArray
} from './utils.ts';

const EMPTY_OBJECT = {};

const toSerializableActon = (action: Action<any, any, any>) => {
if (typeof action === 'string') {
return { type: action };
}
if (typeof action === 'function') {
if ('resolve' in action) {
return { type: (action as any).type };
}
return {
type: action.name
};
}
return action;
};

interface StateNodeOptions<
TContext extends MachineContext,
TEvent extends EventObject
Expand Down Expand Up @@ -91,11 +105,11 @@ export class StateNode<
/**
* The action(s) to be executed upon entering the state node.
*/
public entry: BaseActionObject[];
public entry: Action<any, any, any>[];
/**
* The action(s) to be executed upon exiting the state node.
*/
public exit: BaseActionObject[];
public exit: Action<any, any, any>[];
/**
* The parent state node.
*/
Expand Down Expand Up @@ -180,8 +194,8 @@ export class StateNode<
this.history =
this.config.history === true ? 'shallow' : this.config.history || false;

this.entry = toActionObjects(this.config.entry);
this.exit = toActionObjects(this.config.exit);
this.entry = toArray(this.config.entry);
this.exit = toArray(this.config.exit);

this.meta = this.config.meta;
this.output =
Expand Down Expand Up @@ -217,13 +231,13 @@ export class StateNode<
? {
target: this.initial.target,
source: this,
actions: this.initial.actions,
actions: this.initial.actions.map(toSerializableActon),
eventType: null as any,
reenter: false,
toJSON: () => ({
target: this.initial!.target!.map((t) => `#${t.id}`),
source: `#${this.id}`,
actions: this.initial!.actions,
actions: this.initial!.actions.map(toSerializableActon),
eventType: null as any
})
}
Expand All @@ -233,9 +247,12 @@ export class StateNode<
return state.definition;
}) as StatesDefinition<TContext, TEvent>,
on: this.on,
transitions: [...this.transitions.values()].flat(),
entry: this.entry,
exit: this.exit,
transitions: [...this.transitions.values()].flat().map((t) => ({
...t,
actions: t.actions.map(toSerializableActon)
})),
entry: this.entry.map(toSerializableActon),
exit: this.exit.map(toSerializableActon),
meta: this.meta,
order: this.order || -1,
output: this.output,
Expand All @@ -261,11 +278,9 @@ export class StateNode<
const src = invokeConfig.src as string | AnyActorLogic;
const { systemId } = invokeConfig;

const resolvedSrc = isString(src)
? src
: !('type' in src)
? resolvedId
: src;
// TODO: resolving should not happen here
const resolvedSrc =
typeof src === 'string' ? src : !('type' in src) ? resolvedId : src;

if (
!this.machine.implementations.actors[resolvedId] &&
Expand All @@ -280,7 +295,7 @@ export class StateNode<
}

return {
type: actionTypes.invoke,
type: 'xstate.invoke',
...invokeConfig,
src: resolvedSrc,
id: resolvedId,
Expand All @@ -289,7 +304,7 @@ export class StateNode<
const { onDone, onError, ...invokeDefValues } = invokeConfig;
return {
...invokeDefValues,
type: actionTypes.invoke,
type: 'xstate.invoke',
src: resolvedSrc,
id: resolvedId
};
Expand Down Expand Up @@ -331,7 +346,7 @@ export class StateNode<
event: TEvent
): TransitionDefinition<TContext, TEvent>[] | undefined {
const eventType = event.type;
const actions: BaseActionObject[] = [];
const actions: Action<any, any, any>[] = [];

let selectedTransition: TransitionDefinition<TContext, TEvent> | undefined;

Expand Down
18 changes: 0 additions & 18 deletions packages/core/src/actionTypes.ts

This file was deleted.

Loading

0 comments on commit cdaddc2

Please sign in to comment.