Skip to content

Commit

Permalink
fix(types): normalize type arg names and XState imports
Browse files Browse the repository at this point in the history
- added `SpawnTarget` type for spawn functions
- fix several warnings emitted by TypeDoc
- add missing docstrings to a few things (still plenty left to do!)
  • Loading branch information
boneskull committed Sep 5, 2024
1 parent ea9aa5e commit 44077d3
Show file tree
Hide file tree
Showing 14 changed files with 1,821 additions and 791 deletions.
892 changes: 883 additions & 9 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"dev": "tshy --watch",
"dev:docs": "run-p \"docs:*\"",
"dev:types": "tsc -p tsconfig.tsc.json --watch",
"docs:serve": "npx serve docs",
"docs:serve": "serve docs",
"docs:watch": "typedoc --watch",
"format": "prettier .",
"lint": "eslint . --max-warnings 0",
Expand Down Expand Up @@ -104,6 +104,7 @@
"prettier-plugin-jsdoc": "1.3.0",
"prettier-plugin-organize-imports": "4.0.0",
"prettier-plugin-pkg": "0.18.1",
"serve": "14.2.3",
"tshy": "3.0.2",
"tsx": "4.19.0",
"typedoc": "0.26.6",
Expand Down
41 changes: 22 additions & 19 deletions src/actor.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
type AnyActorRef,
type InspectionEvent,
type Subscription,
} from 'xstate';
import type * as xs from 'xstate';

import {type AuditionOptions, type LoggerFn} from './types.js';
import {isActorRef} from './util.js';
Expand All @@ -12,18 +8,18 @@ import {isActorRef} from './util.js';
*
* @internal
*/
type PatchData = {inspectorSubscription?: Subscription; logger?: LoggerFn};
type PatchData = {inspectorSubscription?: xs.Subscription; logger?: LoggerFn};

/**
* A `WeakMap` to store the data for each `ActorRef` that has been patched. Used
* by {@link unpatchActor}.
*
* @internal
*/
const patchData = new WeakMap<AnyActorRef, PatchData[]>();
const patchData = new WeakMap<xs.AnyActorRef, PatchData[]>();

