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

feat: state value added to transition type #4043

Merged
merged 6 commits into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions .changeset/rotten-tigers-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@xstate/fsm': patch
---

state value added to transition type
Copy link
Contributor

@with-heart with-heart May 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ksv90! Thanks for making your first contribution to @statelyai ❤️

Changesets generate changelog entries for users so you want to think like a user when writing your changesets.

If you're a user reading a changelog entry, you'd want to know things like:

  • What is the change?
  • Why is the change important?
  • How do I make use of the change?

Your changeset isn't technically wrong, it just doesn't help users understand or get excited about the change that you made here!

24 changes: 14 additions & 10 deletions packages/xstate-fsm/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,18 +182,21 @@ export function createMachine<

if (stateConfig.on) {
const transitions: Array<
StateMachine.Transition<TContext, TEvent>
StateMachine.Transition<TContext, TEvent, TState['value']>
> = toArray(stateConfig.on[eventObject.type]);

for (const transition of transitions) {
if (transition === undefined) {
return createUnchangedState(value, context);
}

const { target, actions = [], cond = () => true } =
typeof transition === 'string'
? { target: transition }
: transition;
const {
target,
actions = [],
cond = () => true
} = typeof transition === 'string'
? { target: transition }
: transition;

const isTargetless = target === undefined;

Expand All @@ -209,11 +212,12 @@ export function createMachine<
}

if (cond(context, eventObject)) {
const allActions = (isTargetless
? toArray(actions)
: ([] as any[])
.concat(stateConfig.exit, actions, nextStateConfig.entry)
.filter((a) => a)
const allActions = (
isTargetless
? toArray(actions)
: ([] as any[])
.concat(stateConfig.exit, actions, nextStateConfig.entry)
.filter((a) => a)
).map<StateMachine.ActionObject<TContext, TEvent>>((action) =>
toActionObject(action, (machine as any)._options.actions)
);
Expand Down
22 changes: 14 additions & 8 deletions packages/xstate-fsm/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,14 @@ export namespace StateMachine {
assignment: Assigner<TContext, TEvent> | PropertyAssigner<TContext, TEvent>;
}

export type Transition<TContext extends object, TEvent extends EventObject> =
| string
export type Transition<
TContext extends object,
TEvent extends EventObject,
TStateValue extends string
Andarist marked this conversation as resolved.
Show resolved Hide resolved
> =
| TStateValue
| {
target?: string;
target?: TStateValue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly does this solve for you? Could you share some code that is affected by this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Andarist
I decided that it would be better to show in dynamics. This file describes the state machine. The creation takes place elsewhere, here I wanted to show the development process. Please ask more questions if you need to explain in more detail what is happening in the video.

2023-05-27.13-10-34.mp4
import { StateMachine } from '@xstate/fsm';

export type TestContext = {
  readonly value: number;
};

export type TestStateValue = 'init' | 'loading' | 'idle' | 'process';

export type TestStateMachine = StateMachine.Config<
  TestContext,
  { type: 'NEXT' | 'STOP' | 'COMPLETE' },
  { value: TestStateValue; context: TestContext }
>;

export const createStateMachine = (): TestStateMachine => ({
  context: { value: 42 },
  initial: 'init',
  states: {
    init: {
      on: {
        COMPLETE: 'loading',
      },
    },
    loading: {
      on: {
        COMPLETE: { target: 'idle' },
      },
    },
    idle: {
      on: {
        NEXT: 'process',
      },
    },
    process: {
      on: {
        STOP: { target: 'idle' },
      },
    },
  },
});

actions?: SingleOrArray<Action<TContext, TEvent>>;
cond?: (context: TContext, event: TEvent) => boolean;
};
Expand Down Expand Up @@ -121,13 +125,17 @@ export namespace StateMachine {
TState extends Typestate<TContext> = { value: any; context: TContext }
> {
id?: string;
initial: string;
initial: TState['value'];
context?: TContext;
states: {
[key in TState['value']]: {
on?: {
[K in TEvent['type']]?: SingleOrArray<
Transition<TContext, TEvent extends { type: K } ? TEvent : never>
Transition<
TContext,
TEvent extends { type: K } ? TEvent : never,
TState['value']
>
>;
};
exit?: SingleOrArray<Action<TContext, TEvent>>;
Expand Down Expand Up @@ -157,9 +165,7 @@ export namespace StateMachine {
TState extends Typestate<TContext> = { value: any; context: TContext }
> {
send: (event: TEvent | TEvent['type']) => void;
subscribe: (
listener: StateListener<State<TContext, TEvent, TState>>
) => {
subscribe: (listener: StateListener<State<TContext, TEvent, TState>>) => {
unsubscribe: () => void;
};
start: (
Expand Down
Loading