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

[v5] Explicit spawn #3148

Merged
merged 98 commits into from
May 26, 2022
Merged
Changes from 1 commit
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
29e04ae
All tests pass!
davidkpiano Mar 5, 2022
4859fe9
Fix all tests
davidkpiano Mar 6, 2022
abb47d4
Some types cleanup
davidkpiano Mar 6, 2022
39bc706
Merge branch 'next' into v5/improved-spawn-1
davidkpiano Mar 7, 2022
eb1f5eb
Merge branch 'next' into v5/improved-spawn-1
davidkpiano Mar 11, 2022
99424c3
Fix types WIP
davidkpiano Mar 11, 2022
d6ffbc9
Add TODOs for types
davidkpiano Mar 12, 2022
b7a8751
Skip questionable test
davidkpiano Mar 12, 2022
cee5249
Remove stray console logs
davidkpiano Mar 12, 2022
0a3ac9f
Add `spawn.machine`
davidkpiano Mar 12, 2022
9fce5a9
Add `spawn.promise`
davidkpiano Mar 12, 2022
6df48b5
Add `spawn.observable`
davidkpiano Mar 12, 2022
0f5cfb9
Add tests for referenced behaviors
davidkpiano Mar 12, 2022
5505179
Revert "Add `spawn.observable`"
davidkpiano Mar 13, 2022
91ecae1
Revert "Add `spawn.promise`"
davidkpiano Mar 13, 2022
65fe6b4
Revert "Add `spawn.machine`"
davidkpiano Mar 13, 2022
65a272b
Cleanup
davidkpiano Mar 13, 2022
3689875
Temp fix for string references
davidkpiano Mar 13, 2022
53e560c
Merge branch 'next' into v5/improved-spawn-1
davidkpiano Mar 22, 2022
56b7d16
Ignore excessive stack depth warnings
davidkpiano Mar 22, 2022
04e228a
Merge branch 'next' into v5/improved-spawn-1
davidkpiano Mar 25, 2022
ce9971e
Merge branch 'next' into v5/improved-spawn-1
davidkpiano Mar 26, 2022
3fb32fd
Merge branch 'next' into v5/improved-spawn-1
davidkpiano Mar 29, 2022
6cdd3cc
This actually passes
davidkpiano Mar 30, 2022
6d07555
Remove invoke*
davidkpiano Mar 30, 2022
8f2d906
Rename createDeferredBehavior -> createCallbackBehavior
davidkpiano Mar 30, 2022
1fe8923
Make getContextAndActions private
davidkpiano Mar 30, 2022
a9ff1bf
Fix & clarify unskipped test
davidkpiano Mar 31, 2022
6bf4ea4
Add test from todo
davidkpiano Mar 31, 2022
69e8b80
Clean up test
davidkpiano Mar 31, 2022
b467f67
Make parent "private"
davidkpiano Mar 31, 2022
f0de1ac
Make sure children is "immutable" (+ todos)
davidkpiano Mar 31, 2022
eab43a5
Revert initialState change
davidkpiano Mar 31, 2022
ecf9853
Add comment
davidkpiano Mar 31, 2022
fe16e0c
Oops
davidkpiano Mar 31, 2022
01e9c65
Remove invoke* functions (except for invokeMachine)
davidkpiano Apr 4, 2022
01ffc77
Quell 1 type error
davidkpiano Apr 4, 2022
bd8e8e8
Fixed the conditional type in the `interpret`
Andarist Apr 8, 2022
9de5049
Bring back removed `spawn` type test
Andarist Apr 8, 2022
9b48db2
Tweak one `assign` test
Andarist Apr 8, 2022
e69d261
Remove lazy argument from `createMachineBehavior` and remove `invokeM…
Andarist Apr 9, 2022
e348d67
Add a TODO comment about hiding `ActorRef["_parent"]`
Andarist Apr 9, 2022
2f6d61d
Require a machine with all implementations provided as an argument fo…
Andarist Apr 9, 2022
1142173
Cache the `initialState` getter in `createMachineBehavior`
Andarist Apr 11, 2022
089c58b
Unwrap `createCallbackBehavior` argument from a redundant lazy layer
Andarist Apr 11, 2022
bdaa37d
Merge pull request #3213 from statelyai/andarist/spawn-stuff
Andarist Apr 12, 2022
b3b6a75
Merge branch 'next' into v5/improved-spawn-1
davidkpiano Apr 14, 2022
eeb1210
Renaming WIP
davidkpiano Apr 14, 2022
c05bd50
Renaming WIP
davidkpiano Apr 14, 2022
6a14905
Add back spawnBehavior but call it createActorRef
davidkpiano Apr 15, 2022
4ea8080
behaviors -> actors
davidkpiano Apr 15, 2022
14a3a0b
Tweak tests
davidkpiano Apr 15, 2022
664665a
Remove Actor class
davidkpiano Apr 15, 2022
ebff7dc
Remove actor.ts
davidkpiano Apr 21, 2022
2c72cde
Fix missing function
davidkpiano Apr 21, 2022
d0d24dd
Remove createBehaviorFrom
davidkpiano Apr 21, 2022
ac21c9f
Make behavior private
davidkpiano Apr 21, 2022
c30059d
Add onEmit and remove complete
davidkpiano Apr 22, 2022
5f9f088
Tighten up types (a little)
davidkpiano Apr 22, 2022
575f3d3
Fix types
davidkpiano Apr 22, 2022
b6bb4ae
Remove createBehaviorFrom
davidkpiano Apr 22, 2022
4b7a74b
No more magic events
davidkpiano Apr 22, 2022
e526656
Update packages/core/src/actors.ts
davidkpiano Apr 22, 2022
38b34e6
Update packages/core/src/types.ts
davidkpiano Apr 22, 2022
db1079f
Fix types
davidkpiano Apr 22, 2022
a77d4e8
Merge branch 'next' into v5/improved-spawn-1
davidkpiano Apr 25, 2022
82fc286
Fix sendError (send raw error data, not events)
davidkpiano Apr 25, 2022
6851f62
Attempt to fix type
davidkpiano Apr 25, 2022
21ca13c
Fix type
davidkpiano Apr 25, 2022
8b10ff9
Merge branch 'next' into v5/improved-spawn-1
Andarist Apr 28, 2022
fb76fe0
Rename onEmit -> onSnapshot
davidkpiano Apr 28, 2022
0bea428
Rename types: TEmitted -> TSnapshot
davidkpiano Apr 28, 2022
9c45c1b
Change src to allow behaviors directly (WIP)
davidkpiano May 7, 2022
401dbd7
Fix type errors
davidkpiano May 7, 2022
dd54cfe
Add back InvokeSrcDefinition for now
davidkpiano May 7, 2022
cc80182
Add fromEventObservable
davidkpiano May 10, 2022
2f3116b
Remove outdated `xstate/behaviors` references (#3280)
Andarist May 10, 2022
de5ee43
Avoid wrapping `behaviorImpl` in a throwaway function (#3281)
Andarist May 10, 2022
f8f065f
Update packages/core/test/actions.test.ts
davidkpiano May 11, 2022
845a7dd
Update packages/xstate-svelte/src/useSelector.ts
davidkpiano May 11, 2022
52719b9
Update packages/xstate-svelte/src/useSelector.ts
davidkpiano May 11, 2022
31a5021
Update packages/xstate-vue/src/useSelector.ts
davidkpiano May 11, 2022
4318926
Update packages/xstate-vue/src/useSelector.ts
davidkpiano May 11, 2022
d84106d
Remove unused type
davidkpiano May 12, 2022
d4bec9f
Remove subscriptions from behaviors (they belong on ObservableActorRe…
davidkpiano May 13, 2022
8de2ed8
Add TODO
davidkpiano May 13, 2022
f13f476
Remove unused type
davidkpiano May 13, 2022
1173a61
Refactor: do not use observers for invoked promises
davidkpiano May 14, 2022
0a91f87
Remove latestData logic in interpreter
davidkpiano May 14, 2022
652658c
Remove observer logic from fromObservable/fromObservableEvent
davidkpiano May 14, 2022
a97cd80
Remove observers
davidkpiano May 14, 2022
fece479
Remove subscription logic from interpreter
davidkpiano May 14, 2022
d3274d1
Remove unused type
davidkpiano May 15, 2022
dbfbae9
Fixed `ObservableActorRef` subscriptions and remove some outdated/red…
Andarist May 25, 2022
8655dad
Remove `createActorRef`
Andarist May 25, 2022
359998d
Make `Interpreter#nextState` pure again (#3340)
Andarist May 25, 2022
93a5ada
Rename `EmittedFrom` to `SnapshotFrom` (#3341)
Andarist May 25, 2022
7e2c649
Add changesets
Andarist May 26, 2022
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
Prev Previous commit
Next Next commit
Remove observer logic from fromObservable/fromObservableEvent
davidkpiano committed May 14, 2022
commit 652658cd4480a16ad87827881de5aa526a8157ab
156 changes: 112 additions & 44 deletions packages/core/src/actors.ts
Original file line number Diff line number Diff line change
@@ -156,9 +156,10 @@ export function fromPromise<T>(
lazyPromise: Lazy<PromiseLike<T>>
): Behavior<{ type: string }, T | undefined> {
let canceled = false;
const resolveEvent = Symbol('resolve');
const rejectEvent = Symbol('reject');
const resolveEventType = Symbol('resolve');
const rejectEventType = Symbol('reject');

// TODO: add event types
const behavior: Behavior<any, T | undefined> = {
transition: (state, event, { self, name }) => {
if (canceled) {
@@ -171,21 +172,21 @@ export function fromPromise<T>(

resolvedPromise.then(
(response) => {
self.send({ type: resolveEvent, data: response });
self.send({ type: resolveEventType, data: response });
},
(errorData) => {
self.send({ type: rejectEvent, data: errorData });
self.send({ type: rejectEventType, data: errorData });
}
);
return undefined;
case resolveEvent:
case resolveEventType:
self._parent?.send(
toSCXMLEvent(doneInvoke(name, event.data) as any, {
origin: self
})
);
return event.data;
case rejectEvent:
case rejectEventType:
const errorEvent = error(name, event.data);

self._parent?.send(
@@ -212,27 +213,66 @@ export function fromObservable<T, TEvent extends EventObject>(
): Behavior<TEvent, T | undefined> {
Copy link
Member

Choose a reason for hiding this comment

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

so... in a way, this should be:

Suggested change
): Behavior<TEvent, T | undefined> {
): Behavior<never, T | undefined> {

or with the latest changes:

Suggested change
): Behavior<TEvent, T | undefined> {
): Behavior<{ type: string }, T | undefined> {

With this design, an observable is really closer to a promise than a machine/callback (they can send events directly to the parent)

let subscription: Subscription | undefined;
let observable: Subscribable<T> | undefined;
const nextEventType = Symbol('next');
const errorEventType = Symbol('error');
const completeEventType = Symbol('complete');
let canceled = false;

const behavior: Behavior<TEvent, T | undefined> = {
transition: (_, event, { observers }) => {
if (event.type === startSignalType) {
observable = lazyObservable();
subscription = observable.subscribe({
next: (value) => {
observers.forEach((o) => o.next?.(value));
},
error: (err) => {
observers.forEach((o) => o.error?.(err));
},
complete: () => {
observers.forEach((o) => o.complete?.());
}
});
} else if (event.type === stopSignalType) {
subscription && subscription.unsubscribe();
// TODO: add event types
const behavior: Behavior<any, T | undefined> = {
transition: (state, event, { self, name }) => {
if (canceled) {
return state;
}

return undefined;
switch (event.type) {
case startSignalType:
observable = lazyObservable();
subscription = observable.subscribe({
next: (value) => {
self.send({ type: nextEventType, data: value });
},
error: (err) => {
self.send({ type: errorEventType, data: err });
},
complete: () => {
self.send({ type: completeEventType });
}
});
return state;
case nextEventType:
self._parent?.send(
toSCXMLEvent(
{
type: `xstate.snapshot.${name}`,
data: event.data
},
{ origin: self }
)
);
return event.data;
case errorEventType:
const errorEvent = error(name, event.data);
self._parent?.send(
toSCXMLEvent(errorEvent, {
origin: self
})
);
return state;
case completeEventType:
self._parent?.send(
toSCXMLEvent(doneInvoke(name), {
origin: self
})
);
return state;
case stopSignalType:
canceled = true;
subscription?.unsubscribe();
return state;
default:
return state;
}
},
initialState: undefined
};
@@ -253,29 +293,57 @@ export function fromEventObservable<T extends EventObject>(
): Behavior<EventObject, T | undefined> {
let subscription: Subscription | undefined;
let observable: Subscribable<T> | undefined;
const nextEventType = Symbol('next');
const errorEventType = Symbol('error');
const completeEventType = Symbol('complete');
let canceled = false;

const behavior: Behavior<EventObject, T | undefined> = {
transition: (_, event, { self, observers }) => {
const { _parent: parent } = self;

if (event.type === startSignalType) {
observable = lazyObservable();
subscription = observable.subscribe({
next: (value) => {
parent?.send(toSCXMLEvent(value, { origin: self }));
},
error: (err) => {
observers.forEach((o) => o.error?.(err));
},
complete: () => {
observers.forEach((o) => o.complete?.());
}
});
} else if (event.type === stopSignalType) {
subscription && subscription.unsubscribe();
// TODO: event types
const behavior: Behavior<any, T | undefined> = {
transition: (state, event, { self, name }) => {
if (canceled) {
return state;
}

return undefined;
switch (event.type) {
case startSignalType:
observable = lazyObservable();
subscription = observable.subscribe({
next: (value) => {
self._parent?.send(toSCXMLEvent(value, { origin: self }));
},
error: (err) => {
self.send({ type: errorEventType, data: err });
},
complete: () => {
self.send({ type: completeEventType });
}
});
return state;
Copy link
Member

Choose a reason for hiding this comment

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

return state is technically correct within this whole behavior but in practice, this is return undefined. I wonder if it's worth to change that to make this more visible - right now a reader could assume that some state can be associated with this behavior.

Copy link
Member Author

Choose a reason for hiding this comment

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

Should I rename state to snapshot to make this more clear?

Copy link
Member

Choose a reason for hiding this comment

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

That could be done (i dont mind using state here though). The main point was that this particular behavior wont have non-undefined state/snapshot and when reading through those return statements it looks like it can

case nextEventType:
return event.data;
Comment on lines +329 to +330
Copy link
Member

Choose a reason for hiding this comment

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

This is an unused code. It should either be removed or this event should be sent from here:

self._parent?.send(toSCXMLEvent(value, { origin: self }));

and the self._parent.send(...) should be performed here

case errorEventType:
const errorEvent = error(name, event.data);
self._parent?.send(
toSCXMLEvent(errorEvent, {
origin: self
})
);
return state;
case completeEventType:
self._parent?.send(
toSCXMLEvent(doneInvoke(name), {
origin: self
})
);
return state;
case stopSignalType:
canceled = true;
subscription?.unsubscribe();
return state;
default:
return state;
}
},
initialState: undefined
};