/**
* Utility to _mutate_ an existing {@link ActorRef} allowing addition of an
* Utility to _mutate_ an existing {@link TActor} allowing addition of an
* inspector and/or new logger.
*
* Inspectors are additive, so adding a new inspector is not destructive.
Expand Down Expand Up @@ -55,16 +51,16 @@ const patchData = new WeakMap<AnyActorRef, PatchData[]>();
* });
* ```
*
* @template Actor The type of `ActorRef` to patch
* @param actor An `ActorRef` (or `Actor`)
* @template TActor The type of `ActorRef` to patch
* @param actor An {@link xs.ActorRef} (or {@link xs.Actor})
* @param options Options
* @returns The original `actor`, but modified
* @see {@link https://stately.ai/docs/inspection}
*/
export function patchActor<Actor extends AnyActorRef>(
actor: Actor,
export function patchActor<TActor extends xs.AnyActorRef>(
actor: TActor,
{inspector, logger}: AuditionOptions = {},
): Actor {
): TActor {
if (!isActorRef(actor)) {
throw new TypeError('patchActor() called with a non-ActorRef', {
cause: actor,
Expand Down Expand Up @@ -133,12 +129,14 @@ export function patchActor<Actor extends AnyActorRef>(
* This function is not currently used internally and is considered
* **experimental**. It may be removed in the future if it does not prove to
* have a reasonable use-case.
* @template Actor The type of the `ActorRef` to unpatch
* @template TActor The type of the `ActorRef` to unpatch
* @param actor `ActorRef` or `Actor` to unpatch
* @returns `actor`, but unpatched
* @experimental
*/
export function unpatchActor<Actor extends AnyActorRef>(actor: Actor): Actor {
export function unpatchActor<TActor extends xs.AnyActorRef>(
actor: TActor,
): TActor {
const data = patchData.get(actor);

if (!data) {
Expand Down Expand Up @@ -169,13 +167,18 @@ export function unpatchActor<Actor extends AnyActorRef>(actor: Actor): Actor {
}

/**
* @param param0
* @returns
* Returns a function which patches an `ActorRef` with the given options.
*
* Avoids patching the same `ActorRef` multiple times.
*
* @param options
* @returns Function to patch an `ActorRef`
* @internal
*/
export function createPatcher(opts: AuditionOptions = {}) {
const knownActorRefs = new WeakSet<AnyActorRef>();
const knownActorRefs = new WeakSet<xs.AnyActorRef>();

return (evt: AnyActorRef | InspectionEvent) => {
return (evt: xs.AnyActorRef | xs.InspectionEvent) => {
if (isActorRef(evt)) {
if (!knownActorRefs.has(evt)) {
patchActor(evt, opts);
Expand Down
5 changes: 5 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* The type of an `InspectionEvent` object representing an event sent to an
* Actor.
*/
export const XSTATE_EVENT = '@xstate.event';
94 changes: 58 additions & 36 deletions src/create-actor.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,88 @@
import {
type Actor,
type ActorOptions,
type AnyActorLogic,
createActor,
type InputFrom,
type IsNotNever,
} from 'xstate';

export type RequiredOptions<TLogic extends AnyActorLogic> =
undefined extends InputFrom<TLogic> ? never : 'input';

export type CreateActorOptions<TLogic extends AnyActorLogic> =
IsNotNever<RequiredOptions<TLogic>> extends true
? {input: ActorOptions<TLogic>['input']} & ActorOptions<TLogic>
: ActorOptions<TLogic>;
import * as xs from 'xstate';

/**
* Required input values for `TLogic`.
*
* @template TLogic Actor logic type
* @see {@link CreateActorOptions}
*/
export type RequiredOptions<TLogic extends xs.AnyActorLogic> =
undefined extends xs.InputFrom<TLogic> ? never : 'input';

/**
* Options for creating an actor from actor logic.
*
* @see {@link createActorFromLogic}
* @see {@link createActorWith}
*/
export type CreateActorOptions<TLogic extends xs.AnyActorLogic> =
xs.IsNotNever<RequiredOptions<TLogic>> extends true
? {input: xs.ActorOptions<TLogic>['input']} & xs.ActorOptions<TLogic>
: xs.ActorOptions<TLogic>;

export type CurryCreateActorFromLogic = (() => CurryCreateActorFromLogic) &
(<TLogic extends AnyActorLogic>(
(<TLogic extends xs.AnyActorLogic>(
logic: TLogic,
options: CreateActorOptions<TLogic>,
) => Actor<TLogic>) &
(<TLogic extends AnyActorLogic>(
) => xs.Actor<TLogic>) &
(<TLogic extends xs.AnyActorLogic>(
logic: TLogic,
) => CurryCreateActorFromLogicP1<TLogic>);

export type CurryCreateActorFromLogicP1<TLogic extends AnyActorLogic> = ((
export type CurryCreateActorFromLogicP1<TLogic extends xs.AnyActorLogic> = ((
options: CreateActorOptions<TLogic>,
) => Actor<TLogic>) &
) => xs.Actor<TLogic>) &
(() => CurryCreateActorFromLogicP1<TLogic>);

export type CurryCreateActorWith = (() => CurryCreateActorWith) &
(<TLogic extends AnyActorLogic>(
(<TLogic extends xs.AnyActorLogic>(
options: CreateActorOptions<TLogic>,
logic: TLogic,
) => Actor<TLogic>) &
(<TLogic extends AnyActorLogic>(
) => xs.Actor<TLogic>) &
(<TLogic extends xs.AnyActorLogic>(
options: CreateActorOptions<TLogic>,
) => CurryCreateActorWithP1<TLogic>);

export type CurryCreateActorWithP1<TLogic extends AnyActorLogic> = ((
export type CurryCreateActorWithP1<TLogic extends xs.AnyActorLogic> = ((
logic: TLogic,
) => Actor<TLogic>) &
) => xs.Actor<TLogic>) &
(() => CurryCreateActorWithP1<TLogic>);

/**
* Returns itself
*/
export function createActorFromLogic(): typeof createActorFromLogic;

export function createActorFromLogic<TLogic extends AnyActorLogic>(
/**
* Returns a function which accepts {@link CreateActorOptions} and returns a
* function which accepts actor logic, then creates an `Actor`.
*
* @template TLogic Actor logic type
* @param logic Actor logic
*/
export function createActorFromLogic<TLogic extends xs.AnyActorLogic>(
logic: TLogic,
): CurryCreateActorFromLogicP1<TLogic>;

export function createActorFromLogic<TLogic extends AnyActorLogic>(
/**
* Creates an actor from actor logic and options.
*
* @template TLogic Actor logic type
* @param logic Actor logic
* @param options Options
*/
export function createActorFromLogic<TLogic extends xs.AnyActorLogic>(
logic: TLogic,
options: CreateActorOptions<TLogic>,
): Actor<TLogic>;
): xs.Actor<TLogic>;

export function createActorFromLogic<TLogic extends AnyActorLogic>(
export function createActorFromLogic<TLogic extends xs.AnyActorLogic>(
logic?: TLogic,
options?: CreateActorOptions<TLogic>,
) {
if (logic) {
if (options) {
return createActor(logic, options);
return xs.createActor(logic, options);
}

return ((options?: CreateActorOptions<TLogic>) => {
Expand All @@ -75,22 +97,22 @@ export function createActorFromLogic<TLogic extends AnyActorLogic>(

export function createActorWith(): typeof createActorWith;

export function createActorWith<TLogic extends AnyActorLogic>(
export function createActorWith<TLogic extends xs.AnyActorLogic>(
options: CreateActorOptions<TLogic>,
): CurryCreateActorWithP1<TLogic>;

export function createActorWith<TLogic extends AnyActorLogic>(
export function createActorWith<TLogic extends xs.AnyActorLogic>(
options: CreateActorOptions<TLogic>,
logic: TLogic,
): Actor<TLogic>;
): xs.Actor<TLogic>;

export function createActorWith<TLogic extends AnyActorLogic>(
export function createActorWith<TLogic extends xs.AnyActorLogic>(
options?: CreateActorOptions<TLogic>,
logic?: TLogic,
) {
if (options) {
if (logic) {
return createActor(logic, options);
return xs.createActor(logic, options);
}

return ((logic?: TLogic) => {
Expand Down
4 changes: 2 additions & 2 deletions src/timer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/prefer-promise-reject-errors */
import {type AnyActorRef} from 'xstate';
import type * as xs from 'xstate';

import {noop} from './util.js';

Expand All @@ -14,7 +14,7 @@ import {noop} from './util.js';
* @param message Timeout message
*/
export function startTimer(
actor: AnyActorRef,
actor: xs.AnyActorRef,
abortController: AbortController,
timeout: number,
message?: string,
Expand Down
38 changes: 17 additions & 21 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,28 @@ import type * as xs from 'xstate';
* A tuple of events Event by an actor, based on a {@link ActorEventTypeTuple}
*/
export type ActorEventTuple<
Actor extends AnyActor,
EventTypes extends Readonly<ActorEventTypeTuple<Actor>>,
TActor extends AnyActor,
TEventTypes extends Readonly<ActorEventTypeTuple<TActor>>,
> = {
-readonly [K in keyof EventTypes]: EventFromEventType<Actor, EventTypes[K]>;
-readonly [K in keyof TEventTypes]: EventFromEventType<
TActor,
TEventTypes[K]
>;
};

/**
* The `type` prop of any event or Event event from an actor
*/
export type ActorEventType<Actor extends AnyActor> =
xs.EventFromLogic<Actor['logic']> extends xs.EventObject
? xs.EventFromLogic<Actor['logic']>['type']
export type ActorEventType<TActor extends AnyActor> =
xs.EventFromLogic<TActor['logic']> extends xs.EventObject
? xs.EventFromLogic<TActor['logic']>['type']
: string;

/**
* A tuple of event types (event names) Event by an actor
*/
export type ActorEventTypeTuple<Actor extends AnyActor> = ReadableArray<
[ActorEventType<Actor>, ...ActorEventType<Actor>[]]
export type ActorEventTypeTuple<TActor extends AnyActor> = ReadableArray<
[ActorEventType<TActor>, ...ActorEventType<TActor>[]]
>;

export type AnyActor = xs.AnyActor;
Expand Down Expand Up @@ -71,18 +74,18 @@ export type AuditionOptions = {
};

/**
* Given a XState Actor and an {@link EventObject.type event type} (the `type`
* Given a XState Actor and an {@link xs.EventObject.type event type} (the `type`
* field of an `EventObject`), returns the type of the corresponding event.
*
* Does not apply to "emitted" events.
*
* @template Actor The State Machine Actor
* @template EventType The event type (the `type` field of the `EventObject`)
* @template TActor The State Machine Actor
* @template TEventType The event type (the `type` field of the `EventObject`)
*/
export type EventFromEventType<
Actor extends AnyActor,
EventType extends ActorEventType<Actor>,
> = xs.ExtractEvent<xs.EventFromLogic<Actor['logic']>, EventType>;
TActor extends AnyActor,
TEventType extends ActorEventType<TActor>,
> = xs.ExtractEvent<xs.EventFromLogic<TActor['logic']>, TEventType>;

/**
* An inspector function or XState `Observer` for an Actor
Expand Down Expand Up @@ -129,13 +132,6 @@ export type AnyEventReceiverLogic =
| SomeTransitionLogic
| xs.ActorLogic<xs.CallbackSnapshot<any>, any, any, any, any>;

/**
* Any actor logic that can send events
*
* @see {@link https://stately.ai/docs/actors#actor-logic-capabilities}
*/
export type AnyEventSenderLogic = xs.AnyActorLogic;

/**
* Any actor logic which can theoretically emit snapshots
*
Expand Down
Loading

0 comments on commit 44077d3

Please sign in to comment.