Skip to content

Commit 3cd9821

Browse files
authored
Api changes for sendT (#72)
1 parent 64e906f commit 3cd9821

4 files changed

Lines changed: 199 additions & 178 deletions

File tree

src/index.ts

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { useEffect, useReducer } from "react";
2-
import { UseStateMachine, Machine, $$t } from "./types";
2+
import { UseStateMachine, Machine, $$t, O } from "./types";
33
import { assertNever, R, useConstant } from "./extras";
44

5+
56
const useStateMachineImpl = (definition: Machine.Definition.Impl) => {
6-
const [state, dispatch] = useReducer(createReducer(definition), createInitialState(definition));
7+
const [machineInstant, dispatch] = useReducer(createReducer(definition), createInitialState(definition));
78

89
const send = useConstant(() => (sendable: Machine.Sendable.Impl) => dispatch({ type: "SEND", sendable }));
910

@@ -13,30 +14,33 @@ const useStateMachineImpl = (definition: Machine.Definition.Impl) => {
1314
};
1415

1516
useEffect(() => {
16-
const entry = R.get(definition.states, state.value)!.effect;
17+
const entry = R.get(definition.states, machineInstant.state)!.effect;
1718
let exit = entry?.({
1819
send,
1920
setContext,
20-
event: state.event,
21-
context: state.context,
21+
event: machineInstant.event,
22+
context: machineInstant.context,
2223
});
2324

2425
return typeof exit === "function"
25-
? () => exit?.({ send, setContext, event: state.event, context: state.context })
26+
? () => exit?.({ send, setContext, event: machineInstant.event, context: machineInstant.context })
2627
: undefined;
2728
// eslint-disable-next-line react-hooks/exhaustive-deps
28-
}, [state.value, state.event]);
29+
}, [machineInstant.state, machineInstant.event]);
2930

30-
return [state, send];
31+
return { ...machineInstant, send };
3132
};
3233

