Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: statelyai/xstate
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: bb54418f45d88d1be40da15468bb15f862e48950
Choose a base ref
..
head repository: statelyai/xstate
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4b669066725441303fd458cde4fc52f522335d63
Choose a head ref
5 changes: 5 additions & 0 deletions .changeset/few-monkeys-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'xstate': minor
---

`State.from`, `StateMachine#createState` and `StateMachine#resolveStateValue` were removed. They largely served the same purpose as `StateMachine#resolveState` and this is the method that is still available and can be used instead of them.
3 changes: 3 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
@@ -60,6 +60,7 @@
"five-queens-behave",
"five-ravens-own",
"flat-clouds-greet",
"flat-jokes-breathe",
"flat-oranges-bathe",
"forty-apples-argue",
"fresh-garlics-fry",
@@ -71,6 +72,7 @@
"giant-moons-glow",
"gold-buses-thank",
"good-comics-collect",
"good-masks-play",
"great-kangaroos-confess",
"green-brooms-laugh",
"green-fishes-shave",
@@ -159,6 +161,7 @@
"shiny-apes-press",
"shy-cobras-ring",
"shy-gifts-shake",
"shy-poets-sleep",
"shy-walls-develop",
"silly-chefs-kiss",
"silly-chefs-tickle",
10 changes: 10 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# xstate

## 5.0.0-beta.41

### Major Changes

- [#4423](https://github.com/statelyai/xstate/pull/4423) [`8fb984494`](https://github.com/statelyai/xstate/commit/8fb98449471a67ad4231c2ce18d88d511b1112f8) Thanks [@Andarist](https://github.com/Andarist)! - Removed `Interpreter['status']` from publicly available properties.

### Minor Changes

- [#4435](https://github.com/statelyai/xstate/pull/4435) [`37d879335`](https://github.com/statelyai/xstate/commit/37d879335c3c9ad1c28533bef4768ed0411fa0e8) Thanks [@davidkpiano](https://github.com/davidkpiano)! - The default `timeout` for `waitFor(...)` is now `Infinity` instead of 10 seconds.

## 5.0.0-beta.40

### Minor Changes
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "xstate",
"version": "5.0.0-beta.40",
"version": "5.0.0-beta.41",
"description": "Finite State Machines and Statecharts for the Modern Web.",
"main": "dist/xstate.cjs.js",
"module": "dist/xstate.esm.js",
31 changes: 21 additions & 10 deletions packages/core/src/StateMachine.ts
Original file line number Diff line number Diff line change
@@ -45,7 +45,8 @@ import type {
TODO,
SnapshotFrom,
Snapshot,
AnyActorLogic
AnyActorLogic,
HistoryValue
} from './types.ts';
import { isErrorActorEvent, resolveReferencedActor } from './utils.ts';
import { $$ACTOR_TYPE, createActor } from './interpreter.ts';
@@ -247,11 +248,17 @@ export class StateMachine<
});
}

