UNPKG

14.5 kBJavaScriptView Raw
1'use strict';
2
3var guards_dist_xstateGuards = require('./raise-40b1a1f5.cjs.js');
4
5// it's likely-ish that `(TActor & { src: TSrc })['logic']` would be faster
6// but it's only possible to do it since https://github.com/microsoft/TypeScript/pull/53098 (TS 5.1)
7// and we strive to support TS 5.0 whenever possible
8function createSpawner(actorScope, {
9 machine,
10 context
11}, event, spawnedChildren) {
12 const spawn = (src, options = {}) => {
13 const {
14 systemId,
15 input
16 } = options;
17 if (typeof src === 'string') {
18 const logic = guards_dist_xstateGuards.resolveReferencedActor(machine, src);
19 if (!logic) {
20 throw new Error(`Actor logic '${src}' not implemented in machine '${machine.id}'`);
21 }
22 const actorRef = guards_dist_xstateGuards.createActor(logic, {
23 id: options.id,
24 parent: actorScope.self,
25 syncSnapshot: options.syncSnapshot,
26 input: typeof input === 'function' ? input({
27 context,
28 event,
29 self: actorScope.self
30 }) : input,
31 src,
32 systemId
33 });
34 spawnedChildren[actorRef.id] = actorRef;
35 return actorRef;
36 } else {
37 const actorRef = guards_dist_xstateGuards.createActor(src, {
38 id: options.id,
39 parent: actorScope.self,
40 syncSnapshot: options.syncSnapshot,
41 input: options.input,
42 src,
43 systemId
44 });
45 return actorRef;
46 }
47 };
48 return (src, options) => {
49 const actorRef = spawn(src, options); // TODO: fix types
50 spawnedChildren[actorRef.id] = actorRef;
51 actorScope.defer(() => {
52 if (actorRef._processingStatus === guards_dist_xstateGuards.ProcessingStatus.Stopped) {
53 return;
54 }
55 actorRef.start();
56 });
57 return actorRef;
58 };
59}
60
61function resolveAssign(actorScope, snapshot, actionArgs, actionParams, {
62 assignment
63}) {
64 if (!snapshot.context) {
65 throw new Error('Cannot assign to undefined `context`. Ensure that `context` is defined in the machine config.');
66 }
67 const spawnedChildren = {};
68 const assignArgs = {
69 context: snapshot.context,
70 event: actionArgs.event,
71 spawn: createSpawner(actorScope, snapshot, actionArgs.event, spawnedChildren),
72 self: actorScope.self,
73 system: actorScope.system
74 };
75 let partialUpdate = {};
76 if (typeof assignment === 'function') {
77 partialUpdate = assignment(assignArgs, actionParams);
78 } else {
79 for (const key of Object.keys(assignment)) {
80 const propAssignment = assignment[key];
81 partialUpdate[key] = typeof propAssignment === 'function' ? propAssignment(assignArgs, actionParams) : propAssignment;
82 }
83 }
84 const updatedContext = Object.assign({}, snapshot.context, partialUpdate);
85 return [guards_dist_xstateGuards.cloneMachineSnapshot(snapshot, {
86 context: updatedContext,
87 children: Object.keys(spawnedChildren).length ? {
88 ...snapshot.children,
89 ...spawnedChildren
90 } : snapshot.children
91 })];
92}
93/**
94 * Updates the current context of the machine.
95 *
96 * @param assignment An object that represents the partial context to update, or a
97 * function that returns an object that represents the partial context to update.
98 *
99 * @example
100 ```ts
101 import { createMachine, assign } from 'xstate';
102
103 const countMachine = createMachine({
104 context: {
105 count: 0,
106 message: ''
107 },
108 on: {
109 inc: {
110 actions: assign({
111 count: ({ context }) => context.count + 1
112 })
113 },
114 updateMessage: {
115 actions: assign(({ context, event }) => {
116 return {
117 message: event.message.trim()
118 }
119 })
120 }
121 }
122 });
123 ```
124 */
125function assign(assignment) {
126 function assign(args, params) {
127 }
128 assign.type = 'xstate.assign';
129 assign.assignment = assignment;
130 assign.resolve = resolveAssign;
131 return assign;
132}
133
134function resolveEmit(_, snapshot, args, actionParams, {
135 event: eventOrExpr
136}) {
137 const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args, actionParams) : eventOrExpr;
138 return [snapshot, {
139 event: resolvedEvent
140 }];
141}
142function executeEmit(actorScope, {
143 event
144}) {
145 actorScope.defer(() => actorScope.emit(event));
146}
147/**
148 * Emits an event to event handlers registered on the actor via `actor.on(event, handler)`.
149 *
150 * @example
151 ```ts
152 import { emit } from 'xstate';
153
154 const machine = createMachine({
155 // ...
156 on: {
157 something: {
158 actions: emit({
159 type: 'emitted',
160 some: 'data'
161 })
162 }
163 }
164 // ...
165 });
166
167 const actor = createActor(machine).start();
168
169 actor.on('emitted', (event) => {
170 console.log(event);
171 });
172
173 actor.send({ type: 'something' });
174 // logs:
175 // {
176 // type: 'emitted',
177 // some: 'data'
178 // }
179 ```
180 */
181function emit(
182/**
183 * The event to emit, or an expression that returns an event to emit.
184 */
185eventOrExpr) {
186 function emit(args, params) {
187 }
188 emit.type = 'xstate.emit';
189 emit.event = eventOrExpr;
190 emit.resolve = resolveEmit;
191 emit.execute = executeEmit;
192 return emit;
193}
194
195/**
196 *
197 * @remarks
198 *
199 * `T | unknown` reduces to `unknown` and that can be problematic when it comes to contextual typing.
200 * It especially is a problem when the union has a function member, like here:
201 *
202 * ```ts
203 * declare function test(cbOrVal: ((arg: number) => unknown) | unknown): void;
204 * test((arg) => {}) // oops, implicit any
205 * ```
206 *
207 * This type can be used to avoid this problem. This union represents the same value space as `unknown`.
208 */
209
210// https://github.com/microsoft/TypeScript/issues/23182#issuecomment-379091887
211
212// @TODO: Replace with native `NoInfer` when TS issue gets fixed:
213// https://github.com/microsoft/TypeScript/pull/57673
214/**
215 * @deprecated Use the built-in `NoInfer` type instead
216 */
217/**
218 * The full definition of an event, with a string `type`.
219 */
220/**
221 * The string or object representing the state value relative to the parent state node.
222 *
223 * @remarks
224 *
225 * - For a child atomic state node, this is a string, e.g., `"pending"`.
226 *
227 * - For complex state nodes, this is an object, e.g., `{ success: "someChildState" }`.
228 */
229// TODO: remove once TS fixes this type-widening issue
230/** @deprecated use `AnyMachineSnapshot` instead */
231// TODO: possibly refactor this somehow, use even a simpler type, and maybe even make `machine.options` private or something
232/**
233 * @hidden
234 */
235let SpecialTargets = /*#__PURE__*/function (SpecialTargets) {
236 SpecialTargets["Parent"] = "#_parent";
237 SpecialTargets["Internal"] = "#_internal";
238 return SpecialTargets;
239}({});
240
241/**
242 * @deprecated Use `AnyActor` instead.
243 */
244
245// Based on RxJS types
246
247/**
248 * @deprecated Use `Actor<T>` instead.
249 */
250
251// only meant to be used internally for debugging purposes
252
253/**
254 * Represents logic which can be used by an actor.
255 *
256 * @template TSnapshot - The type of the snapshot.
257 * @template TEvent - The type of the event object.
258 * @template TInput - The type of the input.
259 * @template TSystem - The type of the actor system.
260 */
261
262function resolveSendTo(actorScope, snapshot, args, actionParams, {
263 to,
264 event: eventOrExpr,
265 id,
266 delay
267}, extra) {
268 const delaysMap = snapshot.machine.implementations.delays;
269 if (typeof eventOrExpr === 'string') {
270 throw new Error(`Only event objects may be used with sendTo; use sendTo({ type: "${eventOrExpr}" }) instead`);
271 }
272 const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args, actionParams) : eventOrExpr;
273 let resolvedDelay;
274 if (typeof delay === 'string') {
275 const configDelay = delaysMap && delaysMap[delay];
276 resolvedDelay = typeof configDelay === 'function' ? configDelay(args, actionParams) : configDelay;
277 } else {
278 resolvedDelay = typeof delay === 'function' ? delay(args, actionParams) : delay;
279 }
280 const resolvedTarget = typeof to === 'function' ? to(args, actionParams) : to;
281 let targetActorRef;
282 if (typeof resolvedTarget === 'string') {
283 if (resolvedTarget === SpecialTargets.Parent) {
284 targetActorRef = actorScope.self._parent;
285 } else if (resolvedTarget === SpecialTargets.Internal) {
286 targetActorRef = actorScope.self;
287 } else if (resolvedTarget.startsWith('#_')) {
288 // SCXML compatibility: https://www.w3.org/TR/scxml/#SCXMLEventProcessor
289 // #_invokeid. If the target is the special term '#_invokeid', where invokeid is the invokeid of an SCXML session that the sending session has created by <invoke>, the Processor must add the event to the external queue of that session.
290 targetActorRef = snapshot.children[resolvedTarget.slice(2)];
291 } else {
292 targetActorRef = extra.deferredActorIds?.includes(resolvedTarget) ? resolvedTarget : snapshot.children[resolvedTarget];
293 }
294 if (!targetActorRef) {
295 throw new Error(`Unable to send event to actor '${resolvedTarget}' from machine '${snapshot.machine.id}'.`);
296 }
297 } else {
298 targetActorRef = resolvedTarget || actorScope.self;
299 }
300 return [snapshot, {
301 to: targetActorRef,
302 event: resolvedEvent,
303 id,
304 delay: resolvedDelay
305 }];
306}
307function retryResolveSendTo(_, snapshot, params) {
308 if (typeof params.to === 'string') {
309 params.to = snapshot.children[params.to];
310 }
311}
312function executeSendTo(actorScope, params) {
313 // this forms an outgoing events queue
314 // thanks to that the recipient actors are able to read the *updated* snapshot value of the sender
315 actorScope.defer(() => {
316 const {
317 to,
318 event,
319 delay,
320 id
321 } = params;
322 if (typeof delay === 'number') {
323 actorScope.system.scheduler.schedule(actorScope.self, to, event, delay, id);
324 return;
325 }
326 actorScope.system._relay(actorScope.self,
327 // at this point, in a deferred task, it should already be mutated by retryResolveSendTo
328 // if it initially started as a string
329 to, event.type === guards_dist_xstateGuards.XSTATE_ERROR ? guards_dist_xstateGuards.createErrorActorEvent(actorScope.self.id, event.data) : event);
330 });
331}
332/**
333 * Sends an event to an actor.
334 *
335 * @param actor The `ActorRef` to send the event to.
336 * @param event The event to send, or an expression that evaluates to the event to send
337 * @param options Send action options
338 * - `id` - The unique send event identifier (used with `cancel()`).
339 * - `delay` - The number of milliseconds to delay the sending of the event.
340 */
341function sendTo(to, eventOrExpr, options) {
342 function sendTo(args, params) {
343 }
344 sendTo.type = 'xsnapshot.sendTo';
345 sendTo.to = to;
346 sendTo.event = eventOrExpr;
347 sendTo.id = options?.id;
348 sendTo.delay = options?.delay;
349 sendTo.resolve = resolveSendTo;
350 sendTo.retryResolve = retryResolveSendTo;
351 sendTo.execute = executeSendTo;
352 return sendTo;
353}
354
355/**
356 * Sends an event to this machine's parent.
357 *
358 * @param event The event to send to the parent machine.
359 * @param options Options to pass into the send event.
360 */
361function sendParent(event, options) {
362 return sendTo(SpecialTargets.Parent, event, options);
363}
364/**
365 * Forwards (sends) an event to the `target` actor.
366 *
367 * @param target The target actor to forward the event to.
368 * @param options Options to pass into the send action creator.
369 */
370function forwardTo(target, options) {
371 return sendTo(target, ({
372 event
373 }) => event, options);
374}
375
376function resolveEnqueueActions(actorScope, snapshot, args, actionParams, {
377 collect
378}) {
379 const actions = [];
380 const enqueue = function enqueue(action) {
381 actions.push(action);
382 };
383 enqueue.assign = (...args) => {
384 actions.push(assign(...args));
385 };
386 enqueue.cancel = (...args) => {
387 actions.push(guards_dist_xstateGuards.cancel(...args));
388 };
389 enqueue.raise = (...args) => {
390 // for some reason it fails to infer `TDelay` from `...args` here and picks its default (`never`)
391 // then it fails to typecheck that because `...args` use `string` in place of `TDelay`
392 actions.push(guards_dist_xstateGuards.raise(...args));
393 };
394 enqueue.sendTo = (...args) => {
395 // for some reason it fails to infer `TDelay` from `...args` here and picks its default (`never`)
396 // then it fails to typecheck that because `...args` use `string` in place of `TDelay
397 actions.push(sendTo(...args));
398 };
399 enqueue.spawnChild = (...args) => {
400 actions.push(guards_dist_xstateGuards.spawnChild(...args));
401 };
402 enqueue.stopChild = (...args) => {
403 actions.push(guards_dist_xstateGuards.stopChild(...args));
404 };
405 enqueue.emit = (...args) => {
406 actions.push(emit(...args));
407 };
408 collect({
409 context: args.context,
410 event: args.event,
411 enqueue,
412 check: guard => guards_dist_xstateGuards.evaluateGuard(guard, snapshot.context, args.event, snapshot),
413 self: actorScope.self,
414 system: actorScope.system
415 }, actionParams);
416 return [snapshot, undefined, actions];
417}
418/**
419 * Creates an action object that will execute actions that are queued by the `enqueue(action)` function.
420 *
421 * @example
422 ```ts
423 import { createMachine, enqueueActions } from 'xstate';
424
425 const machine = createMachine({
426 entry: enqueueActions(({ enqueue, check }) => {
427 enqueue.assign({ count: 0 });
428
429 if (check('someGuard')) {
430 enqueue.assign({ count: 1 });
431 }
432
433 enqueue('someAction');
434 })
435 })
436 ```
437 */
438function enqueueActions(collect) {
439 function enqueueActions(args, params) {
440 }
441 enqueueActions.type = 'xstate.enqueueActions';
442 enqueueActions.collect = collect;
443 enqueueActions.resolve = resolveEnqueueActions;
444 return enqueueActions;
445}
446
447function resolveLog(_, snapshot, actionArgs, actionParams, {
448 value,
449 label
450}) {
451 return [snapshot, {
452 value: typeof value === 'function' ? value(actionArgs, actionParams) : value,
453 label
454 }];
455}
456function executeLog({
457 logger
458}, {
459 value,
460 label
461}) {
462 if (label) {
463 logger(label, value);
464 } else {
465 logger(value);
466 }
467}
468/**
469 *
470 * @param expr The expression function to evaluate which will be logged.
471 * Takes in 2 arguments:
472 * - `ctx` - the current state context
473 * - `event` - the event that caused this action to be executed.
474 * @param label The label to give to the logged expression.
475 */
476function log(value = ({
477 context,
478 event
479}) => ({
480 context,
481 event
482}), label) {
483 function log(args, params) {
484 }
485 log.type = 'xstate.log';
486 log.value = value;
487 log.label = label;
488 log.resolve = resolveLog;
489 log.execute = executeLog;
490 return log;
491}
492
493exports.SpecialTargets = SpecialTargets;
494exports.assign = assign;
495exports.emit = emit;
496exports.enqueueActions = enqueueActions;
497exports.forwardTo = forwardTo;
498exports.log = log;
499exports.sendParent = sendParent;
500exports.sendTo = sendTo;