fix(core): clarify interpret defaults, consolidate invoked submachine completion, and add test coverage - #268
sytabaresa wants to merge 7 commits into
Conversation
…nsition test case
…w a error on normal execution if the 'done' transition don't exists. on debugging execution throws the unknown state error as usual.
…ple execution of interpret
…reducers, and add comprehensive test coverage
🦋 Changeset detectedLatest commit: 0579bae The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
23b1869 to
9c36a26
Compare
be96374 to
ba1bd56
Compare
ba1bd56 to
0579bae
Compare
| @@ -0,0 +1,6 @@ | |||
| --- | |||
| "robot3": minor | |||
| "robot-docs": minor | |||
| let data = service.child.context; | ||
| delete service.child; | ||
| return transitionTo(service, machine, { type: 'done', data }, this.transitions.get('done')); | ||
| return send(service, { type: 'done', data }) || machine; |
There was a problem hiding this comment.
This is a big change, but it's hidden in this massive PR. I'd like to see a PR specifically for this change and it spelled out exactly why to do this.
|
|
||
| if (d._onEnter) d._onEnter(machine, to, service.context, context, fromEvent); | ||
| let isSelfTransition = machine.current === to; | ||
| if (!isSelfTransition) delete service.child; |
| let state = newMachine.state.value; | ||
| service.machine = newMachine; | ||
| let ret = state.enter(newMachine, service, fromEvent); | ||
| let ret = (isSelfTransition && service.child) ? |
There was a problem hiding this comment.
this is a change of behavior, arguably a breaking change. This is another I'd like to see submitted as a dedicated PR so it's easier to reason about what it solves.
| }; | ||
|
|
||
| export function interpret(machine, onChange, initialContext, event) { | ||
| export function interpret(machine, onChange = () => { }, initialContext, event) { |
There was a problem hiding this comment.
Not that I'm necessarily against it, but what does this solve?
|
Left some comments. Mostly I'd like to see this broken up into smaller changes since at least a couple of them are changing long-standing behavior and it's difficult to understand the motivation given how much this PR is doing. |
Motivation
This PR cleans up a few rough edges around ergonomics, runtime safety, and consistency across the library:
onChange: Callinginterpret(machine)without anonChangecallback previously threw aTypeErroron state transitions. Defaulting it to a no-op (() => {}) makes passing a callback optional, matching what the docs and TypeScript types already promised.send()unifies this behavior—giving you helpful errors in debug mode (d._send) while failing gracefully in production if a'done'transition isn't defined.invokeFnType.enter, the variable namernwas an ambiguous abbreviation for "return value". Renaming it toinvokedResultmakes the codebase self-documenting by explicitly indicating that the variable contains the result (either a Promise or a child machine) returned from invokingthis.fn.call(service, ...). During debugging when the user put a non machine, promise, or function that return a promise in the invoke state, this will help the user track that malformed argument.service.childcleanup: When a machine exits an invoked state—via'done','error', or an external transition—we now explicitly clean upservice.child(delete service.child) so the reference only exists while a child is actively running. This is important because a parent machine can 'cancel' a child machine by transitioning out of the invoked state, even before the child machine has reached a final state. in this case the library needs to free this machine to align with the API. This not includes a self transition in the parent machine, because some events needs to be handle by the parent, and some by the child machine. and always reset break backtrack compatibility and can be very uncovenient.Summary of Changes
interpret(): Added a default() => {}fallback foronChangeand updated the docs to reflect that it's optional.Child Machine Management & Completion::
send(service, { type: 'done', data }). In debug mode, throws a clear error if the parent state lacks a'done'handler; in normal mode, cleans up cleanly without blowing up.service.child): UpdatedtransitionTo()sodelete service.childonly executes when transitioning to a different state (!isSelfTransition). Self-transitions on invoked states preserve the active child machine instance and its extended state (context) rather than re-initializing them.rntoinvokedResultinsideinvokeFnType.enter.Test Suite Expansion (
packages/core/test/):test-create-machine.js: Initial state selection, context factories, and machine immutability.test-interpret.js: OptionalonChange, self-transitions, event payloads, and unhandled events in both debug and normal modes.test-transition.js: Transitions, guard branching, and lifecycle execution order (Guard → Reducer/Action → State Change → Listener).test-reduce.js: Reducer sequence execution and event arguments.test-guard.js: Chained guard short-circuit behavior.test-invoke.js: Child machine completion across debug and normal modes.Test Results