@nanobpm/workflow 0.8.2 → 0.9.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/dist/declarative.d.ts +172 -10
- package/dist/declarative.js +213 -355
- package/dist/nodes/branch.d.ts +11 -0
- package/dist/nodes/branch.js +40 -0
- package/dist/nodes/break.d.ts +8 -0
- package/dist/nodes/break.js +19 -0
- package/dist/nodes/continue.d.ts +8 -0
- package/dist/nodes/continue.js +18 -0
- package/dist/nodes/forEach.d.ts +24 -0
- package/dist/nodes/forEach.js +104 -0
- package/dist/nodes/index.d.ts +11 -0
- package/dist/nodes/index.js +18 -0
- package/dist/nodes/loop.d.ts +9 -0
- package/dist/nodes/loop.js +25 -0
- package/dist/nodes/parallel.d.ts +9 -0
- package/dist/nodes/parallel.js +40 -0
- package/dist/nodes/registry.d.ts +33 -0
- package/dist/nodes/registry.js +71 -0
- package/dist/nodes/run.d.ts +10 -0
- package/dist/nodes/run.js +21 -0
- package/dist/nodes/signal.d.ts +11 -0
- package/dist/nodes/signal.js +21 -0
- package/dist/nodes/switch.d.ts +11 -0
- package/dist/nodes/switch.js +51 -0
- package/dist/nodes/task.d.ts +11 -0
- package/dist/nodes/task.js +21 -0
- package/dist/nodes/timer.d.ts +9 -0
- package/dist/nodes/timer.js +34 -0
- package/dist/test-support/diff.d.ts +8 -0
- package/dist/test-support/diff.js +70 -0
- package/dist/test-support/index.d.ts +8 -0
- package/dist/test-support/index.js +49 -0
- package/dist/test-support/normalize.d.ts +19 -0
- package/dist/test-support/normalize.js +245 -0
- package/dist/test-support/parity.d.ts +28 -0
- package/dist/test-support/parity.js +61 -0
- package/dist/test-support/xml.d.ts +17 -0
- package/dist/test-support/xml.js +135 -0
- package/dist/types.d.ts +20 -56
- package/package.json +12 -4
- package/src/declarative.ts +327 -359
- package/src/nodes/README.md +123 -0
- package/src/nodes/branch.ts +48 -0
- package/src/nodes/break.ts +25 -0
- package/src/nodes/continue.ts +24 -0
- package/src/nodes/forEach.ts +137 -0
- package/src/nodes/index.ts +19 -0
- package/src/nodes/loop.ts +34 -0
- package/src/nodes/parallel.ts +48 -0
- package/src/nodes/registry.ts +105 -0
- package/src/nodes/run.ts +29 -0
- package/src/nodes/signal.ts +29 -0
- package/src/nodes/switch.ts +56 -0
- package/src/nodes/task.ts +29 -0
- package/src/nodes/timer.ts +42 -0
- package/src/test-support/diff.ts +69 -0
- package/src/test-support/index.ts +53 -0
- package/src/test-support/normalize.ts +274 -0
- package/src/test-support/parity.ts +85 -0
- package/src/test-support/xml.ts +140 -0
- package/src/types.ts +20 -30
package/dist/declarative.d.ts
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import type { DeclarativeFlow, FlowContracts, FlowNode, JsonObject } from "./types.js";
|
|
1
|
+
import type { DeclarativeFlow, FlowContracts, FlowNode, JsonObject, NodeEnvelopes, StepHandler, TimerStart } from "./types.js";
|
|
2
2
|
import type { Envelope } from "./envelope.js";
|
|
3
|
+
import "./nodes/index.js";
|
|
3
4
|
/** The TS payload type of a contract's input envelope (untyped fallback). */
|
|
4
|
-
type InPayload<Ct> = Ct extends {
|
|
5
|
+
export type InPayload<Ct> = Ct extends {
|
|
5
6
|
in: Envelope;
|
|
6
7
|
} ? Ct["in"]["type"] & JsonObject : JsonObject;
|
|
7
8
|
/** The TS payload type of a contract's output envelope (untyped fallback). */
|
|
8
|
-
type OutPayload<Ct> = Ct extends {
|
|
9
|
+
export type OutPayload<Ct> = Ct extends {
|
|
9
10
|
out: Envelope;
|
|
10
11
|
} ? Ct["out"]["type"] & JsonObject : JsonObject;
|
|
11
12
|
/** The input payload type of step `K` under contracts `C`. */
|
|
12
|
-
type VarsOf<C, K extends string> = K extends keyof C ? InPayload<C[K]> : JsonObject;
|
|
13
|
+
export type VarsOf<C, K extends string> = K extends keyof C ? InPayload<C[K]> : JsonObject;
|
|
13
14
|
/** The output payload type of step `K` under contracts `C`. */
|
|
14
|
-
type ResultOf<C, K extends string> = K extends keyof C ? OutPayload<C[K]> : JsonObject;
|
|
15
|
+
export type ResultOf<C, K extends string> = K extends keyof C ? OutPayload<C[K]> : JsonObject;
|
|
15
16
|
/** A typed handler for a `run` step: its job variables and result are resolved
|
|
16
17
|
* from the flow contracts by the step name. */
|
|
17
|
-
type TypedHandler<V extends JsonObject, R extends JsonObject> = (job: {
|
|
18
|
+
export type TypedHandler<V extends JsonObject, R extends JsonObject> = (job: {
|
|
18
19
|
jobKey: string;
|
|
19
20
|
processInstanceKey: string;
|
|
20
21
|
elementId: string;
|
|
@@ -22,7 +23,7 @@ type TypedHandler<V extends JsonObject, R extends JsonObject> = (job: {
|
|
|
22
23
|
variables: V;
|
|
23
24
|
}) => Promise<R | void> | R | void;
|
|
24
25
|
/** A block: the callback that populates a nested body (a case, arm, or loop). */
|
|
25
|
-
type Block<C extends object> = (b: FlowBuilder<C>) => void;
|
|
26
|
+
export type Block<C extends object = object> = (b: FlowBuilder<C>) => void;
|
|
26
27
|
/** The typed builder for a flow body.
|
|
27
28
|
*
|
|
28
29
|
* `C` is the flow's contracts map (step name → `{ in, out }` envelopes). The
|
|
@@ -157,6 +158,62 @@ export interface FlowBuilder<C extends object = object> {
|
|
|
157
158
|
* the body. Only valid inside a `loop`. */
|
|
158
159
|
continue(): FlowBuilder<C>;
|
|
159
160
|
}
|
|
161
|
+
/** A builder method as stored on the dynamically-assembled builder. Its precise,
|
|
162
|
+
* generic user-facing signature comes from the `FlowBuilder<C>` interface (a
|
|
163
|
+
* built-in method declared centrally, a slice method declaration-merged from
|
|
164
|
+
* its module); this loose shape is only what the registry stores/installs. */
|
|
165
|
+
export type BuilderMethod = (...args: never[]) => unknown;
|
|
166
|
+
/** The per-body authoring context a kind module's `build` factory closes over to
|
|
167
|
+
* implement its builder method. Everything a method needs to append its node —
|
|
168
|
+
* claim its step name, resolve contract envelopes, recurse into nested bodies,
|
|
169
|
+
* and return the builder for chaining — without reaching into `declarative.ts`
|
|
170
|
+
* internals or the shared `FlowNode` union. */
|
|
171
|
+
export interface BuildApi {
|
|
172
|
+
/** The flow id (for error messages). */
|
|
173
|
+
readonly id: string;
|
|
174
|
+
/** Whether this is the root (top-level) builder — e.g. `startOn` is root-only. */
|
|
175
|
+
readonly isRoot: boolean;
|
|
176
|
+
/** The node list this builder appends to (`api.out.push(node)`). */
|
|
177
|
+
readonly out: FlowNode[];
|
|
178
|
+
/** The flow's typed I/O contracts, keyed by step name. */
|
|
179
|
+
readonly contracts: FlowContracts;
|
|
180
|
+
/** The flow's handler registry — a `run`-like kind registers its handler here. */
|
|
181
|
+
readonly handlers: Record<string, StepHandler>;
|
|
182
|
+
/** The current loop-nesting depth (0 outside any loop) — `break`/`continue`
|
|
183
|
+
* guard on it. */
|
|
184
|
+
readonly loopDepth: number;
|
|
185
|
+
/** The builder itself, for chaining (`return api.self()`). */
|
|
186
|
+
self(): FlowBuilder;
|
|
187
|
+
/** Populate a nested body block, returning its node list. `inLoop` deepens the
|
|
188
|
+
* loop nesting (a `loop` body); use it for bodies that can `break`/`continue`. */
|
|
189
|
+
child(fn: (b: FlowBuilder) => void, inLoop: boolean): FlowNode[];
|
|
190
|
+
/** Populate a nested body that runs in its OWN token scope (an embedded
|
|
191
|
+
* sub-process): `break`/`continue` cannot cross the boundary (loop depth 0). */
|
|
192
|
+
childScoped(fn: (b: FlowBuilder) => void): FlowNode[];
|
|
193
|
+
/** Claim a step name (rejects duplicates / reserved ids), as every leaf does. */
|
|
194
|
+
claim(name: string): void;
|
|
195
|
+
/** Resolve the declared envelopes for a step name from the contracts. */
|
|
196
|
+
contractEnvelopes(name: string): {
|
|
197
|
+
in?: Envelope;
|
|
198
|
+
out?: Envelope;
|
|
199
|
+
} | undefined;
|
|
200
|
+
/** Lift a durable timer start onto the flow (used only by `startOn`). */
|
|
201
|
+
setStartTimer(t: TimerStart): void;
|
|
202
|
+
}
|
|
203
|
+
/** A dynamically-assembled builder satisfies `FlowBuilder<C>` once every core
|
|
204
|
+
* built-in method is installed. The check is a runtime type guard (not an `as`
|
|
205
|
+
* cast): each own-property must be a function, AND every built-in method in
|
|
206
|
+
* {@link BUILTIN_BUILDER_METHODS} must be present — so a missing or
|
|
207
|
+
* tree-shaken node-kind registration fails fast here at builder assembly (a
|
|
208
|
+
* clear "missing registered methods" error) instead of surfacing later as an
|
|
209
|
+
* opaque `w.run is not a function` at authoring time. */
|
|
210
|
+
export declare function isFlowBuilder<C extends object = object>(x: object): x is FlowBuilder<C>;
|
|
211
|
+
/** Diagnostic for a failed builder assembly. Names the missing built-in
|
|
212
|
+
* method(s) when a registration was tree-shaken/omitted so the failure is
|
|
213
|
+
* actionable; otherwise, when every built-in is present but some own-property
|
|
214
|
+
* isn't a function, names that offending property instead. Exported (like
|
|
215
|
+
* {@link isFlowBuilder}) so the assembly invariant is unit-testable. */
|
|
216
|
+
export declare function assemblyFailureMessage(x: object): string;
|
|
160
217
|
/**
|
|
161
218
|
* Define a declarative flow. Pass a typed `contracts` map (keyed by step name)
|
|
162
219
|
* to type each step's I/O and lift its data envelopes into the model; or omit it
|
|
@@ -164,8 +221,13 @@ export interface FlowBuilder<C extends object = object> {
|
|
|
164
221
|
*/
|
|
165
222
|
export declare function defineFlow<C extends FlowContracts>(id: string, contracts: C, build: (w: FlowBuilder<C>) => void): DeclarativeFlow;
|
|
166
223
|
export declare function defineFlow(id: string, build: (w: FlowBuilder) => void): DeclarativeFlow;
|
|
167
|
-
/** Depth-first visit of every node in a flow tree
|
|
168
|
-
*
|
|
224
|
+
/** Depth-first visit of every node in a flow tree. Recursion into a kind's
|
|
225
|
+
* nested bodies is DISPATCHED through the registry (each kind's `walk` handler),
|
|
226
|
+
* so a slice's structural combinator recurses without editing a central switch.
|
|
227
|
+
* Fails fast (via `requireNodeKind`) on an unregistered kind — matching the
|
|
228
|
+
* emitter — so a tree-shaken/missing registration surfaces as a clear error
|
|
229
|
+
* rather than silently skipping recursion into that node's nested bodies. A
|
|
230
|
+
* registered leaf kind with no `walk` handler is fine (nothing to recurse). */
|
|
169
231
|
export declare function walkNodes(nodes: FlowNode[], visit: (n: FlowNode) => void): void;
|
|
170
232
|
/** The job types of a flow's external `task` steps (anywhere in the tree) — the
|
|
171
233
|
* contract workers outside this program must subscribe to. Each is the derived
|
|
@@ -173,6 +235,106 @@ export declare function walkNodes(nodes: FlowNode[], visit: (n: FlowNode) => voi
|
|
|
173
235
|
* { jobType })`. Deduplicated (preserving first-seen order) since several steps
|
|
174
236
|
* may intentionally share one override token. */
|
|
175
237
|
export declare function externalJobTypes(flow: DeclarativeFlow): string[];
|
|
238
|
+
/** A renderable BPMN element the emitter has placed. A kind's `emit` handler
|
|
239
|
+
* adds one (or more) via `api.addNode(...)` (or a typed helper like
|
|
240
|
+
* `api.addServiceTask`). */
|
|
241
|
+
export interface RenderNode {
|
|
242
|
+
id: string;
|
|
243
|
+
render(incoming: string[], outgoing: string[]): string;
|
|
244
|
+
/** For exclusive gateways: the flow id of the unconditional default edge. */
|
|
245
|
+
defaultFlow?: string;
|
|
246
|
+
/** Id of the embedded sub-process this node lives in, or undefined at the
|
|
247
|
+
* top level (the root process). */
|
|
248
|
+
scope?: string;
|
|
249
|
+
}
|
|
250
|
+
/** A BPMN sequence flow being wired. A kind's `emit` handler creates danglers
|
|
251
|
+
* with `api.newEdge(from)` and resolves them with `api.connect(edges, toId)`. */
|
|
252
|
+
export interface Edge {
|
|
253
|
+
id: string;
|
|
254
|
+
from: string;
|
|
255
|
+
to?: string;
|
|
256
|
+
condition?: string;
|
|
257
|
+
name?: string;
|
|
258
|
+
/** The scope (sub-process id, or undefined = root process) this flow is
|
|
259
|
+
* nested in — so it renders inside the right container. */
|
|
260
|
+
scope?: string;
|
|
261
|
+
}
|
|
262
|
+
/** The enclosing-loop context threaded through `emit`: `break`/`continue` route
|
|
263
|
+
* to `headId`, and `break` danglers collect in `breaks`. `null` outside a loop. */
|
|
264
|
+
export interface LoopCtx {
|
|
265
|
+
headId: string;
|
|
266
|
+
breaks: Edge[];
|
|
267
|
+
}
|
|
268
|
+
/** The emitter primitives a kind's `emit` handler uses to place its BPMN nodes
|
|
269
|
+
* and wire its sequence flows — WITHOUT reaching into `Compiler` internals or a
|
|
270
|
+
* central emit switch. Built-in kinds and slice-added kinds emit through this
|
|
271
|
+
* same surface. Node-render string helpers (`incomingOutgoing`, `escapeXml`, …)
|
|
272
|
+
* are exported alongside for building custom `RenderNode.render` closures. */
|
|
273
|
+
export interface EmitApi {
|
|
274
|
+
/** The flow id (for error messages). */
|
|
275
|
+
readonly flowId: string;
|
|
276
|
+
/** Create a new (dangling) sequence flow from `from`; resolve its target with
|
|
277
|
+
* `connect`. */
|
|
278
|
+
newEdge(from: string, opts?: {
|
|
279
|
+
condition?: string;
|
|
280
|
+
name?: string;
|
|
281
|
+
}): Edge;
|
|
282
|
+
/** Point every one of `incoming` at `toId`. */
|
|
283
|
+
connect(incoming: Edge[], toId: string): void;
|
|
284
|
+
/** Record a referenced data envelope so it is lifted to a `nano:shape`. */
|
|
285
|
+
recordEnvelope(env?: Envelope): void;
|
|
286
|
+
/** Emit a sequence of nodes, threading danglers; used to emit nested bodies. */
|
|
287
|
+
emitList(list: FlowNode[], incoming: Edge[], loop: LoopCtx | null): Edge[];
|
|
288
|
+
/** Place a fully custom BPMN element (a slice's own render closure). */
|
|
289
|
+
addNode(node: RenderNode): void;
|
|
290
|
+
/** Place a `<bpmn:serviceTask>` with the standard taskDefinition/envelope
|
|
291
|
+
* extension elements (optionally with multi-instance characteristics). */
|
|
292
|
+
addServiceTask(node: {
|
|
293
|
+
name: string;
|
|
294
|
+
envelopes?: NodeEnvelopes;
|
|
295
|
+
jobType?: string;
|
|
296
|
+
}, mi?: string): void;
|
|
297
|
+
/** Place a `<bpmn:intermediateCatchEvent>` with a message event definition. */
|
|
298
|
+
addCatchEvent(node: {
|
|
299
|
+
name: string;
|
|
300
|
+
}): void;
|
|
301
|
+
/** Place a `<bpmn:intermediateCatchEvent>` with a timer event definition. */
|
|
302
|
+
addTimerCatchEvent(node: {
|
|
303
|
+
name: string;
|
|
304
|
+
after?: string;
|
|
305
|
+
at?: string;
|
|
306
|
+
}): void;
|
|
307
|
+
/** Place a `<bpmn:exclusiveGateway>`, returning it so `defaultFlow` can be set. */
|
|
308
|
+
addGateway(id: string, name?: string): RenderNode;
|
|
309
|
+
/** Place a `<bpmn:parallelGateway>`. */
|
|
310
|
+
addParallelGateway(id: string): RenderNode;
|
|
311
|
+
/** Place an embedded `<bpmn:subProcess>` whose body renders in its own scope. */
|
|
312
|
+
addSubProcess(id: string, mi: string): RenderNode;
|
|
313
|
+
/** Place a plain none `<bpmn:startEvent>` (for an embedded sub-process). */
|
|
314
|
+
addPlainStart(id: string): void;
|
|
315
|
+
/** Place a plain `<bpmn:endEvent>` (for an embedded sub-process). */
|
|
316
|
+
addPlainEnd(id: string): void;
|
|
317
|
+
/** A fresh monotonic counter value for generated gateway/loop/sub ids. */
|
|
318
|
+
nextGw(): number;
|
|
319
|
+
/** The current scope (enclosing sub-process id, or undefined at the top level). */
|
|
320
|
+
currentScope(): string | undefined;
|
|
321
|
+
/** Open a sub-process scope (subsequent nodes/edges nest inside it). */
|
|
322
|
+
pushScope(id: string): void;
|
|
323
|
+
/** Close the current sub-process scope. */
|
|
324
|
+
popScope(): void;
|
|
325
|
+
}
|
|
176
326
|
/** Derive an executable BPMN model from a declarative flow. */
|
|
177
327
|
export declare function declarativeToBpmn(flow: DeclarativeFlow): string;
|
|
178
|
-
|
|
328
|
+
/** Wrap a raw FEEL expression as a Zeebe condition body (leading `=`). Exported
|
|
329
|
+
* for slice-added combinators that emit conditional sequence flows. */
|
|
330
|
+
export declare const feel: (expr: string) => string;
|
|
331
|
+
/** A FEEL equality test `subject = "value"`, with the value as a FEEL string.
|
|
332
|
+
* Exported for slice-added combinators that emit an XOR gateway. */
|
|
333
|
+
export declare const feelEquals: (subject: string, value: string) => string;
|
|
334
|
+
/** Render the `<bpmn:incoming>`/`<bpmn:outgoing>` refs of a flow node. Exported
|
|
335
|
+
* for slice `RenderNode.render` closures. */
|
|
336
|
+
export declare function incomingOutgoing(inc: string[], outg: string[]): string;
|
|
337
|
+
/** Render only the `<bpmn:incoming>` refs (for end-like events). Exported. */
|
|
338
|
+
export declare const incomingOnly: (inc: string[]) => string;
|
|
339
|
+
/** Render only the `<bpmn:outgoing>` refs (for start-like events). Exported. */
|
|
340
|
+
export declare const outgoingOnly: (outg: string[]) => string;
|