@mantaq/sugar 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/dist/index.d.mts +56 -2
- package/dist/index.mjs +42 -8
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -307,6 +307,29 @@ broadcast(map, { type: "ping" });
|
|
|
307
307
|
|
|
308
308
|
Works with `ActorMap` or any object implementing `{ keys(): string[]; send(key, event): void }`.
|
|
309
309
|
|
|
310
|
+
### `onOutput(actor, handler)`
|
|
311
|
+
|
|
312
|
+
Route an actor's emitted outputs to a handler. `regions` auto-wire child
|
|
313
|
+
outputs into the parent; ActorMap children do not — this is the public
|
|
314
|
+
wrapper for that wiring seam, no internal import needed:
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
import { ActorMap, onOutput } from "@mantaq/sugar";
|
|
318
|
+
|
|
319
|
+
const requests = new ActorMap(
|
|
320
|
+
(id) => {
|
|
321
|
+
const child = createHandler(id);
|
|
322
|
+
onOutput(child, (e) => {
|
|
323
|
+
if (result.is(e)) parent.send(e);
|
|
324
|
+
});
|
|
325
|
+
return child;
|
|
326
|
+
},
|
|
327
|
+
{ autoReap: true },
|
|
328
|
+
);
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
The `is()` guard narrows the output to the receiver's declared input.
|
|
332
|
+
|
|
310
333
|
### `tag(...stateRefs)`
|
|
311
334
|
|
|
312
335
|
Group multiple `StateRef`s and test if a snapshot matches any of them. Useful for UI state grouping.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyActor, AnyEventRef, EffectInput, EventRef, InternalEvent, Snapshot, StateRef } from "@mantaq/core";
|
|
1
|
+
import { Actor, ActorBuilder, ActorOptions, AnyActor, AnyEventRef, AnyStateRef, Clock, EffectInput, EventRef, InitialState, InternalEvent, Snapshot, StateRef } from "@mantaq/core";
|
|
2
2
|
//#region src/actors/matches.d.ts
|
|
3
3
|
declare function matches(actor: {
|
|
4
4
|
snapshot(): Snapshot;
|
|
@@ -60,6 +60,16 @@ declare function states<const T extends StatesArg[]>(...entries: T): StatesRecor
|
|
|
60
60
|
//#region src/event.d.ts
|
|
61
61
|
declare function events<T extends string>(...names: T[]): { [K in T]: EventRef<K>; };
|
|
62
62
|
//#endregion
|
|
63
|
+
//#region src/output.d.ts
|
|
64
|
+
/**
|
|
65
|
+
* Route an actor's emitted outputs to a handler.
|
|
66
|
+
*
|
|
67
|
+
* `regions` auto-wire child outputs into the parent. ActorMap children do
|
|
68
|
+
* not — this is the public wrapper for that wiring seam. One call in the
|
|
69
|
+
* factory connects a child's declared outputs to a receiver.
|
|
70
|
+
*/
|
|
71
|
+
declare function onOutput(actor: AnyActor, handler: (event: InternalEvent) => void): void;
|
|
72
|
+
//#endregion
|
|
63
73
|
//#region src/effects/promise.d.ts
|
|
64
74
|
type EmitFn = (event: {
|
|
65
75
|
type: string;
|
|
@@ -85,8 +95,52 @@ interface Tag {
|
|
|
85
95
|
}
|
|
86
96
|
declare function tag(...stateNames: StateRef<string, unknown>[]): Tag;
|
|
87
97
|
//#endregion
|
|
98
|
+
//#region src/parts.d.ts
|
|
99
|
+
interface ActorSpec {
|
|
100
|
+
states: readonly AnyStateRef[];
|
|
101
|
+
inputs: readonly AnyEventRef[];
|
|
102
|
+
internal?: readonly AnyEventRef[];
|
|
103
|
+
outputs?: readonly AnyEventRef[];
|
|
104
|
+
context?: unknown;
|
|
105
|
+
initial: AnyStateRef | {
|
|
106
|
+
state: AnyStateRef;
|
|
107
|
+
payload?: unknown;
|
|
108
|
+
};
|
|
109
|
+
clock?: Clock;
|
|
110
|
+
regions?: Record<string, AnyActor>;
|
|
111
|
+
internalBudget?: number;
|
|
112
|
+
}
|
|
113
|
+
type NotUndef<T> = [Exclude<T, undefined>] extends [never] ? never : Exclude<T, undefined>;
|
|
114
|
+
type InternalOf<S extends ActorSpec> = "internal" extends keyof S ? [NotUndef<S["internal"]>] extends [never] ? readonly [] : NotUndef<S["internal"]> : readonly [];
|
|
115
|
+
type OutputsOf<S extends ActorSpec> = "outputs" extends keyof S ? [NotUndef<S["outputs"]>] extends [never] ? readonly [] : NotUndef<S["outputs"]> : readonly [];
|
|
116
|
+
type ContextOf<S extends ActorSpec> = "context" extends keyof S ? [NotUndef<S["context"]>] extends [never] ? Record<string, unknown> : NotUndef<S["context"]> : Record<string, unknown>;
|
|
117
|
+
type BuilderOf<S extends ActorSpec> = ActorBuilder<S["states"], S["inputs"], InternalOf<S>, OutputsOf<S>, ContextOf<S>>;
|
|
118
|
+
type Fragment<S extends ActorSpec> = (m: BuilderOf<S>) => void;
|
|
119
|
+
declare function definePart<S extends ActorSpec = never>(fn: (m: BuilderOf<S>) => void): Fragment<S>;
|
|
120
|
+
declare function use<S extends ActorSpec>(m: BuilderOf<S>, part: Fragment<S>): void;
|
|
121
|
+
type Part<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef[], Internal extends readonly AnyEventRef[], Outputs extends readonly AnyEventRef[], ActorContext> = (m: ActorBuilder<States, Inputs, Internal, Outputs, ActorContext>) => void;
|
|
122
|
+
type SpecValue<States extends readonly AnyStateRef[], Inputs extends readonly AnyEventRef[], Internal extends readonly AnyEventRef[], Outputs extends readonly AnyEventRef[], ActorContext, Initial> = {
|
|
123
|
+
states: States;
|
|
124
|
+
inputs: Inputs;
|
|
125
|
+
internal?: Internal;
|
|
126
|
+
outputs?: Outputs;
|
|
127
|
+
context?: ActorContext;
|
|
128
|
+
clock?: Clock;
|
|
129
|
+
regions?: Record<string, AnyActor>;
|
|
130
|
+
internalBudget?: number;
|
|
131
|
+
initial: Initial;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Construct the actor's static spec — states, inputs, internal/output events,
|
|
135
|
+
* context, initial state, clock, regions and budget. State/event tuples and
|
|
136
|
+
* the initial ref narrow to literals; the context stays mutable, so
|
|
137
|
+
* `definePart` handlers read and write it with no `as` casts.
|
|
138
|
+
*/
|
|
139
|
+
declare function actorSpec<const States extends readonly AnyStateRef[], const Inputs extends readonly AnyEventRef[], const Internal extends readonly AnyEventRef[] = readonly [], const Outputs extends readonly AnyEventRef[] = readonly [], ActorContext = Record<string, unknown>, const Initial extends InitialState<States[number]> = InitialState<States[number]>>(spec: SpecValue<States, Inputs, Internal, Outputs, ActorContext, Initial>): SpecValue<States, Inputs, Internal, Outputs, ActorContext, Initial>;
|
|
140
|
+
declare function withParts<const States extends readonly AnyStateRef[], const Inputs extends readonly AnyEventRef[], const Internal extends readonly AnyEventRef[] = readonly [], const Outputs extends readonly AnyEventRef[] = readonly [], ActorContext = Record<string, unknown>>(base: Omit<ActorOptions<States, Inputs, Internal, Outputs, ActorContext>, "setup">, parts: Part<States, Inputs, Internal, Outputs, ActorContext> | readonly Part<States, Inputs, Internal, Outputs, ActorContext>[]): Actor<States, Inputs, Internal, Outputs, ActorContext>;
|
|
141
|
+
//#endregion
|
|
88
142
|
//#region src/snapshot.d.ts
|
|
89
143
|
declare function isIn(snapshot: Snapshot, stateRefName: string): boolean;
|
|
90
144
|
declare function activeLeaves(snapshot: Snapshot): string[];
|
|
91
145
|
//#endregion
|
|
92
|
-
export { ActorMap, type EventLike, type SendableEvent, type SendableMap, activeLeaves, broadcast, events, isIn, matches, states, tag, withPromise, withTimeout };
|
|
146
|
+
export { ActorMap, type ActorSpec, type BuilderOf, type EventLike, type Fragment, type Part, type SendableEvent, type SendableMap, activeLeaves, actorSpec, broadcast, definePart, events, isIn, matches, onOutput, states, tag, use, withParts, withPromise, withTimeout };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Either } from "@mantaq/utils";
|
|
3
|
-
import { event, state } from "@mantaq/core";
|
|
1
|
+
import { Actor, event, state } from "@mantaq/core";
|
|
4
2
|
//#region src/actors/matches.ts
|
|
5
3
|
function matchSnapshot(snapshot, parts, index) {
|
|
6
4
|
const stateName = snapshot.path[0];
|
|
@@ -45,6 +43,7 @@ var ActorMap = class {
|
|
|
45
43
|
}
|
|
46
44
|
const off = child.on("done", () => {
|
|
47
45
|
if (this.#actors.get(key) === child) this.#actors.delete(key);
|
|
46
|
+
this.#reapers.delete(key);
|
|
48
47
|
});
|
|
49
48
|
this.#reapers.set(key, off);
|
|
50
49
|
}
|
|
@@ -53,10 +52,7 @@ var ActorMap = class {
|
|
|
53
52
|
this.#actors.get(key)?.send(event);
|
|
54
53
|
}
|
|
55
54
|
kill(key) {
|
|
56
|
-
|
|
57
|
-
if (actor) Either.match(abortEffects(actor), (err) => {
|
|
58
|
-
throw new Error(err.message);
|
|
59
|
-
}, () => {});
|
|
55
|
+
this.#actors.get(key)?.dispose();
|
|
60
56
|
this.#reapers.get(key)?.();
|
|
61
57
|
this.#reapers.delete(key);
|
|
62
58
|
this.#actors.delete(key);
|
|
@@ -96,6 +92,18 @@ function events(...names) {
|
|
|
96
92
|
return result;
|
|
97
93
|
}
|
|
98
94
|
//#endregion
|
|
95
|
+
//#region src/output.ts
|
|
96
|
+
/**
|
|
97
|
+
* Route an actor's emitted outputs to a handler.
|
|
98
|
+
*
|
|
99
|
+
* `regions` auto-wire child outputs into the parent. ActorMap children do
|
|
100
|
+
* not — this is the public wrapper for that wiring seam. One call in the
|
|
101
|
+
* factory connects a child's declared outputs to a receiver.
|
|
102
|
+
*/
|
|
103
|
+
function onOutput(actor, handler) {
|
|
104
|
+
actor.on("output", handler);
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
99
107
|
//#region src/effects/promise.ts
|
|
100
108
|
function withPromise(promise, signal, emit, events) {
|
|
101
109
|
promise.then((data) => {
|
|
@@ -137,4 +145,30 @@ function tag(...stateNames) {
|
|
|
137
145
|
return { has: (snapshot) => names.some((name) => isIn(snapshot, name)) };
|
|
138
146
|
}
|
|
139
147
|
//#endregion
|
|
140
|
-
|
|
148
|
+
//#region src/parts.ts
|
|
149
|
+
function definePart(fn) {
|
|
150
|
+
return fn;
|
|
151
|
+
}
|
|
152
|
+
function use(m, part) {
|
|
153
|
+
part(m);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Construct the actor's static spec — states, inputs, internal/output events,
|
|
157
|
+
* context, initial state, clock, regions and budget. State/event tuples and
|
|
158
|
+
* the initial ref narrow to literals; the context stays mutable, so
|
|
159
|
+
* `definePart` handlers read and write it with no `as` casts.
|
|
160
|
+
*/
|
|
161
|
+
function actorSpec(spec) {
|
|
162
|
+
return spec;
|
|
163
|
+
}
|
|
164
|
+
function withParts(base, parts) {
|
|
165
|
+
const list = Array.isArray(parts) ? parts : [parts];
|
|
166
|
+
return new Actor({
|
|
167
|
+
...base,
|
|
168
|
+
setup: (m) => {
|
|
169
|
+
for (const part of list) part(m);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
174
|
+
export { ActorMap, activeLeaves, actorSpec, broadcast, definePart, events, isIn, matches, onOutput, states, tag, use, withParts, withPromise, withTimeout };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mantaq/sugar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Userland sugar for mantaq actors — matches, effect helpers, transition utilities.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,8 +20,7 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@mantaq/core": "0.
|
|
24
|
-
"@mantaq/utils": "0.0.2"
|
|
23
|
+
"@mantaq/core": "0.3.0"
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
26
|
"@stryker-mutator/core": "^9",
|