Skip to content

Commit

Permalink
Remove State['event'] (#4062)
Browse files Browse the repository at this point in the history
* Remove `State['event']`

* Create stale-chairs-rush.md
  • Loading branch information
Andarist committed Jun 13, 2023
1 parent eb7c8b3 commit 28603a0
Show file tree
Hide file tree
Showing 21 changed files with 177 additions and 229 deletions.
5 changes: 5 additions & 0 deletions .changeset/stale-chairs-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"xstate": major
---

Removed `State['event']`.
9 changes: 1 addition & 8 deletions packages/core/src/State.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import isDevelopment from '#is-development';
import { createInitEvent } from './actions.ts';
import { memo } from './memo.ts';
import type { StateNode } from './StateNode.ts';
import {
Expand Down Expand Up @@ -31,7 +30,7 @@ export function isStateConfig<
return false;
}

return 'value' in state && 'event' in state;
return 'value' in state;
}

/**
Expand All @@ -56,7 +55,6 @@ export class State<
public output: any; // TODO: add an explicit type for `output`
public context: TContext;
public historyValue: Readonly<HistoryValue<TContext, TEvent>> = {};
public event: TEvent;
public _internalQueue: Array<TEvent>;
public _initial: boolean = false;
/**
Expand Down Expand Up @@ -99,7 +97,6 @@ export class State<
{
value: stateValue.value,
context,
event: stateValue.event,
meta: {},
configuration: [], // TODO: fix,
transitions: [],
Expand All @@ -112,8 +109,6 @@ export class State<
return stateValue;
}

const event = createInitEvent({}) as unknown as TEvent; // TODO: fix

const configuration = getConfiguration(
getStateNodes(machine.root, stateValue)
);
Expand All @@ -122,7 +117,6 @@ export class State<
{
value: stateValue,
context,
event,
meta: undefined,
configuration: Array.from(configuration),
transitions: [],
Expand All @@ -143,7 +137,6 @@ export class State<
) {
this.context = config.context;
this._internalQueue = config._internalQueue ?? [];
this.event = config.event;
this.historyValue = config.historyValue || {};
this.matches = this.matches.bind(this);
this.toStrings = this.toStrings.bind(this);
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/StateMachine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ export class StateMachine<
this.createState({
value: {}, // TODO: this is computed in state constructor
context,
event: createInitEvent({}) as unknown as TEvent,
meta: undefined,
configuration: config,
transitions: [],
Expand Down
47 changes: 17 additions & 30 deletions packages/core/src/stateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1040,7 +1040,6 @@ export function microstep<

if (!currentState._initial && !willTransition) {
const inertState = cloneState(currentState, {
event,
transitions: []
});

Expand Down Expand Up @@ -1113,6 +1112,7 @@ function microstepProcedure(

// Enter states
enterStates(
event,
filteredTransitions,
mutConfiguration,
actions,
Expand Down Expand Up @@ -1152,7 +1152,6 @@ function microstepProcedure(
historyValue,
_internalQueue: internalQueue,
context: nextState.context,
event,
done,
output,
children: nextState.children
Expand All @@ -1167,6 +1166,7 @@ function microstepProcedure(
}

function enterStates(
event: AnyEventObject,
filteredTransitions: AnyTransitionDefinition[],
mutConfiguration: Set<AnyStateNode>,
actions: BaseActionObject[],
Expand Down Expand Up @@ -1218,11 +1218,7 @@ function enterStates(
done(
parent!.id,
stateNodeToEnter.output
? mapContext(
stateNodeToEnter.output,
currentState.context,
currentState.event
)
? mapContext(stateNodeToEnter.output, currentState.context, event)
: undefined
)
);
Expand Down Expand Up @@ -1535,18 +1531,20 @@ export function macrostep(
};
}

let nextEvent = event;

// Assume the state is at rest (no raised events)
// Determine the next state based on the next microstep
if (event.type !== actionTypes.init) {
const transitions = selectTransitions(event, nextState);
nextState = microstep(transitions, state, actorCtx, event);
if (nextEvent.type !== actionTypes.init) {
const transitions = selectTransitions(nextEvent, nextState);
nextState = microstep(transitions, state, actorCtx, nextEvent);
states.push(nextState);
}

while (!nextState.done) {
let enabledTransitions = selectEventlessTransitions(nextState);
let enabledTransitions = selectEventlessTransitions(nextState, nextEvent);

if (enabledTransitions.length === 0) {
if (!enabledTransitions.length) {
// TODO: this is a bit of a hack, we need to review this
// this matches the behavior from v4 for eventless transitions
// where for `hasAlwaysTransitions` we were always trying to resolve with a NULL event
Expand All @@ -1559,30 +1557,23 @@ export function macrostep(
if (!nextState._internalQueue.length) {
break;
} else {
const nextEvent = nextState._internalQueue[0];
nextEvent = nextState._internalQueue[0];
const transitions = selectTransitions(nextEvent, nextState);
nextState = microstep(transitions, nextState, actorCtx, nextEvent);
nextState._internalQueue.shift();

states.push(nextState);
}
}

if (enabledTransitions.length) {
nextState = microstep(
enabledTransitions,
nextState,
actorCtx,
nextState.event
);
} else {
nextState = microstep(enabledTransitions, nextState, actorCtx, nextEvent);

states.push(nextState);
}
}

if (nextState.done) {
// Perform the stop step to ensure that child actors are stopped
stopStep(nextState.event, nextState, actorCtx);
stopStep(nextEvent, nextState, actorCtx);
}

return {
Expand Down Expand Up @@ -1619,7 +1610,8 @@ function selectTransitions(
}

function selectEventlessTransitions(
nextState: AnyState
nextState: AnyState,
event: AnyEventObject
): AnyTransitionDefinition[] {
const enabledTransitionSet: Set<AnyTransitionDefinition> = new Set();
const atomicStates = nextState.configuration.filter(isAtomicStateNode);
Expand All @@ -1634,12 +1626,7 @@ function selectEventlessTransitions(
for (const transition of s.always) {
if (
transition.guard === undefined ||
evaluateGuard(
transition.guard,
nextState.context,
nextState.event,
nextState
)
evaluateGuard(transition.guard, nextState.context, event, nextState)
) {
enabledTransitionSet.add(transition);
break loop;
Expand Down
3 changes: 1 addition & 2 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1506,7 +1506,6 @@ export interface StateConfig<
> {
value: StateValue;
context: TContext;
event: TEvent;
historyValue?: HistoryValue<TContext, TEvent>;
meta?: any;
configuration?: Array<StateNode<TContext, TEvent>>;
Expand Down Expand Up @@ -1899,7 +1898,7 @@ export type AnyActorSystem = ActorSystem<any>;

export type PersistedMachineState<TState extends AnyState> = Pick<
TState,
'value' | 'output' | 'context' | 'event' | 'done' | 'historyValue'
'value' | 'output' | 'context' | 'done' | 'historyValue'
> & {
children: {
[K in keyof TState['children']]: {
Expand Down
1 change: 0 additions & 1 deletion packages/core/test/actionCreators.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ describe('action creators', () => {
state: machine.createState({
context: { delay: 100 },
value: {},
event: {} as any,
transitions: [],
children: {}
}) as any, // TODO: fix
Expand Down
36 changes: 5 additions & 31 deletions packages/core/test/invoke.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { interval, of } from 'rxjs';
import { map, take } from 'rxjs/operators';
import {
actionTypes,
doneInvoke,
escalate,
forwardTo,
raise,
sendTo
} from '../src/actions.ts';
import { escalate, forwardTo, raise, sendTo } from '../src/actions.ts';
import {
fromCallback,
fromEventObservable,
Expand Down Expand Up @@ -1805,7 +1798,7 @@ describe('invoke', () => {
interpret(machine).start();
});

describe('sub invoke race condition', () => {
describe('sub invoke race condition ends on the completed state', () => {
const anotherChildMachine = createMachine({
id: 'child',
initial: 'start',
Expand Down Expand Up @@ -1841,29 +1834,10 @@ describe('invoke', () => {
}
});

it('ends on the completed state', (done) => {
const events: EventObject[] = [];
let state: any;
const service = interpret(anotherParentMachine);
service.subscribe((s) => {
state = s;
events.push(s.event);
});
service.subscribe({
complete: () => {
expect(events.map((e) => e.type)).toEqual([
actionTypes.init,
'STOPCHILD',
doneInvoke('invoked.child').type
]);
expect(state.value).toEqual('completed');
done();
}
});
service.start();
const actorRef = interpret(anotherParentMachine).start();
actorRef.send({ type: 'STOPCHILD' });

service.send({ type: 'STOPCHILD' });
});
expect(actorRef.getSnapshot().value).toEqual('completed');
});
});

Expand Down
10 changes: 4 additions & 6 deletions packages/core/test/scxml.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,9 +369,9 @@ async function runW3TestToCompletion(machine: AnyStateMachine): Promise<void> {
} else {
reject(
new Error(
`Reached "fail" state with event ${JSON.stringify(
nextState.event
)} from state ${JSON.stringify(prevState?.value)}`
`Reached "fail" state from state ${JSON.stringify(
prevState?.value
)}`
)
);
}
Expand Down Expand Up @@ -405,9 +405,7 @@ async function runTestToCompletion(
complete: () => {
if (nextState.value === 'fail') {
throw new Error(
`Reached "fail" state with event ${JSON.stringify(
nextState.event
)} from state ${JSON.stringify(prevState?.value)}`
`Reached "fail" state from state ${JSON.stringify(prevState?.value)}`
);
}
done = true;
Expand Down
35 changes: 0 additions & 35 deletions packages/core/test/state.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createMachine, interpret } from '../src/index';
import { initEvent } from '../src/actions';
import { assign } from '../src/actions/assign';
import { fromCallback } from '../src/actors/callback';

Expand Down Expand Up @@ -384,40 +383,6 @@ describe('State', () => {
});
});

describe('.event', () => {
it('the .event prop should be the event (string) that caused the transition', () => {
const actorRef = interpret(exampleMachine).start();

actorRef.send({
type: 'TO_TWO',
foo: 'test'
});

expect(actorRef.getSnapshot().event).toEqual({
type: 'TO_TWO',
foo: 'test'
});
});

it('the .event prop should be the event (object) that caused the transition', () => {
const actorRef = interpret(exampleMachine).start();

actorRef.send({
type: 'TO_TWO',
foo: 'bar'
});

expect(actorRef.getSnapshot().event).toEqual({
type: 'TO_TWO',
foo: 'bar'
});
});

it('the .event prop should be the initial event for the initial state', () => {
expect(interpret(exampleMachine).getSnapshot().event).toEqual(initEvent);
});
});

describe('.transitions', () => {
it('should have no transitions for the initial state', () => {
expect(interpret(exampleMachine).getSnapshot().transitions).toHaveLength(
Expand Down
4 changes: 3 additions & 1 deletion packages/xstate-analytics/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ export function createAnalyzer(
const stateSerial = serializeState(state);
const prevState = currentState;
const prevStateSerial = serializeState(prevState);
const eventSerial = JSON.stringify(state.event);
const eventSerial = JSON.stringify({
type: 'string' // TODO: replace with real event when we land on the new inspection API
});

analysis.count++;

Expand Down
3 changes: 2 additions & 1 deletion packages/xstate-analytics/test/analytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ const lightMachine = createMachine({
});

describe('@xstate/analytics', () => {
it('analyzes transition counts', () => {
// TODO: re-enable when we land on the new inspection API
it.skip('analyzes transition counts', () => {
let analysis: any = {};

const service = interpret(lightMachine);
Expand Down
6 changes: 0 additions & 6 deletions packages/xstate-inspect/src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,6 @@ export function inspect(options?: InspectorOptions): Inspector | undefined {
parent: (service._parent as AnyInterpreter)?.sessionId
});

inspectService.send({
type: 'service.event',
event: stringifyWithSerializer(state.event),
sessionId: service.sessionId
});

if (!patchedInterpreters.has(service)) {
patchedInterpreters.add(service);

Expand Down
2 changes: 1 addition & 1 deletion packages/xstate-inspect/src/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function stringifyState(state: AnyState, replacer?: Replacer): string {
state;
return selectivelyStringify(
{ ...stateToStringify, tags: Array.from(tags) },
['context', 'event'],
['context'],
replacer
);
}
Expand Down
Loading

0 comments on commit 28603a0

Please sign in to comment.