public resolveStateValue(
stateValue: StateValue,
...[context]: Equals<TContext, MachineContext> extends true
? []
: [TContext]
public resolveState(
config: {
value: StateValue;
context?: TContext;
historyValue?: HistoryValue<TContext, TEvent>;
status?: 'active' | 'done' | 'error' | 'stopped';
output?: TOutput;
error?: unknown;
} & (Equals<TContext, MachineContext> extends false
? { context: unknown }
: {})
): MachineSnapshot<
TContext,
TEvent,
@@ -260,17 +267,22 @@ export class StateMachine<
TOutput,
TResolvedTypesMeta
> {
const resolvedStateValue = resolveStateValue(this.root, stateValue);
const resolvedStateValue = resolveStateValue(this.root, config.value);
const configurationSet = getConfiguration(
getStateNodes(this.root, resolvedStateValue)
);

return new State(
{
configuration: [...configurationSet],
context: (context || {}) as TContext,
context: config.context || ({} as TContext),
children: {},
status: isInFinalState(configurationSet, this.root) ? 'done' : 'active'
status: isInFinalState(configurationSet, this.root)
? 'done'
: config.status || 'active',
output: config.output,
error: config.error,
historyValue: config.historyValue
},
this
) as MachineSnapshot<
@@ -385,7 +397,6 @@ export class StateMachine<
{
context:
typeof context !== 'function' && context ? context : ({} as TContext),
meta: undefined,
configuration: [this.root],
children: {},
status: 'active'
12 changes: 12 additions & 0 deletions packages/core/src/interpreter.ts
Original file line number Diff line number Diff line change
@@ -598,6 +598,18 @@ export class Actor<TLogic extends AnyActorLogic>
};
}

/**
* Obtain the internal state of the actor, which can be persisted.
*
* @remarks
* The internal state can be persisted from any actor, not only machines.
*
* Note that the persisted state is not the same as the snapshot from {@link Actor.getSnapshot}. Persisted state represents the internal state of the actor, while snapshots represent the actor's last emitted value.
*
* Can be restored with {@link ActorOptions.state}
*
* @see https://stately.ai/docs/persistence
*/
public getPersistedState(): Snapshot<unknown>;
public getPersistedState(options?: unknown): Snapshot<unknown> {
return this.logic.getPersistedState(this._state, options);
113 changes: 109 additions & 4 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
@@ -1657,19 +1657,39 @@ export interface StateConfig<
> {
context: TContext;
historyValue?: HistoryValue<TContext, TEvent>;
meta?: any;
configuration: Array<StateNode<TContext, TEvent>>;
children: Record<string, ActorRef<any, any>>;
status: 'active' | 'done' | 'error' | 'stopped';
output?: any;
error?: unknown;
tags?: Set<string>;
machine?: StateMachine<TContext, TEvent, any, any, any, any, any, any, any>;
}

export interface ActorOptions<TLogic extends AnyActorLogic> {
/**
* The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
*
* @remarks
* You can create your own “clock”. The clock interface is an object with two functions/methods:
*
* - `setTimeout` - same arguments as `window.setTimeout(fn, timeout)`
* - `clearTimeout` - same arguments as `window.clearTimeout(id)`
*
* By default, the native `setTimeout` and `clearTimeout` functions are used.
*
* For testing, XState provides `SimulatedClock`.
*
* @see {@link Clock}
* @see {@link SimulatedClock}
*/
clock?: Clock;
/**
* Specifies the logger to be used for log(...) actions. Defaults to the native console.log method.
*/
logger?: (...args: any[]) => void;
/**
* @internal
*/
parent?: ActorRef<any, any>;
/**
* The custom `id` for referencing this service.
@@ -1682,8 +1702,6 @@ export interface ActorOptions<TLogic extends AnyActorLogic> {
*/
devTools?: boolean | DevToolsAdapter; // TODO: add enhancer options

sync?: boolean;

/**
* The system ID to register this actor under
*/
@@ -1693,6 +1711,19 @@ export interface ActorOptions<TLogic extends AnyActorLogic> {
*/
input?: InputFrom<TLogic>;

/**
* Initializes actor logic from a specific persisted internal state.
*
* @remarks
*
* If the state is compatible with the actor logic, when the actor is started it will be at that persisted state.
* Actions from machine actors will not be re-executed, because they are assumed to have been already executed.
* However, invocations will be restarted, and spawned actors will be restored recursively.
*
* Can be generated with {@link Actor.getPersistedState}.
*
* @see https://stately.ai/docs/persistence
*/
// state?:
// | PersistedStateFrom<TActorLogic>
// | InternalStateFrom<TActorLogic>;
@@ -1703,6 +1734,80 @@ export interface ActorOptions<TLogic extends AnyActorLogic> {
*/
src?: string | AnyActorLogic;

/**
* A callback function or observer object which can be used to inspect actor system updates.
*
* @remarks
* If a callback function is provided, it can accept an inspection event argument. The types of inspection events that can be observed include:
*
* - `@xstate.actor` - An actor ref has been created in the system
* - `@xstate.event` - An event was sent from a source actor ref to a target actor ref in the system
* - `@xstate.snapshot` - An actor ref emitted a snapshot due to a received event
*
* @example
* ```ts
* import { createMachine } from 'xstate';
*
* const machine = createMachine({
* // ...
* });
*
* const actor = createActor(machine, {
* inspect: (inspectionEvent) => {
* if (inspectionEvent.actorRef === actor) {
* // This event is for the root actor
* }
*
* if (inspectionEvent.type === '@xstate.actor') {
* console.log(inspectionEvent.actorRef);
* }
*
* if (inspectionEvent.type === '@xstate.event') {
* console.log(inspectionEvent.sourceRef);
* console.log(inspectionEvent.actorRef);
* console.log(inspectionEvent.event);
* }
*
* if (inspectionEvent.type === '@xstate.snapshot') {
* console.log(inspectionEvent.actorRef);
* console.log(inspectionEvent.event);
* console.log(inspectionEvent.snapshot);
* }
* }
* });
* ```
*
* Alternately, an observer object (`{ next?, error?, complete? }`) can be provided:
*
* @example
* ```ts
* const actor = createActor(machine, {
* inspect: {
* next: (inspectionEvent) => {
* if (inspectionEvent.actorRef === actor) {
* // This event is for the root actor
* }
*
* if (inspectionEvent.type === '@xstate.actor') {
* console.log(inspectionEvent.actorRef);
* }
*
* if (inspectionEvent.type === '@xstate.event') {
* console.log(inspectionEvent.sourceRef);
* console.log(inspectionEvent.actorRef);
* console.log(inspectionEvent.event);
* }
*
* if (inspectionEvent.type === '@xstate.snapshot') {
* console.log(inspectionEvent.actorRef);
* console.log(inspectionEvent.event);
* console.log(inspectionEvent.snapshot);
* }
* }
* }
* });
* ```
*/
inspect?:
| Observer<InspectionEvent>
| ((inspectionEvent: InspectionEvent) => void);
2 changes: 1 addition & 1 deletion packages/core/test/assign.test.ts
Original file line number Diff line number Diff line change
@@ -307,7 +307,7 @@ describe('assign meta', () => {
expect(actor.getSnapshot().context.count).toEqual(11);
});

it.only('should provide the action parameters to the partial assigner', () => {
it('should provide the action parameters to the partial assigner', () => {
const machine = createMachine(
{
types: {} as {
22 changes: 11 additions & 11 deletions packages/core/test/deterministic.test.ts
Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API
expect(
lightMachine.transition(
lightMachine.resolveStateValue('green'),
lightMachine.resolveState({ value: 'green' }),
{
type: 'TIMER'
},
@@ -102,7 +102,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API
expect(() =>
lightMachine.transition(
testMachine.resolveStateValue('red'),
testMachine.resolveState({ value: 'red' }),
undefined as any,
actorScope
)
@@ -113,7 +113,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API
expect(
testMachine.transition(
testMachine.resolveStateValue('a'),
testMachine.resolveState({ value: 'a' }),
{ type: 'T' },
actorScope
).value
@@ -126,7 +126,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API
expect(() =>
testMachine.transition(
testMachine.resolveStateValue('fake'),
testMachine.resolveState({ value: 'fake' }),
{ type: 'T' },
actorScope
)
@@ -137,7 +137,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API
expect(() =>
testMachine.transition(
testMachine.resolveStateValue('a.fake'),
testMachine.resolveState({ value: 'a.fake' }),
{
type: 'T'
},
@@ -175,7 +175,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API
expect(
lightMachine.transition(
lightMachine.resolveStateValue({ red: 'walk' }),
lightMachine.resolveState({ value: { red: 'walk' } }),
{ type: 'PED_COUNTDOWN' },
actorScope
).value
@@ -186,7 +186,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API
expect(
lightMachine.transition(
lightMachine.resolveStateValue('red'),
lightMachine.resolveState({ value: 'red' }),
{
type: 'PED_COUNTDOWN'
},
@@ -201,7 +201,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API
expect(
lightMachine.transition(
lightMachine.resolveStateValue('red'),
lightMachine.resolveState({ value: 'red' }),
{
type: 'PED_COUNTDOWN'
},
@@ -216,7 +216,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API
expect(
lightMachine.transition(
lightMachine.resolveStateValue({ red: 'stop' }),
lightMachine.resolveState({ value: { red: 'stop' } }),
{ type: 'TIMER' },
actorScope
).value
@@ -255,7 +255,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API
expect(
lightMachine.transition(
lightMachine.resolveStateValue('yellow'),
lightMachine.resolveState({ value: 'yellow' }),
{
type: 'TIMER'
},
@@ -327,7 +327,7 @@ describe('deterministic machine', () => {
const actorScope = null as any; // TODO: figure out the simulation API

const walkState = lightMachine.transition(
lightMachine.resolveStateValue({ red: 'walk' }),
lightMachine.resolveState({ value: { red: 'walk' } }),
{ type: 'TIMER' },
actorScope
);
Loading