33-
const createInitialState = (definition: Machine.Definition.Impl): Machine.State.Impl => {
34+
type MachineInstant =
35+
O.OmitKey<Machine.Impl, "send">
36+
37+
const createInitialState = (definition: Machine.Definition.Impl): MachineInstant => {
3438
let nextEvents = R.keys(R.concat(
3539
R.fromMaybe(R.get(definition.states, definition.initial)!.on),
3640
R.fromMaybe(definition.on)
3741
))
3842
return {
39-
value: definition.initial,
43+
state: definition.initial,
4044
context: definition.context as Machine.Context.Impl,
4145
event: { type: "$$initial" } as Machine.Event.Impl,
4246
nextEvents: nextEvents,
@@ -46,56 +50,56 @@ const createInitialState = (definition: Machine.Definition.Impl): Machine.State.
4650

4751
const createReducer = (definition: Machine.Definition.Impl) => {
4852
let log = createLogger(definition);
49-
return (machineState: Machine.State.Impl, internalEvent: InternalEvent): Machine.State.Impl => {
53+
return (machineInstant: MachineInstant, internalEvent: InternalEvent): MachineInstant => {
5054
if (internalEvent.type === "SET_CONTEXT") {
51-
let nextContext = internalEvent.updater(machineState.context);
52-
log("Context update", ["Previous Context", machineState.context], ["Next Context", nextContext]);
55+
let nextContext = internalEvent.updater(machineInstant.context);
56+
log("Context update", ["Previous Context", machineInstant.context], ["Next Context", nextContext]);
5357

54-
return { ...machineState, context: nextContext };
58+
return { ...machineInstant, context: nextContext };
5559
}
5660

5761
if (internalEvent.type === "SEND") {
5862
let sendable = internalEvent.sendable;
5963
let event = typeof sendable === "string" ? { type: sendable } : sendable;
60-
let context = machineState.context;
61-
let stateNode = R.get(definition.states, machineState.value)!;
64+
let context = machineInstant.context;
65+
let stateNode = R.get(definition.states, machineInstant.state)!;
6266
let resolvedTransition =
6367
R.get(R.fromMaybe(stateNode.on), event.type) ?? R.get(R.fromMaybe(definition.on), event.type);
6468

6569
if (!resolvedTransition) {
6670
log(
6771
`Current state doesn't listen to event type "${event.type}".`,
68-
["Current State", machineState],
72+
["Current State", machineInstant],
6973
["Event", event]
7074
);
71-
return machineState;
75+
return machineInstant;
7276
}
7377

74-
let [nextStateValue, didGuardDeny = false] = (() => {
78+
let [nextState, didGuardDeny = false] = (() => {
7579
if (typeof resolvedTransition === "string") return [resolvedTransition];
7680
if (resolvedTransition.guard === undefined) return [resolvedTransition.target];
7781
if (resolvedTransition.guard({ context, event })) return [resolvedTransition.target];
7882
return [resolvedTransition.target, true]
79-
})() as [Machine.StateValue.Impl, true?]
83+
})() as [Machine.State.Impl, true?]
8084

8185
if (didGuardDeny) {
8286
log(
83-
`Transition from "${machineState.value}" to "${nextStateValue}" denied by guard`,
87+
`Transition from "${machineInstant.state}" to "${nextState}" denied by guard`,
8488
["Event", event],
8589
["Context", context]
8690
);
87-
return machineState;
91+
return machineInstant;
8892
}
89-
log(`Transition from "${machineState.value}" to "${nextStateValue}"`, ["Event", event]);
93+
log(`Transition from "${machineInstant.state}" to "${nextState}"`, ["Event", event]);
9094

91-
let resolvedStateNode = R.get(definition.states, nextStateValue)!;
95+
let resolvedStateNode = R.get(definition.states, nextState)!;
9296

9397
let nextEvents = R.keys(R.concat(
9498
R.fromMaybe(resolvedStateNode.on),
9599
R.fromMaybe(definition.on)
96100
));
97101
return {
98-
value: nextStateValue,
102+
state: nextState,
99103
context,
100104
event,
101105
nextEvents,

src/types.ts

Lines changed: 71 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,44 @@ import { R } from "./extras"
33

44
export type UseStateMachine =
55
<D extends Machine.Definition<D>>(definition: A.InferNarrowestObject<D>) =>
6-
[ state: A.Instantiated<Machine.State<Machine.Definition.FromTypeParamter<D>>>
7-
, send: A.Instantiated<Machine.Send<Machine.Definition.FromTypeParamter<D>>>
8-
]
6+
Machine<Machine.Definition.FromTypeParameter<D>>
97

108
export const $$t = Symbol("$$t");
119
type $$t = typeof $$t;
1210
export type CreateType = <T>() => { [$$t]: T }
1311

12+
export type Machine<D,
13+
State = Machine.State<D>,
14+
NextEvents =
15+
( State extends any
16+
? A.Get<Machine.ExitEventForState<D, State>, "type">
17+
: never
18+
)[]
19+
> =
20+
& { nextEvents: NextEvents
21+
, send: Machine.Send<D>
22+
}
23+
& ( State extends any
24+
? { state: State
25+
, context: Machine.Context<D>
26+
, event: Machine.EntryEventForState<D, State>
27+
, nextEventsT: A.Get<Machine.ExitEventForState<D, State>, "type">[]
28+
}
29+
: never
30+
)
31+
32+
interface MachineImpl
33+
{ state: Machine.State.Impl
34+
, context: Machine.Context.Impl
35+
, event: Machine.Event.Impl
36+
, nextEvents: Machine.Event.Impl["type"][]
37+
, nextEventsT: Machine.Event.Impl["type"][]
38+
, send: Machine.Send.Impl
39+
}
40+
1441
export namespace Machine {
42+
export type Impl = MachineImpl
43+
1544
export type Definition<
1645
Self,
1746
States = A.Get<Self, "states">,
@@ -52,8 +81,8 @@ export namespace Machine {
5281
)
5382

5483
interface DefinitionImp
55-
{ initial: StateValue.Impl
56-
, states: R.Of<StateValue.Impl, Definition.StateNode.Impl>
84+
{ initial: State.Impl
85+
, states: R.Of<State.Impl, Definition.StateNode.Impl>
5786
, on?: Definition.On.Impl
5887
, schema?: { context?: null, events?: R.Of<Event.Impl["type"], null> }
5988
, verbose?: boolean
@@ -64,7 +93,7 @@ export namespace Machine {
6493
export namespace Definition {
6594
export type Impl = DefinitionImp
6695

67-
export type FromTypeParamter<D> =
96+
export type FromTypeParameter<D> =
6897
"$$internalIsConstraint" extends keyof D
6998
? D extends infer X ? X extends Definition<infer X> ? X : never : never
7099
: D
@@ -120,7 +149,7 @@ export namespace Machine {
120149
}
121150

122151
export type Transition<D, P,
123-
TargetString = Machine.StateValue<D>,
152+
TargetString = Machine.State<D>,
124153
Event = { type: L.Pop<P> }
125154
> =
126155
| TargetString
@@ -135,12 +164,12 @@ export namespace Machine {
135164
}
136165

137166
type TransitionImpl =
138-
| State.Impl["value"]
139-
| { target: State.Impl["value"]
167+
| Machine.Impl["state"]
168+
| { target: Machine.Impl["state"]
140169
, guard?:
141170
( parameter:
142-
{ context: State.Impl["context"]
143-
, event: State.Impl["event"]
171+
{ context: Machine.Impl["context"]
172+
, event: Machine.Impl["event"]
144173
}
145174
) => boolean
146175
}
@@ -149,10 +178,10 @@ export namespace Machine {
149178
}
150179

151180

152-
export type Effect<D, P, StateValue = L.Pop<L.Popped<P>>> =
153-
(parameter: A.Instantiated<EffectParameterForStateValue<D, StateValue>>) =>
181+
export type Effect<D, P, State = L.Pop<L.Popped<P>>> =
182+
(parameter: A.Instantiated<EffectParameterForState<D, State>>) =>
154183
| void
155-
| ((parameter: A.Instantiated<EffectCleanupParameterForStateValue<D, StateValue>>) => void)
184+
| ((parameter: A.Instantiated<EffectCleanupParameterForState<D, State>>) => void)
156185

157186
type EffectImpl =
158187
(parameter: EffectParameter.Impl) =>
@@ -218,15 +247,15 @@ export namespace Machine {
218247
export type InitialEventType = "$$initial";
219248
}
220249

221-
export type StateValue<D> =
250+
export type State<D> =
222251
keyof A.Get<D, "states">
223252

224-
export type InitialStateValue<D> =
253+
export type InitialState<D> =
225254
A.Get<D, "initial">
226255

227-
type StateValueImpl = string & A.Tag<"Machine.StateValue">
228-
export namespace StateValue {
229-
export type Impl = StateValueImpl;
256+
type StateImpl = string & A.Tag<"Machine.State">
257+
export namespace State {
258+
export type Impl = StateImpl;
230259
}
231260

232261
export type Context<D> =
@@ -240,7 +269,7 @@ export namespace Machine {
240269
export type Event<D, EventsSchema = A.Get<D, ["schema", "events"], {}>> =
241270
| O.Value<{ [T in U.Exclude<keyof EventsSchema, Definition.ExhaustiveIdentifier>]:
242271
A.Get<EventsSchema, [T, $$t]> extends infer P
243-
? P extends any ? O.ShallowMerge<{ type: T } & P> : never
272+
? P extends any ? O.ShallowClean<{ type: T } & P> : never
244273
: never
245274
}>
246275
| ( A.Get<EventsSchema, Definition.ExhaustiveIdentifier, false> extends true ? never :
@@ -271,7 +300,17 @@ export namespace Machine {
271300
}
272301

273302
export namespace EffectParameter {
303+
export interface EffectParameterForState<D, State>
304+
extends BaseEffectParameter<D>
305+
{ event: Machine.EntryEventForState<D, State>
306+
}
307+
274308
export namespace Cleanup {
309+
export interface ForState<D, State>
310+
extends BaseEffectParameter<D>
311+
{ event: Machine.ExitEventForState<D, State>
312+
}
313+
275314
export type Impl = EffectParameter.Impl
276315
}
277316

@@ -284,14 +323,14 @@ export namespace Machine {
284323
, setContext: SetContext.Impl
285324
}
286325

287-
export interface EffectParameterForStateValue<D, StateValue>
326+
export interface EffectParameterForState<D, State>
288327
extends BaseEffectParameter<D>
289-
{ event: A.Uninstantiated<Machine.EntryEventForStateValue<D, StateValue>>
328+
{ event: A.Uninstantiated<Machine.EntryEventForState<D, State>>
290329
}
291330

292-
export interface EffectCleanupParameterForStateValue<D, StateValue>
331+
export interface EffectCleanupParameterForState<D, State>
293332
extends BaseEffectParameter<D>
294-
{ event: A.Uninstantiated<Machine.ExitEventForStateValue<D, StateValue>>
333+
{ event: A.Uninstantiated<Machine.ExitEventForState<D, State>>
295334
}
296335

297336
export interface BaseEffectParameter<D>
@@ -300,8 +339,8 @@ export namespace Machine {
300339
, setContext: Machine.SetContext<D>
301340
}
302341

303-
export type EntryEventForStateValue<D, StateValue> =
304-
| ( StateValue extends InitialStateValue<D>
342+
export type EntryEventForState<D, State> =
343+
| ( State extends InitialState<D>
305344
? { type: Definition.InitialEventType }
306345
: never
307346
)
@@ -311,27 +350,27 @@ export namespace Machine {
311350
| O.Value<{ [S in keyof A.Get<D, "states">]:
312351
O.Value<{ [E in keyof A.Get<D, ["states", S, "on"]>]:
313352
A.Get<D, ["states", S, "on", E]> extends infer T
314-
? (T extends A.String ? T : A.Get<T, "target">) extends StateValue
353+
? (T extends A.String ? T : A.Get<T, "target">) extends State
315354
? E
316355
: never
317356
: never
318357
}>
319358
}>
320359
| O.Value<{ [E in keyof A.Get<D, ["on"]>]:
321360
A.Get<D, ["on", E]> extends infer T
322-
? (T extends A.String ? T : A.Get<T, "target">) extends StateValue
361+
? (T extends A.String ? T : A.Get<T, "target">) extends State
323362
? E
324363
: never
325364
: never
326365
}>
327366
}
328367
>
329368

330-
export type ExitEventForStateValue<D, StateValue> =
369+
export type ExitEventForState<D, State> =
331370
U.Extract<
332371
Event<D>,
333372
{ type:
334-
| keyof A.Get<D, ["states", StateValue, "on"], {}>
373+
| keyof A.Get<D, ["states", State, "on"], {}>
335374
| keyof A.Get<D, "on", {}>
336375
}
337376
>
@@ -378,34 +417,6 @@ export namespace Machine {
378417
export namespace ContextUpdater {
379418
export type Impl = ContextUpdaterImpl;
380419
}
381-
382-
export type State<D,
383-
Value = StateValue<D>,
384-
NextEvents =
385-
( Value extends any
386-
? A.Get<ExitEventForStateValue<D, Value>, "type">
387-
: never
388-
)[]
389-
> =
390-
Value extends any
391-
? { value: Value
392-
, context: A.Uninstantiated<Context<D>>
393-
, event: A.Uninstantiated<EntryEventForStateValue<D, Value>>
394-
, nextEventsT: A.Get<ExitEventForStateValue<D, Value>, "type">[]
395-
, nextEvents: NextEvents
396-
}
397-
: never
398-
399-
interface StateImpl
400-
{ value: StateValue.Impl
401-
, context: Context.Impl
402-
, event: Event.Impl
403-
, nextEvents: Event.Impl["type"][]
404-
, nextEventsT: Event.Impl["type"][]
405-
}
406-
export namespace State {
407-
export type Impl = StateImpl
408-
}
409420
}
410421

411422
export namespace L {
@@ -439,7 +450,8 @@ export namespace U {
439450

440451
export namespace O {
441452
export type Value<T> = T[keyof T];
442-
export type ShallowMerge<T> = { [K in keyof T]: T[K] } & unknown
453+
export type ShallowClean<T> = { [K in keyof T]: T[K] }
454+
export type OmitKey<T, K extends keyof T> = { [P in U.Exclude<keyof T, K>]: T[P] }
443455
}
444456

445457
export namespace A {

0 commit comments

Comments
 (0)