process-graph 1.0.6 → 1.1.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.
Files changed (58) hide show
  1. package/README.md +85 -17
  2. package/dist/bin.d.ts +1 -0
  3. package/dist/bin.js +92 -0
  4. package/dist/cli.d.ts +512 -0
  5. package/dist/cli.js +3 -0
  6. package/dist/control-aDk9560d.js +294 -0
  7. package/dist/detail-panel-B1ZmMuJT.js +341 -0
  8. package/dist/dist-BpCBmnMl.js +582 -0
  9. package/dist/dist-HLlW8vgT.js +1388 -0
  10. package/dist/dist-IjrgWhHQ.js +3 -0
  11. package/dist/errors-BZe5WzCn.js +19 -0
  12. package/dist/exit-codes-0ultCqdS.js +23 -0
  13. package/dist/graphql-C1j5wQFz.d.ts +631 -0
  14. package/dist/index-CCfe0csl.d.ts +353 -0
  15. package/dist/index-CmZOswkx.d.ts +512 -0
  16. package/dist/index-CoA6vXqe.d.ts +404 -0
  17. package/dist/index-CptUHq6F.d.ts +58 -0
  18. package/dist/index-CrM5qWUA.d.ts +110 -0
  19. package/dist/index-DhbvDgK4.d.ts +1582 -0
  20. package/dist/index-DricKcyl.d.ts +421 -0
  21. package/dist/index.d.ts +111 -4
  22. package/dist/index.js +929 -5
  23. package/dist/layout-CCM-KBdp.js +307 -0
  24. package/dist/layout.d.ts +8 -0
  25. package/dist/layout.js +2 -0
  26. package/dist/node-AchI1T-K.js +40 -0
  27. package/dist/open-CyRXJ4bt.js +29 -0
  28. package/dist/parse-CuipC_2K.js +41 -0
  29. package/dist/queries-CCexJAE2.js +2202 -0
  30. package/dist/react-flow/style.css +658 -0
  31. package/dist/react-flow.d.ts +173 -0
  32. package/dist/react-flow.js +450 -0
  33. package/dist/react.d.ts +2 -0
  34. package/dist/react.js +107 -0
  35. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  36. package/dist/router-D4gtTlXm.js +188 -0
  37. package/dist/schema-CVnS6HiX.js +234 -0
  38. package/dist/selection-BW_xXWOy.js +314 -0
  39. package/dist/source/github/node.d.ts +16 -0
  40. package/dist/source/github/node.js +2 -0
  41. package/dist/source/github.d.ts +49 -0
  42. package/dist/source/github.js +201 -0
  43. package/dist/source-DRDpEA8Q.js +1316 -0
  44. package/dist/status-Bm1CGu9C.js +11 -0
  45. package/dist/store/node.d.ts +24 -0
  46. package/dist/store/node.js +2 -0
  47. package/dist/store/wasm/worker.d.ts +16 -0
  48. package/dist/store/wasm/worker.js +98 -0
  49. package/dist/store/wasm.d.ts +9 -0
  50. package/dist/store/wasm.js +11 -0
  51. package/dist/store-BcR70CaO.js +1287 -0
  52. package/dist/store.d.ts +1328 -0
  53. package/dist/store.js +238 -0
  54. package/dist/ui/style.css +351 -0
  55. package/dist/ui.d.ts +235 -0
  56. package/dist/ui.js +2 -0
  57. package/dist/validate-DF3mQZww.js +125 -0
  58. package/package.json +148 -13
@@ -0,0 +1,2202 @@
1
+ import { a as findCycles, d as lookup$1, f as CycleError, i as assertAcyclic, o as stronglyConnectedComponents, p as UnknownNodeError, r as loopTransitions, t as controlDag, u as buildDag } from "./control-aDk9560d.js";
2
+ import { createSyncEvaluator } from "trilean";
3
+ //#region ../../core/graph/projection/dist/actors.js
4
+ const actorMap = (model) => {
5
+ const actors = /* @__PURE__ */ new Map();
6
+ for (const element of model.elements) if ((element.kind === "activity" || element.kind === "decision") && element.actor !== void 0) actors.set(element.id, element.actor);
7
+ return actors;
8
+ };
9
+ //#endregion
10
+ //#region ../../core/graph/dag/dist/layers.js
11
+ /**
12
+ * Layers the graph by the longest `needs` chain below each node, so everything in one layer can run once the earlier layers are done.
13
+ *
14
+ * Defined on the acyclic part of the graph: a node on a cycle, or one that needs such a node directly or transitively, has no finite chain length and is reported in `unlayered` rather than being given a level. Every other node is layered exactly as in an acyclic graph. Unknown references are not edges and contribute nothing to a level. Iterative (Kahn's algorithm), so depth cannot overflow the call stack.
15
+ */
16
+ function topologicalLayers(dag) {
17
+ const depth = new Map(dag.nodes.map((id) => [id, 0]));
18
+ const waitingOn = new Map(dag.nodes.map((id) => [id, lookup$1(dag.needs, id).length]));
19
+ const ready = dag.nodes.filter((id) => lookup$1(waitingOn, id) === 0);
20
+ for (const current of ready) {
21
+ const above = lookup$1(depth, current) + 1;
22
+ for (const dependent of lookup$1(dag.dependents, current)) {
23
+ depth.set(dependent, Math.max(lookup$1(depth, dependent), above));
24
+ const remaining = lookup$1(waitingOn, dependent) - 1;
25
+ waitingOn.set(dependent, remaining);
26
+ if (remaining === 0) ready.push(dependent);
27
+ }
28
+ }
29
+ const levels = /* @__PURE__ */ new Map();
30
+ const layers = [];
31
+ const unlayered = [];
32
+ for (const id of dag.nodes) {
33
+ if (lookup$1(waitingOn, id) !== 0) {
34
+ unlayered.push(id);
35
+ continue;
36
+ }
37
+ const level = lookup$1(depth, id);
38
+ levels.set(id, level);
39
+ (layers[level] ??= []).push(id);
40
+ }
41
+ return {
42
+ levels,
43
+ layers,
44
+ unlayered
45
+ };
46
+ }
47
+ //#endregion
48
+ //#region ../../core/graph/dag/dist/dominators.js
49
+ /**
50
+ * The immediate dominator of every node reachable from `root` along `needs` edges. A node `d` dominates `n` when every path from `root` to `n` passes through `d`; the immediate dominator is the dominator closest to `n` other than `n` itself. Read with `needs` edges pointing from a step to the steps before it and `root` a virtual end every last step needs, this gives post-dominators: where every way forward from a step meets again.
51
+ *
52
+ * Found by the Lengauer-Tarjan algorithm with path compression, so the work is the number of reachable nodes and edges times a slowly growing factor, and every walk uses an explicit stack, so depth is bounded by memory, not the call stack. Cycles are allowed.
53
+ * @param dag - The graph to read.
54
+ * @param root - Where every path starts.
55
+ * @returns Each node reachable from `root` other than `root`, mapped to its immediate dominator, in the order a depth-first walk from `root` first reaches the nodes. A node `root` does not reach has no entry.
56
+ * @throws UnknownNodeError when `root` is not a node of `dag`.
57
+ */
58
+ function immediateDominators(dag, root) {
59
+ lookup$1(dag.needs, root);
60
+ const number = /* @__PURE__ */ new Map();
61
+ const order = [];
62
+ const parent = [];
63
+ const frames = [];
64
+ const enter = (node, from) => {
65
+ number.set(node, order.length);
66
+ order.push(node);
67
+ parent.push(from);
68
+ frames.push({
69
+ node,
70
+ next: 0
71
+ });
72
+ };
73
+ enter(root, -1);
74
+ for (let frame = frames.at(-1); frame !== void 0; frame = frames.at(-1)) {
75
+ const target = lookup$1(dag.needs, frame.node)[frame.next];
76
+ if (target === void 0) {
77
+ frames.pop();
78
+ continue;
79
+ }
80
+ frame.next += 1;
81
+ if (!number.has(target)) enter(target, lookup$1(number, frame.node));
82
+ }
83
+ const predecessors = order.map(() => []);
84
+ for (const [index, node] of order.entries()) for (const target of lookup$1(dag.needs, node)) predecessors[lookup$1(number, target)]?.push(index);
85
+ const semi = order.map((_, index) => index);
86
+ const idom = order.map(() => 0);
87
+ const ancestor = order.map(() => -1);
88
+ const label = order.map((_, index) => index);
89
+ const bucket = order.map(() => []);
90
+ /** Path compression up the forest built by `link`, done with an explicit stack. */
91
+ const compress = (start) => {
92
+ const path = [];
93
+ for (let node = start; (ancestor[ancestor[node] ?? -1] ?? -1) !== -1; node = ancestor[node] ?? -1) path.push(node);
94
+ for (const node of path.toReversed()) {
95
+ const up = ancestor[node] ?? -1;
96
+ const upLabel = label[up] ?? up;
97
+ if ((semi[upLabel] ?? 0) < (semi[label[node] ?? node] ?? 0)) label[node] = upLabel;
98
+ ancestor[node] = ancestor[up] ?? -1;
99
+ }
100
+ };
101
+ /** The node with the least semidominator on the forest path to `node`. */
102
+ const evaluate = (node) => {
103
+ if (ancestor[node] === -1) return node;
104
+ compress(node);
105
+ return label[node] ?? node;
106
+ };
107
+ for (let index = order.length - 1; index > 0; index -= 1) {
108
+ for (const from of predecessors[index] ?? []) {
109
+ const least = semi[evaluate(from)] ?? index;
110
+ if (least < (semi[index] ?? index)) semi[index] = least;
111
+ }
112
+ bucket[semi[index] ?? index]?.push(index);
113
+ const up = parent[index] ?? 0;
114
+ ancestor[index] = up;
115
+ for (const waiting of bucket[up] ?? []) {
116
+ const least = evaluate(waiting);
117
+ idom[waiting] = (semi[least] ?? 0) < (semi[waiting] ?? 0) ? least : up;
118
+ }
119
+ bucket[up] = [];
120
+ }
121
+ const dominators = /* @__PURE__ */ new Map();
122
+ for (let index = 1; index < order.length; index += 1) {
123
+ if (idom[index] !== semi[index]) idom[index] = idom[idom[index] ?? 0] ?? 0;
124
+ const node = order[index];
125
+ const dominator = order[idom[index] ?? 0];
126
+ if (node !== void 0 && dominator !== void 0) dominators.set(node, dominator);
127
+ }
128
+ return dominators;
129
+ }
130
+ //#endregion
131
+ //#region ../../core/graph/dag/dist/critical-path.js
132
+ /**
133
+ * The longest weighted chain along `needs`, where a chain's weight is the sum of its nodes' weights.
134
+ *
135
+ * `weight` is called exactly once per node, in node order, and must return a finite number that is not negative. The returned path always runs back to a node with no needs and ends at the node whose chain is heaviest.
136
+ *
137
+ * Ties are broken deterministically, and the rule is part of the contract. Where several needs of a node give an equally heavy chain, the one that comes first in node order is followed. Where several nodes end an equally heavy chain, the one that comes first in node order ends it. A zero-weight node therefore never shortens the path back to the start, and a zero-weight dependent never extends the path past an earlier node of equal total.
138
+ *
139
+ * Defined for acyclic graphs. An empty graph returns `{ path: [], weight: 0 }`. Unknown references are not edges.
140
+ * @throws CycleError when the graph contains a cycle: a chain through a cycle has no greatest weight.
141
+ * @throws RangeError when `weight` returns a negative or non-finite number.
142
+ */
143
+ function criticalPath$1(dag, weight) {
144
+ assertAcyclic(dag);
145
+ const weights = /* @__PURE__ */ new Map();
146
+ for (const id of dag.nodes) {
147
+ const value = weight(id);
148
+ if (!Number.isFinite(value) || value < 0) throw new RangeError(`The weight of "${String(id)}" must be a finite, non-negative number, got ${String(value)}`);
149
+ weights.set(id, value);
150
+ }
151
+ const position = new Map(dag.nodes.map((id, order) => [id, order]));
152
+ const total = /* @__PURE__ */ new Map();
153
+ const previous = /* @__PURE__ */ new Map();
154
+ for (const layer of topologicalLayers(dag).layers) for (const id of layer) {
155
+ let best;
156
+ let bestTotal = 0;
157
+ for (const need of lookup$1(dag.needs, id)) {
158
+ const candidate = lookup$1(total, need);
159
+ if (best === void 0 || candidate > bestTotal || candidate === bestTotal && lookup$1(position, need) < lookup$1(position, best)) {
160
+ best = need;
161
+ bestTotal = candidate;
162
+ }
163
+ }
164
+ total.set(id, lookup$1(weights, id) + bestTotal);
165
+ if (best !== void 0) previous.set(id, best);
166
+ }
167
+ let end;
168
+ for (const id of dag.nodes) if (end === void 0 || lookup$1(total, id) > lookup$1(total, end)) end = id;
169
+ if (end === void 0) return {
170
+ path: [],
171
+ weight: 0
172
+ };
173
+ const path = [];
174
+ for (let node = end; node !== void 0; node = previous.get(node)) path.push(node);
175
+ return {
176
+ path: path.reverse(),
177
+ weight: lookup$1(total, end)
178
+ };
179
+ }
180
+ //#endregion
181
+ //#region ../../core/graph/projection/dist/chains.js
182
+ /** The transitions leaving each element, in model order. */
183
+ const outgoingMap = (model) => {
184
+ const outgoing = /* @__PURE__ */ new Map();
185
+ for (const transition of model.transitions) {
186
+ const list = outgoing.get(transition.source);
187
+ if (list === void 0) outgoing.set(transition.source, [transition]);
188
+ else list.push(transition);
189
+ }
190
+ return outgoing;
191
+ };
192
+ /** Appends `value` to the list `map` holds under `key`. */
193
+ const append$1 = (map, key, value) => {
194
+ const list = map.get(key);
195
+ if (list === void 0) map.set(key, [value]);
196
+ else list.push(value);
197
+ };
198
+ /** A computation run once, on first call, and remembered. */
199
+ const once = (compute) => {
200
+ let memo;
201
+ return () => {
202
+ memo ??= { value: compute() };
203
+ return memo.value;
204
+ };
205
+ };
206
+ /** More than this many distinct entrances or targets is counted as "many": the folding rule only needs to tell one, two and more apart. */
207
+ const enough = 3;
208
+ /** Adds `values` to a capped set: once it would hold `enough`, it stands for "many" and keeps no more. */
209
+ const addCapped = (set, values) => {
210
+ for (const value of values) {
211
+ if (set.size >= enough) return;
212
+ set.add(value);
213
+ }
214
+ };
215
+ /**
216
+ * The elements a notation would fold that it must not, because folding them would multiply edges.
217
+ *
218
+ * Folding an element replaces the routes through it with one chain per pair of a way in and a drawn element it leads to. Through a folded region, an element is reached by some set of entering transitions (transitions from an element that is not folded) and leads to some set of accepted targets; folding it can draw up to entering times targets chains where the model had entering plus targets transitions. So an element is folded only when that product is no more than that sum: when one side is a single item, or both are two. Counting k sources into one message that leads to k ends, or into a run of messages that fans out to k ends further on, both fail, so neither draws k times k edges. The counts are the distinct entering transitions reaching each element and the distinct targets it reaches, both through folded elements, each held as a set capped at `enough` and carried over the condensed folded graph once in each direction, so deciding every element costs linear work. The counts are taken before any element is unfolded, so an element downstream of an unfolded one may be unfolded too; that errs towards drawing less, never towards multiplying.
219
+ */
220
+ const multiplying = (model, outgoing, foldable, accepted) => {
221
+ const components = stronglyConnectedComponents(buildDag([...foldable], (id) => (outgoing.get(id) ?? []).map((transition) => transition.target).filter((target) => foldable.has(target))));
222
+ const componentOf = /* @__PURE__ */ new Map();
223
+ for (const [index, members] of components.entries()) for (const member of members) componentOf.set(member, index);
224
+ const entering = components.map(() => /* @__PURE__ */ new Set());
225
+ const reaching = components.map(() => /* @__PURE__ */ new Set());
226
+ const before = components.map(() => []);
227
+ const after = components.map(() => []);
228
+ for (const transition of model.transitions) {
229
+ const from = componentOf.get(transition.source);
230
+ const to = componentOf.get(transition.target);
231
+ if (to !== void 0 && from === void 0) addCapped(entering[to] ?? /* @__PURE__ */ new Set(), [transition.id]);
232
+ if (from !== void 0 && to === void 0 && accepted(transition.target)) addCapped(reaching[from] ?? /* @__PURE__ */ new Set(), [transition.target]);
233
+ if (from !== void 0 && to !== void 0 && from !== to) {
234
+ before[to]?.push(from);
235
+ after[from]?.push(to);
236
+ }
237
+ }
238
+ for (const [index] of components.entries()) for (const successor of after[index] ?? []) addCapped(reaching[index] ?? /* @__PURE__ */ new Set(), reaching[successor] ?? []);
239
+ for (let index = components.length - 1; index >= 0; index -= 1) for (const predecessor of before[index] ?? []) addCapped(entering[index] ?? /* @__PURE__ */ new Set(), entering[predecessor] ?? []);
240
+ const unfolded = /* @__PURE__ */ new Set();
241
+ for (const [index, members] of components.entries()) {
242
+ const ways = entering[index]?.size ?? 0;
243
+ const ends = reaching[index]?.size ?? 0;
244
+ if (ways * ends > ways + ends) for (const member of members) unfolded.add(member);
245
+ }
246
+ return unfolded;
247
+ };
248
+ /**
249
+ * Indexes a model's folded elements so chains can be read off for any first transition.
250
+ *
251
+ * An element the notation would fold is left unfolded when folding it would multiply edges (see `multiplying`), and is then drawn no more than any element the notation has no shape for; `unfolded` lists them so the projection can report them.
252
+ *
253
+ * The folded elements that lead to some accepted element are found first, by one walk back from the accepted elements, and no walk enters any other, so a run that leads nowhere costs nothing. The folded elements are condensed into strongly connected components in one pass, and the condensed graph is read in reverse topological order. A component gets a flat array of its accepted targets only when something reads it on its own: it is entered from an element that is not folded, or from two or more components. Every other component has at most one component before it and is read as part of that one, so it is visited once in all. Arrays are built on demand and remembered, so a region no start reaches costs nothing; a generation stamp per target removes duplicates in constant time, a component with nothing of its own to add shares the one array it reads, and the only builder of an array nothing else reads extends it in place instead of copying it. The total work is linear in the elements and transitions plus the sizes of the arrays that must be copied, which is where two or more starts, or two or more components, read the same targets. Folded elements entered from exactly one folded element, outside any cycle, form a forest of routes; each records how deep it is and the last trigger, effect and guard on the way down to it, so a single-route chain's labels are found from its ends in constant time.
254
+ *
255
+ * Merged chains' lists, and every chain's lists, are built only when read.
256
+ */
257
+ const chainIndex = (model, folding) => {
258
+ const outgoing = outgoingMap(model);
259
+ const foldable = /* @__PURE__ */ new Set();
260
+ for (const element of model.elements) if (folding.folded(element.id)) foldable.add(element.id);
261
+ const unfolded = multiplying(model, outgoing, foldable, folding.accepted);
262
+ const isFolded = new Set([...foldable].filter((id) => !unfolded.has(id)));
263
+ const events = /* @__PURE__ */ new Map();
264
+ for (const id of isFolded) {
265
+ const event = folding.eventOf?.(id);
266
+ if (event !== void 0) events.set(id, event);
267
+ }
268
+ const foldedIn = /* @__PURE__ */ new Map();
269
+ const arrivingIn = /* @__PURE__ */ new Map();
270
+ for (const transition of model.transitions) {
271
+ if (!isFolded.has(transition.source)) continue;
272
+ append$1(isFolded.has(transition.target) ? foldedIn : arrivingIn, transition.target, transition);
273
+ }
274
+ const live = /* @__PURE__ */ new Set();
275
+ const towards = [];
276
+ for (const [target, into] of arrivingIn) {
277
+ if (!folding.accepted(target)) continue;
278
+ for (const { source } of into) if (!live.has(source)) {
279
+ live.add(source);
280
+ towards.push(source);
281
+ }
282
+ }
283
+ for (let at = towards.pop(); at !== void 0; at = towards.pop()) for (const { source } of foldedIn.get(at) ?? []) if (!live.has(source)) {
284
+ live.add(source);
285
+ towards.push(source);
286
+ }
287
+ /** Whether a walk follows a transition: into a folded element that leads somewhere, or into an accepted element. */
288
+ const followed = (target) => isFolded.has(target) ? live.has(target) : folding.accepted(target);
289
+ const foldedIds = [...isFolded];
290
+ const components = stronglyConnectedComponents(buildDag(foldedIds, (id) => (outgoing.get(id) ?? []).map((transition) => transition.target).filter((target) => isFolded.has(target))));
291
+ const componentOf = /* @__PURE__ */ new Map();
292
+ for (const [index, members] of components.entries()) for (const member of members) componentOf.set(member, index);
293
+ const cyclic = /* @__PURE__ */ new Set();
294
+ for (const members of components) {
295
+ const [only] = members;
296
+ const selfLoop = only !== void 0 && (outgoing.get(only) ?? []).some((transition) => transition.target === only);
297
+ if (members.length > 1 || selfLoop) for (const member of members) cyclic.add(member);
298
+ }
299
+ const observe = folding.observe;
300
+ const successorsOf = components.map(() => []);
301
+ const predecessors = components.map(() => 0);
302
+ for (const [index, members] of components.entries()) {
303
+ const seen = /* @__PURE__ */ new Set();
304
+ for (const member of members) for (const { target } of outgoing.get(member) ?? []) {
305
+ const successor = componentOf.get(target);
306
+ if (successor !== void 0 && successor !== index && !seen.has(successor)) {
307
+ seen.add(successor);
308
+ successorsOf[index]?.push(successor);
309
+ predecessors[successor] = (predecessors[successor] ?? 0) + 1;
310
+ }
311
+ }
312
+ }
313
+ const enteredFromOutside = /* @__PURE__ */ new Set();
314
+ for (const transition of model.transitions) {
315
+ const component = componentOf.get(transition.target);
316
+ if (component !== void 0 && !isFolded.has(transition.source)) enteredFromOutside.add(component);
317
+ }
318
+ const standalone = (component) => enteredFromOutside.has(component) || (predecessors[component] ?? 0) > 1;
319
+ const ownOf = (component) => {
320
+ const own = [];
321
+ for (const member of components[component] ?? []) for (const { target } of outgoing.get(member) ?? []) if (!isFolded.has(target) && folding.accepted(target)) own.push(target);
322
+ return own;
323
+ };
324
+ /** What a standalone component's targets are made of, in reading order: its own targets, then each way on's in order, reading through components that stand only on it and stopping at the next standalone ones. */
325
+ const piecesOf = (component) => {
326
+ const found = [];
327
+ const stack = [{
328
+ component,
329
+ visit: true
330
+ }];
331
+ for (let next = stack.pop(); next !== void 0; next = stack.pop()) {
332
+ if (!next.visit) {
333
+ observe?.(1);
334
+ found.push({ component: next.component });
335
+ continue;
336
+ }
337
+ const own = ownOf(next.component);
338
+ if (own.length > 0) {
339
+ observe?.(own.length);
340
+ found.push({ own });
341
+ }
342
+ for (const successor of (successorsOf[next.component] ?? []).toReversed()) stack.push({
343
+ component: successor,
344
+ visit: !standalone(successor)
345
+ });
346
+ }
347
+ return found;
348
+ };
349
+ const piecesFor = /* @__PURE__ */ new Map();
350
+ const pieces = (component) => {
351
+ const known = piecesFor.get(component);
352
+ if (known !== void 0) return known;
353
+ const found = piecesOf(component);
354
+ piecesFor.set(component, found);
355
+ return found;
356
+ };
357
+ const builders = /* @__PURE__ */ new Map();
358
+ for (const [index] of components.entries()) {
359
+ if (!standalone(index)) continue;
360
+ const readFrom = new Set(pieces(index).flatMap((piece) => piece.component === void 0 ? [] : [piece.component]));
361
+ for (const read of readFrom) builders.set(read, (builders.get(read) ?? 0) + 1);
362
+ }
363
+ const pinnedFor = (component) => enteredFromOutside.has(component) || (builders.get(component) ?? 0) > 1;
364
+ const arrays = /* @__PURE__ */ new Map();
365
+ const stamp = /* @__PURE__ */ new Map();
366
+ let generation = 0;
367
+ const build = (component) => {
368
+ const parts = pieces(component);
369
+ const only = parts.length === 1 ? parts[0] : void 0;
370
+ const onlyArray = only?.component === void 0 ? void 0 : arrays.get(only.component);
371
+ if (onlyArray !== void 0) {
372
+ onlyArray.pinned ||= pinnedFor(component);
373
+ return onlyArray;
374
+ }
375
+ const last = parts.at(-1);
376
+ const lastArray = last?.component === void 0 ? void 0 : arrays.get(last.component);
377
+ const takeOver = lastArray !== void 0 && !lastArray.pinned && lastArray.members !== void 0;
378
+ const target = takeOver ? lastArray : {
379
+ reversed: [],
380
+ members: void 0,
381
+ pinned: pinnedFor(component)
382
+ };
383
+ target.pinned = pinnedFor(component);
384
+ generation += 1;
385
+ const members = target.members;
386
+ const present = (value) => members === void 0 ? stamp.get(value) === generation : members.has(value);
387
+ const add = (value) => {
388
+ if (present(value)) return;
389
+ observe?.(1);
390
+ target.reversed.push(value);
391
+ if (members === void 0) stamp.set(value, generation);
392
+ else members.add(value);
393
+ };
394
+ for (let index = parts.length - (takeOver ? 2 : 1); index >= 0; index -= 1) {
395
+ const piece = parts[index];
396
+ if (piece === void 0) continue;
397
+ if (piece.own !== void 0) {
398
+ for (const value of piece.own.toReversed()) add(value);
399
+ continue;
400
+ }
401
+ for (const value of arrays.get(piece.component)?.reversed ?? []) add(value);
402
+ }
403
+ if (target.pinned) target.members = void 0;
404
+ else if (target.members === void 0) {
405
+ observe?.(target.reversed.length);
406
+ target.members = new Set(target.reversed);
407
+ }
408
+ return target;
409
+ };
410
+ const arrayOf = (component) => {
411
+ const frames = [{
412
+ component,
413
+ expanded: false
414
+ }];
415
+ for (let frame = frames.at(-1); frame !== void 0; frame = frames.at(-1)) {
416
+ if (arrays.has(frame.component)) {
417
+ frames.pop();
418
+ continue;
419
+ }
420
+ if (!frame.expanded) {
421
+ frame.expanded = true;
422
+ for (const piece of pieces(frame.component)) if (piece.component !== void 0 && !arrays.has(piece.component)) frames.push({
423
+ component: piece.component,
424
+ expanded: false
425
+ });
426
+ continue;
427
+ }
428
+ arrays.set(frame.component, build(frame.component));
429
+ frames.pop();
430
+ }
431
+ const found = arrays.get(component);
432
+ if (found === void 0) throw new Error("Invariant violated: a component's targets were not built");
433
+ return found;
434
+ };
435
+ const leads = [];
436
+ for (const [index] of components.entries()) leads[index] = ownOf(index).length > 0 || (successorsOf[index] ?? []).some((successor) => leads[successor] === true);
437
+ /** A start component's targets in reading order; only ever asked of a component entered from outside, which is standalone. */
438
+ const targetsOf = (component) => arrayOf(component).reversed.toReversed();
439
+ const parentLink = /* @__PURE__ */ new Map();
440
+ const children = /* @__PURE__ */ new Map();
441
+ for (const id of foldedIds) {
442
+ const into = foldedIn.get(id);
443
+ const link = into?.length === 1 ? into[0] : void 0;
444
+ if (link !== void 0 && !cyclic.has(id) && !cyclic.has(link.source)) {
445
+ parentLink.set(id, link);
446
+ append$1(children, link.source, id);
447
+ }
448
+ }
449
+ const depth = /* @__PURE__ */ new Map();
450
+ const enter = /* @__PURE__ */ new Map();
451
+ const leave = /* @__PURE__ */ new Map();
452
+ const lastTrigger = /* @__PURE__ */ new Map();
453
+ const lastEffect = /* @__PURE__ */ new Map();
454
+ const guardsTo = /* @__PURE__ */ new Map();
455
+ let clock = 0;
456
+ for (const root of foldedIds) {
457
+ if (parentLink.has(root)) continue;
458
+ const stack = [{
459
+ id: root,
460
+ next: 0
461
+ }];
462
+ const visit = (id, level) => {
463
+ depth.set(id, level);
464
+ enter.set(id, clock);
465
+ clock += 1;
466
+ const link = parentLink.get(id);
467
+ const parent = link?.source;
468
+ const event = events.get(id);
469
+ const trigger = event !== void 0 ? {
470
+ value: event,
471
+ depth: level,
472
+ atElement: true
473
+ } : link?.trigger !== void 0 ? {
474
+ value: link.trigger,
475
+ depth: level,
476
+ atElement: false
477
+ } : parent === void 0 ? void 0 : lastTrigger.get(parent);
478
+ if (trigger !== void 0) lastTrigger.set(id, trigger);
479
+ const effect = link?.effect !== void 0 ? {
480
+ value: link.effect,
481
+ depth: level,
482
+ atElement: false
483
+ } : parent === void 0 ? void 0 : lastEffect.get(parent);
484
+ if (effect !== void 0) lastEffect.set(id, effect);
485
+ const above = parent === void 0 ? void 0 : guardsTo.get(parent);
486
+ const guards = link?.guard !== void 0 ? {
487
+ guard: link.guard,
488
+ depth: level,
489
+ previous: above
490
+ } : above;
491
+ if (guards !== void 0) guardsTo.set(id, guards);
492
+ };
493
+ visit(root, 0);
494
+ for (let top = stack.at(-1); top !== void 0; top = stack.at(-1)) {
495
+ const child = (children.get(top.id) ?? [])[top.next];
496
+ if (child === void 0) {
497
+ leave.set(top.id, clock);
498
+ stack.pop();
499
+ continue;
500
+ }
501
+ top.next += 1;
502
+ visit(child, (depth.get(top.id) ?? 0) + 1);
503
+ stack.push({
504
+ id: child,
505
+ next: 0
506
+ });
507
+ }
508
+ }
509
+ /** Whether `ancestor` is `node` or above it in the route forest. */
510
+ const above = (ancestor, node) => {
511
+ const start = enter.get(ancestor);
512
+ const stop = leave.get(ancestor);
513
+ const at = enter.get(node);
514
+ return start !== void 0 && stop !== void 0 && at !== void 0 && start <= at && at < stop;
515
+ };
516
+ const position = new Map(foldedIds.map((id, index) => [id, index]));
517
+ const rootOf = (component) => {
518
+ let root;
519
+ for (const member of components[component] ?? []) if (root === void 0 || (position.get(member) ?? 0) < (position.get(root) ?? 0)) root = member;
520
+ return root;
521
+ };
522
+ const walks = /* @__PURE__ */ new Map();
523
+ const walkFrom = (element) => {
524
+ const component = componentOf.get(element);
525
+ const known = component === void 0 ? void 0 : walks.get(component);
526
+ if (known !== void 0) return known;
527
+ const start = (component === void 0 ? void 0 : rootOf(component)) ?? element;
528
+ const order = /* @__PURE__ */ new Map();
529
+ const entered = /* @__PURE__ */ new Map([[start, 0]]);
530
+ const into = /* @__PURE__ */ new Map();
531
+ const stack = [{
532
+ id: start,
533
+ next: 0
534
+ }];
535
+ for (let top = stack.at(-1); top !== void 0; top = stack.at(-1)) {
536
+ const transition = (outgoing.get(top.id) ?? [])[top.next];
537
+ if (transition === void 0) {
538
+ stack.pop();
539
+ continue;
540
+ }
541
+ top.next += 1;
542
+ if (!followed(transition.target)) continue;
543
+ order.set(transition, order.size);
544
+ append$1(into, transition.target, transition);
545
+ if (isFolded.has(transition.target) && !entered.has(transition.target)) {
546
+ entered.set(transition.target, entered.size);
547
+ stack.push({
548
+ id: transition.target,
549
+ next: 0
550
+ });
551
+ }
552
+ }
553
+ const walk = {
554
+ order,
555
+ entered,
556
+ into
557
+ };
558
+ if (component !== void 0) walks.set(component, walk);
559
+ return walk;
560
+ };
561
+ /** The union of every route from `first` to `target`: walking back from `target` over the shared walk's index of what arrives where, so the work is the size of this union, then put in the order the walk met each transition and element. */
562
+ const union = (first, target) => {
563
+ const walk = walkFrom(first.target);
564
+ const leading = /* @__PURE__ */ new Set([target]);
565
+ const back = [target];
566
+ const transitions = [];
567
+ for (let at = back.pop(); at !== void 0; at = back.pop()) for (const transition of walk.into.get(at) ?? []) {
568
+ transitions.push(transition);
569
+ if (!leading.has(transition.source)) {
570
+ leading.add(transition.source);
571
+ back.push(transition.source);
572
+ }
573
+ }
574
+ const metAt = (transition) => walk.order.get(transition) ?? 0;
575
+ const enteredAt = (element) => walk.entered.get(element) ?? 0;
576
+ return {
577
+ transitions: [first, ...transitions.sort((a, b) => metAt(a) - metAt(b))],
578
+ through: [...leading].filter((element) => walk.entered.has(element)).sort((a, b) => enteredAt(a) - enteredAt(b))
579
+ };
580
+ };
581
+ const from = (first) => {
582
+ const start = first.target;
583
+ if (!isFolded.has(start)) return folding.accepted(start) ? [{
584
+ first,
585
+ target: start,
586
+ merged: false,
587
+ transitions: () => [first],
588
+ through: () => [],
589
+ guards: () => first.guard === void 0 ? [] : [first.guard],
590
+ guarded: first.guard !== void 0,
591
+ trigger: first.trigger,
592
+ effect: first.effect
593
+ }] : [];
594
+ const component = componentOf.get(start);
595
+ const reached = component === void 0 ? [] : targetsOf(component);
596
+ const level = depth.get(start);
597
+ return reached.map((target) => {
598
+ const into = arrivingIn.get(target);
599
+ const last = into?.length === 1 ? into[0] : void 0;
600
+ const source = last?.source;
601
+ const single = last !== void 0 && source !== void 0 && level !== void 0 && above(start, source);
602
+ const lists = once(() => union(first, target));
603
+ if (!single) return {
604
+ first,
605
+ target,
606
+ merged: true,
607
+ transitions: () => lists().transitions,
608
+ through: () => lists().through,
609
+ guards: () => [],
610
+ guarded: false,
611
+ trigger: void 0,
612
+ effect: void 0
613
+ };
614
+ const onRoute = (found) => found !== void 0 && (found.depth > level || found.depth === level && found.atElement);
615
+ const triggerFound = lastTrigger.get(source);
616
+ const effectFound = lastEffect.get(source);
617
+ const guardsFound = guardsTo.get(source);
618
+ const routeGuards = once(() => {
619
+ const middle = [];
620
+ for (let link = guardsFound; link !== void 0 && link.depth > level; link = link.previous) middle.push(link.guard);
621
+ return [
622
+ ...first.guard === void 0 ? [] : [first.guard],
623
+ ...middle.toReversed(),
624
+ ...last.guard === void 0 ? [] : [last.guard]
625
+ ];
626
+ });
627
+ const route = once(() => {
628
+ const nodes = [];
629
+ const links = [];
630
+ for (let at = source; at !== void 0;) {
631
+ nodes.push(at);
632
+ if (at === start) break;
633
+ const link = parentLink.get(at);
634
+ if (link !== void 0) links.push(link);
635
+ at = link?.source;
636
+ }
637
+ return {
638
+ through: nodes.toReversed(),
639
+ transitions: [
640
+ first,
641
+ ...links.toReversed(),
642
+ last
643
+ ]
644
+ };
645
+ });
646
+ return {
647
+ first,
648
+ target,
649
+ merged: false,
650
+ transitions: () => route().transitions,
651
+ through: () => route().through,
652
+ guards: routeGuards,
653
+ guarded: first.guard !== void 0 || last.guard !== void 0 || guardsFound !== void 0 && guardsFound.depth > level,
654
+ trigger: last.trigger ?? (onRoute(triggerFound) ? triggerFound?.value : void 0) ?? first.trigger,
655
+ effect: last.effect ?? (effectFound !== void 0 && effectFound.depth > level ? effectFound.value : void 0) ?? first.effect
656
+ };
657
+ });
658
+ };
659
+ const carried = (firsts) => {
660
+ const reached = /* @__PURE__ */ new Set();
661
+ const stack = [];
662
+ for (const first of firsts) if (live.has(first.target) && !reached.has(first.target)) {
663
+ reached.add(first.target);
664
+ stack.push(first.target);
665
+ }
666
+ for (let at = stack.pop(); at !== void 0; at = stack.pop()) for (const transition of outgoing.get(at) ?? []) if (live.has(transition.target) && !reached.has(transition.target)) {
667
+ reached.add(transition.target);
668
+ stack.push(transition.target);
669
+ }
670
+ return reached;
671
+ };
672
+ return {
673
+ from,
674
+ arriving: (element) => arrivingIn.get(element) ?? [],
675
+ carried,
676
+ unfolded
677
+ };
678
+ };
679
+ //#endregion
680
+ //#region ../../core/graph/projection/dist/handoffs.js
681
+ /**
682
+ * Swimlane view: a transition between two elements with different actors is a hand-off. A transition into a `message` element continues through it to the element after it, so a message between two steps is part of the hand-off it carries, not an end of it. Elements without an actor never produce one.
683
+ * @param model - The model to read.
684
+ * @returns The hand-offs, in the order of the transitions they start with.
685
+ */
686
+ const handoffs = (model) => {
687
+ const actorOf = actorMap(model);
688
+ const messages = new Set(model.elements.flatMap((element) => element.kind === "message" ? [element.id] : []));
689
+ const index = chainIndex(model, {
690
+ folded: (id) => messages.has(id),
691
+ accepted: (id) => actorOf.has(id)
692
+ });
693
+ const found = [];
694
+ for (const transition of model.transitions) {
695
+ const from = actorOf.get(transition.source);
696
+ if (from === void 0) continue;
697
+ for (const chain of index.from(transition)) {
698
+ const to = actorOf.get(chain.target);
699
+ if (to === void 0 || from === to) continue;
700
+ found.push(transition.target === chain.target ? {
701
+ transition: transition.id,
702
+ from,
703
+ to
704
+ } : {
705
+ transition: transition.id,
706
+ from,
707
+ to,
708
+ get through() {
709
+ return chain.through();
710
+ }
711
+ });
712
+ }
713
+ }
714
+ return found;
715
+ };
716
+ //#endregion
717
+ //#region ../../core/graph/projection/dist/loss.js
718
+ /**
719
+ * The elements the notation cannot draw: every element that is neither in `accounted` (drawn, or folded away by design, as a decision is in a state machine) nor a `message`, which `commonLoss` reports as `message-elements` when it is not shown.
720
+ * @param model - The model being projected.
721
+ * @param notation - The notation that cannot draw them.
722
+ * @param accounted - Elements the projection draws or folds away by design.
723
+ * @returns A single `unrepresented-elements` loss, or none when every element is accounted for.
724
+ */
725
+ const unrepresentedLoss = (model, notation, accounted, unfolded) => {
726
+ const elements = [];
727
+ for (const element of model.elements) {
728
+ if (element.kind === "message" && !unfolded.has(element.id) || accounted.has(element.id)) continue;
729
+ elements.push({
730
+ element: element.id,
731
+ kind: element.kind === "pseudo" ? element.role : element.kind
732
+ });
733
+ }
734
+ if (elements.length === 0) return [];
735
+ const lost = new Set(elements.map((entry) => entry.element));
736
+ return [{
737
+ kind: "unrepresented-elements",
738
+ notation,
739
+ elements,
740
+ transitions: model.transitions.filter((transition) => lost.has(transition.source) || lost.has(transition.target)).map((transition) => transition.id)
741
+ }];
742
+ };
743
+ /**
744
+ * The losses every projection can have, whatever its notation: dropped layout, notation-only extensions, message elements and authored fragments.
745
+ * @param model - The model projected.
746
+ * @param notation - The notation whose recorded positions are dropped.
747
+ * @param shown - The message elements and fragments the projection did draw, which are therefore not reported.
748
+ */
749
+ const commonLoss = (model, notation, shown) => {
750
+ const positions = model.views?.[notation];
751
+ const positioned = model.elements.filter((element) => positions?.[element.id] !== void 0);
752
+ const withExtensions = model.elements.filter((element) => element.extensions !== void 0 && Object.keys(element.extensions).length > 0);
753
+ const messages = model.elements.filter((element) => element.kind === "message" && !shown.messages.has(element.id));
754
+ const hidden = model.fragments.filter((fragment) => !shown.fragments.has(fragment.id));
755
+ const losses = [];
756
+ if (positioned.length > 0) losses.push({
757
+ kind: "layout",
758
+ elements: positioned.map((element) => element.id)
759
+ });
760
+ if (withExtensions.length > 0) losses.push({
761
+ kind: "extensions",
762
+ elements: withExtensions.map((element) => element.id)
763
+ });
764
+ if (messages.length > 0) losses.push({
765
+ kind: "message-elements",
766
+ elements: messages.map((element) => element.id)
767
+ });
768
+ if (hidden.length > 0) losses.push({
769
+ kind: "fragments",
770
+ fragments: hidden.map((fragment) => fragment.id)
771
+ });
772
+ return losses;
773
+ };
774
+ //#endregion
775
+ //#region ../../core/graph/projection/dist/flowchart.js
776
+ const flowNode = (element) => {
777
+ switch (element.kind) {
778
+ case "activity": return {
779
+ id: element.id,
780
+ label: element.label,
781
+ shape: "process"
782
+ };
783
+ case "decision": return {
784
+ id: element.id,
785
+ label: element.label,
786
+ shape: "decision"
787
+ };
788
+ case "pseudo": switch (element.role) {
789
+ case "initial": return {
790
+ id: element.id,
791
+ label: "Start",
792
+ shape: "terminator"
793
+ };
794
+ case "final": return {
795
+ id: element.id,
796
+ label: "End",
797
+ shape: "terminator"
798
+ };
799
+ case "fork": return {
800
+ id: element.id,
801
+ label: "Fork",
802
+ shape: "bar"
803
+ };
804
+ case "join": return {
805
+ id: element.id,
806
+ label: "Join",
807
+ shape: "bar"
808
+ };
809
+ }
810
+ }
811
+ };
812
+ /**
813
+ * What a flowchart-shaped projection drops: the common losses, then the elements the flowchart has no node for (`state` elements and `history` pseudo-states) and the transitions that touch them.
814
+ * @param model - The model projected.
815
+ * @param notation - The notation the result is for, `flowchart` or `swimlane`.
816
+ * @param drawn - What the projection drew.
817
+ */
818
+ const flowchartLoss = (model, notation, drawn) => [...commonLoss(model, notation, {
819
+ fragments: /* @__PURE__ */ new Set(),
820
+ messages: /* @__PURE__ */ new Set([...drawn.carried, ...drawn.unfolded])
821
+ }), ...unrepresentedLoss(model, notation, new Set(drawn.nodes.map((node) => node.id)), drawn.unfolded)];
822
+ /**
823
+ * The edge a chain draws. On a single route its label is the route's guards joined with "and", or, when none is guarded, the labels of the messages on it; where several routes are merged the guards belong to different routes and cannot be joined, so the label is the carried messages' labels. An edge through messages builds its lists and label only when they are read, so edges sharing a long run of messages do not each copy it.
824
+ */
825
+ const edgeOf = (chain, messageLabels) => {
826
+ const from = chain.first.source;
827
+ if (chain.first.target === chain.target) {
828
+ const { guard } = chain.first;
829
+ return {
830
+ from,
831
+ to: chain.target,
832
+ ...guard === void 0 ? {} : { label: guard },
833
+ transitions: [chain.first.id]
834
+ };
835
+ }
836
+ const ids = once(() => chain.transitions().map((transition) => transition.id));
837
+ const label = once(() => {
838
+ if (!chain.merged && chain.guarded) return chain.guards().join(" and ");
839
+ return chain.through().flatMap((id) => {
840
+ const message = messageLabels.get(id);
841
+ return message === void 0 ? [] : [message];
842
+ }).join(", ");
843
+ });
844
+ return {
845
+ from,
846
+ to: chain.target,
847
+ get label() {
848
+ return label();
849
+ },
850
+ get transitions() {
851
+ return ids();
852
+ },
853
+ get through() {
854
+ return chain.through();
855
+ }
856
+ };
857
+ };
858
+ /**
859
+ * The flowchart and the parts its inverse needs.
860
+ * @param model - The model to project.
861
+ */
862
+ const flowchartParts = (model) => {
863
+ const nodes = [];
864
+ const messageLabels = /* @__PURE__ */ new Map();
865
+ for (const element of model.elements) {
866
+ if (element.kind === "message") messageLabels.set(element.id, element.label);
867
+ const node = flowNode(element);
868
+ if (node !== void 0) nodes.push(node);
869
+ }
870
+ const included = new Set(nodes.map((node) => node.id));
871
+ const index = chainIndex(model, {
872
+ folded: (id) => messageLabels.has(id),
873
+ accepted: (id) => included.has(id)
874
+ });
875
+ const firsts = model.transitions.filter((transition) => included.has(transition.source));
876
+ const edges = [];
877
+ const origins = [];
878
+ for (const first of firsts) for (const chain of index.from(first)) {
879
+ edges.push(edgeOf(chain, messageLabels));
880
+ origins.push({
881
+ first,
882
+ target: chain.target
883
+ });
884
+ }
885
+ const carried = index.carried(firsts);
886
+ return {
887
+ flowchart: {
888
+ nodes,
889
+ edges,
890
+ loss: flowchartLoss(model, "flowchart", {
891
+ nodes,
892
+ carried,
893
+ unfolded: index.unfolded
894
+ })
895
+ },
896
+ origins,
897
+ index,
898
+ carried
899
+ };
900
+ };
901
+ /**
902
+ * Activities, decisions and terminators, joined by the transitions between them. A `message` element is not a node: a transition into it continues through it, so the edge runs from the step before the message to the step after it and carries the message (`through`). There is one edge per transition leaving a node and node it leads to, however many routes through message elements connect them; such an edge's `transitions`, `through` and `label` are built when first read. A message element no edge carries is reported as a `message-elements` loss. `state` elements and `history` pseudo-states have no flowchart shape and are reported as unrepresented, with the transitions that touch them.
903
+ * @param model - The model to project.
904
+ * @returns The nodes in model order, the edges in the order of the transitions they start with, and what was dropped.
905
+ */
906
+ const toFlowchart = (model) => flowchartParts(model).flowchart;
907
+ //#endregion
908
+ //#region ../../core/graph/projection/dist/swimlane.js
909
+ /**
910
+ * A flowchart plus partitions: a lane for every declared role or system, in declaration order and empty when nothing is assigned to it, then a lane for each actor that was named but never declared. Hand-offs are the edges that change lane.
911
+ */
912
+ const toSwimlane = (model) => {
913
+ const parts = flowchartParts(model);
914
+ const flow = parts.flowchart;
915
+ const actors = actorMap(model);
916
+ const members = /* @__PURE__ */ new Map();
917
+ const unassigned = [];
918
+ for (const node of flow.nodes) {
919
+ const actor = actors.get(node.id);
920
+ if (actor === void 0) {
921
+ unassigned.push(node.id);
922
+ continue;
923
+ }
924
+ const lane = members.get(actor);
925
+ if (lane === void 0) members.set(actor, [node.id]);
926
+ else lane.push(node.id);
927
+ }
928
+ const lanes = [];
929
+ const declared = /* @__PURE__ */ new Set();
930
+ for (const participant of model.participants) {
931
+ if (participant.kind === "entity") continue;
932
+ declared.add(participant.id);
933
+ lanes.push({
934
+ participant: participant.id,
935
+ label: participant.label,
936
+ nodes: members.get(participant.id) ?? []
937
+ });
938
+ }
939
+ for (const [actor, nodes] of members) if (!declared.has(actor)) lanes.push({
940
+ participant: actor,
941
+ label: actor,
942
+ nodes
943
+ });
944
+ return {
945
+ ...flow,
946
+ lanes,
947
+ unassigned,
948
+ handoffs: handoffs(model),
949
+ loss: flowchartLoss(model, "swimlane", {
950
+ nodes: flow.nodes,
951
+ carried: parts.carried,
952
+ unfolded: parts.index.unfolded
953
+ })
954
+ };
955
+ };
956
+ //#endregion
957
+ //#region ../../core/graph/projection/dist/state-machine.js
958
+ const stateOf = (element) => {
959
+ switch (element.kind) {
960
+ case "activity":
961
+ case "state": return {
962
+ id: element.id,
963
+ label: element.label,
964
+ role: "state"
965
+ };
966
+ case "pseudo":
967
+ if (element.role === "initial") return {
968
+ id: element.id,
969
+ label: "Start",
970
+ role: "initial"
971
+ };
972
+ if (element.role === "final") return {
973
+ id: element.id,
974
+ label: "End",
975
+ role: "final"
976
+ };
977
+ }
978
+ };
979
+ /**
980
+ * The state machine and the parts its inverse needs; see `toStateMachine`.
981
+ * @param model - The model to project.
982
+ * @param subject - The entity whose lifecycle the machine shows.
983
+ */
984
+ const stateMachineParts = (model, subject) => {
985
+ if (model.participants.find((participant) => participant.id === subject)?.kind !== "entity") throw new Error(`State machine subject "${subject}" must be a declared entity participant`);
986
+ const elements = new Map(model.elements.map((element) => [element.id, element]));
987
+ const outgoing = outgoingMap(model);
988
+ const scoped = model.elements.some((element) => element.kind === "activity" && element.affects !== void 0);
989
+ /** Whether an element is folded through rather than shown as a state: a decision, a `message` element, or an activity that does not affect the subject in a model that declares what activities affect. */
990
+ const isTransparent = (element) => element.kind === "decision" || element.kind === "message" || element.kind === "activity" && scoped && element.affects?.includes(subject) !== true;
991
+ /** The transition a chain draws. On a single route, the event is the last trigger along it, counting a folded message's own event right after the transition that arrives at it; guards are joined in order; the effect is the entry action of the target activity, or else the last effect along the route. Where several routes are merged their triggers, guards and effects belong to different routes, so only the target's entry action is kept. A transition through folded elements builds its lists and guard only when they are read. */
992
+ const transitionOf = (chain) => {
993
+ const target = elements.get(chain.target);
994
+ const event = chain.trigger;
995
+ const effect = (target?.kind === "activity" ? target.action : void 0) ?? chain.effect;
996
+ const base = {
997
+ source: chain.first.source,
998
+ target: chain.target,
999
+ ...event === void 0 ? {} : { event },
1000
+ ...effect === void 0 ? {} : { effect }
1001
+ };
1002
+ if (chain.first.target === chain.target) {
1003
+ const { guard } = chain.first;
1004
+ return {
1005
+ ...base,
1006
+ ...guard === void 0 ? {} : { guard },
1007
+ transitions: [chain.first.id]
1008
+ };
1009
+ }
1010
+ const ids = once(() => chain.transitions().map((transition) => transition.id));
1011
+ const guard = once(() => chain.guards().join(" and "));
1012
+ return chain.guarded ? {
1013
+ ...base,
1014
+ get guard() {
1015
+ return guard();
1016
+ },
1017
+ get transitions() {
1018
+ return ids();
1019
+ },
1020
+ get through() {
1021
+ return chain.through();
1022
+ }
1023
+ } : {
1024
+ ...base,
1025
+ get transitions() {
1026
+ return ids();
1027
+ },
1028
+ get through() {
1029
+ return chain.through();
1030
+ }
1031
+ };
1032
+ };
1033
+ const states = [];
1034
+ const stateIds = /* @__PURE__ */ new Set();
1035
+ const folded = /* @__PURE__ */ new Set();
1036
+ for (const element of model.elements) if (isTransparent(element)) folded.add(element.id);
1037
+ else if (stateOf(element) !== void 0) stateIds.add(element.id);
1038
+ const index = chainIndex(model, {
1039
+ folded: (id) => folded.has(id),
1040
+ accepted: (id) => stateIds.has(id),
1041
+ eventOf: (id) => {
1042
+ const element = elements.get(id);
1043
+ return element?.kind === "message" ? element.event : void 0;
1044
+ }
1045
+ });
1046
+ const transitions = [];
1047
+ const origins = [];
1048
+ const firsts = [];
1049
+ for (const element of model.elements) {
1050
+ const state = isTransparent(element) ? void 0 : stateOf(element);
1051
+ if (state === void 0) continue;
1052
+ states.push(state);
1053
+ for (const transition of outgoing.get(element.id) ?? []) {
1054
+ firsts.push(transition);
1055
+ for (const chain of index.from(transition)) {
1056
+ transitions.push(transitionOf(chain));
1057
+ origins.push({
1058
+ first: transition,
1059
+ target: chain.target
1060
+ });
1061
+ }
1062
+ }
1063
+ }
1064
+ const carried = index.carried(firsts);
1065
+ const loss = [...commonLoss(model, "stateMachine", {
1066
+ fragments: /* @__PURE__ */ new Set(),
1067
+ messages: /* @__PURE__ */ new Set([...carried, ...index.unfolded])
1068
+ }), ...unrepresentedLoss(model, "stateMachine", /* @__PURE__ */ new Set([...stateIds, ...[...folded].filter((id) => !index.unfolded.has(id))]), index.unfolded)];
1069
+ const skipped = model.elements.filter((element) => element.kind === "activity" && isTransparent(element) && !index.unfolded.has(element.id));
1070
+ if (skipped.length > 0) loss.push({
1071
+ kind: "subject",
1072
+ subject,
1073
+ elements: skipped.map((element) => element.id)
1074
+ });
1075
+ return {
1076
+ machine: {
1077
+ subject,
1078
+ states,
1079
+ transitions,
1080
+ loss
1081
+ },
1082
+ origins,
1083
+ index
1084
+ };
1085
+ };
1086
+ /**
1087
+ * Activity-as-state projection. Each activity that affects the subject becomes a state the subject entity rests in, and a decision collapses into guarded transitions leaving the state before it. The target activity's action becomes the effect of the transition that enters it.
1088
+ *
1089
+ * Which activities affect the subject is declared by their `affects`. An activity that does not list the subject is not a state of it: transitions through it are folded into the transition that leaves the previous state, exactly as a decision is. Authored `state` elements and pseudo-states are always kept. When no activity in the model declares `affects`, the model carries no such information and every activity is kept, which is the unscoped behaviour.
1090
+ *
1091
+ * A `message` element is folded the same way, and its `event`, when it has one, triggers the transition that carries it. A message element no drawn transition carries is reported as a `message-elements` loss.
1092
+ *
1093
+ * Each drawn transition lists the model `transitions` it stands for and the elements folded into it (`through`), so an edit to it maps back to the model. Several routes through folded elements from the same transition to the same state are one drawn transition whose `transitions` and `through` are the union over the routes, each once in the order met; it carries no event or guard, which differ by route, and its effect is only the target's entry action.
1094
+ *
1095
+ * Decisions are folded into guards by design and are not a loss. Fork, join and history pseudo-states have no state of their own here and are reported as unrepresented, together with the transitions that touch them, which are left out rather than pointing at a state that is not drawn.
1096
+ *
1097
+ * Other conventions exist, such as steps as transitions with states between them. Naming states such as "Paid" needs authored states, which the model can hold as `state` elements.
1098
+ * @param model - The model to project.
1099
+ * @param subject - The entity whose lifecycle the machine shows.
1100
+ * @returns The states in model order, the transitions leaving each in turn, and what was dropped.
1101
+ * @throws Error when `subject` is not a declared entity participant, which only a runtime model can cause.
1102
+ */
1103
+ const toStateMachine = (model, subject) => stateMachineParts(model, subject).machine;
1104
+ //#endregion
1105
+ //#region ../../core/graph/projection/dist/fragments.js
1106
+ /** A choice or a split needs at least two branches, and an `opt` is exactly a choice between doing something and skipping it. */
1107
+ const minBranches = 2;
1108
+ /** The virtual end every last step leads to, for finding where branches meet. A number, so it never equals an element id, which is a string. */
1109
+ const end = 0;
1110
+ const derivedItem = (element, operator) => (operands) => ({
1111
+ kind: "fragment",
1112
+ element,
1113
+ operator,
1114
+ operands
1115
+ });
1116
+ /** Appends `value` to the list `map` holds under `key`, starting the list when there is none. */
1117
+ const append = (map, key, value) => {
1118
+ const list = map.get(key);
1119
+ if (list === void 0) map.set(key, [value]);
1120
+ else list.push(value);
1121
+ };
1122
+ /**
1123
+ * The fragments the model's structure implies along the scenario, in model order of the decision or fork each comes from, each decision's loop before its other fragments.
1124
+ *
1125
+ * - A decision transition whose target is in the decision's strongly connected component goes round again, the rule `graph-domain` uses for a legal cycle. Each component holding such a decision on the path draws one `loop`, holding the messages that arrive inside the component, guarded by those transitions' guards joined with "or".
1126
+ * - Each time the path takes one of a decision's other (forward) branches, when it has at least two, an `alt` holds the messages from that step until the path reaches where the branches meet: the decision's immediate post-dominator over forward transitions, or the end of the path when they never meet. With exactly two branches, one going straight to where they meet, it is an `opt`, and taking that empty branch draws nothing. The path coming back to the decision ends the earlier occurrence.
1127
+ * - Each time the path leaves a fork, a `par` holds one operand per branch taken, each with the messages of the steps that follow on from that branch until it reaches the fork's immediate post-dominator; a branch taken again starts a new `par`.
1128
+ *
1129
+ * One pass finds every component and one pass every post-dominator, both only when the path passes a decision or fork, and the path is then read once, so the work is the size of the model and of the path, not their product.
1130
+ */
1131
+ const deriveCandidates = ({ model, steps, entries, onPath, observe }) => {
1132
+ const branching = model.elements.filter((element) => onPath.has(element.id) && (element.kind === "decision" || element.kind === "pseudo" && element.role === "fork"));
1133
+ if (branching.length === 0) return [];
1134
+ const outgoing = outgoingMap(model);
1135
+ const ids = model.elements.map((element) => element.id);
1136
+ const component = /* @__PURE__ */ new Map();
1137
+ for (const members of stronglyConnectedComponents(buildDag(ids, (id) => (outgoing.get(id) ?? []).map((transition) => transition.target)))) for (const member of members) component.set(member, members);
1138
+ const loops = /* @__PURE__ */ new Set();
1139
+ for (const element of model.elements) {
1140
+ const own = component.get(element.id);
1141
+ if (element.kind !== "decision" || own === void 0) continue;
1142
+ for (const transition of outgoing.get(element.id) ?? []) if (component.get(transition.target) === own) loops.add(transition.id);
1143
+ }
1144
+ const before = /* @__PURE__ */ new Map();
1145
+ const last = [];
1146
+ for (const id of ids) {
1147
+ const forward = (outgoing.get(id) ?? []).filter((transition) => !loops.has(transition.id));
1148
+ if (forward.length === 0) last.push(id);
1149
+ for (const transition of forward) append(before, transition.target, id);
1150
+ }
1151
+ const meets = immediateDominators(buildDag([end, ...ids], (id) => id === end ? last : before.get(id) ?? []), end);
1152
+ /** Where an element's ways forward meet, or `undefined` when they only meet at the end. */
1153
+ const meetOf = (id) => {
1154
+ const meet = meets.get(id);
1155
+ return meet === void 0 || meet === end ? void 0 : meet;
1156
+ };
1157
+ const found = /* @__PURE__ */ new Map();
1158
+ const add = (element, candidate) => {
1159
+ append(found, element, candidate);
1160
+ };
1161
+ const looping = /* @__PURE__ */ new Map();
1162
+ const loopGuards = /* @__PURE__ */ new Map();
1163
+ for (const element of branching) {
1164
+ const own = component.get(element.id);
1165
+ const back = (outgoing.get(element.id) ?? []).filter((transition) => loops.has(transition.id));
1166
+ if (own === void 0 || back.length === 0) continue;
1167
+ if (!looping.has(own)) {
1168
+ looping.set(own, element.id);
1169
+ loopGuards.set(own, /* @__PURE__ */ new Set());
1170
+ }
1171
+ for (const transition of back) if (transition.guard !== void 0) loopGuards.get(own)?.add(transition.guard);
1172
+ }
1173
+ const inside = /* @__PURE__ */ new Map();
1174
+ for (const entry of entries) {
1175
+ const own = component.get(entry.target);
1176
+ if (own !== void 0 && looping.has(own)) {
1177
+ observe?.(1);
1178
+ append(inside, own, entry.index);
1179
+ }
1180
+ }
1181
+ for (const [own, element] of looping) {
1182
+ const guards = [...loopGuards.get(own) ?? []];
1183
+ add(element, {
1184
+ authored: void 0,
1185
+ operands: [{
1186
+ guard: guards.length > 0 ? guards.join(" or ") : void 0,
1187
+ positions: inside.get(own) ?? []
1188
+ }],
1189
+ item: derivedItem(element, "loop")
1190
+ });
1191
+ }
1192
+ /** Each branching element's forward branch count, where they meet, and, for a decision, whether it draws an `opt`: found once per element, not once per step that leaves it. */
1193
+ const shapes = /* @__PURE__ */ new Map();
1194
+ for (const element of branching) {
1195
+ const forward = (outgoing.get(element.id) ?? []).filter((transition) => !loops.has(transition.id));
1196
+ const meet = meetOf(element.id);
1197
+ const direct = forward.filter((branch) => branch.target === meet).length;
1198
+ shapes.set(element.id, {
1199
+ branches: forward.length,
1200
+ meet,
1201
+ operator: forward.length === minBranches && direct === 1 ? "opt" : "alt"
1202
+ });
1203
+ }
1204
+ const decisions = new Set(branching.flatMap((element) => element.kind === "decision" ? [element.id] : []));
1205
+ const waiting = /* @__PURE__ */ new Map();
1206
+ const openAt = /* @__PURE__ */ new Map();
1207
+ const closed = /* @__PURE__ */ new Set();
1208
+ const close = (occurrence, stop) => {
1209
+ if (closed.has(occurrence)) return;
1210
+ closed.add(occurrence);
1211
+ if (openAt.get(occurrence.element) === occurrence) openAt.delete(occurrence.element);
1212
+ if (stop > occurrence.start) add(occurrence.element, {
1213
+ authored: void 0,
1214
+ operands: [{
1215
+ guard: occurrence.guard,
1216
+ from: occurrence.start,
1217
+ to: stop - 1
1218
+ }],
1219
+ item: derivedItem(occurrence.element, occurrence.operator)
1220
+ });
1221
+ };
1222
+ const labels = /* @__PURE__ */ new Map();
1223
+ const openParallel = /* @__PURE__ */ new Map();
1224
+ const parallels = [];
1225
+ /** The label a step carrying `label` leaves on `target`: the enclosing one when `target` is where its `par` meets. */
1226
+ const after = (label, target) => label?.parallel.meet === target ? label.parallel.outer : label;
1227
+ const relabel = (target, label) => {
1228
+ const next = after(label, target);
1229
+ if (next === void 0) labels.delete(target);
1230
+ else labels.set(target, next);
1231
+ };
1232
+ for (const [index, step] of steps.entries()) {
1233
+ const { transition } = step;
1234
+ const position = (steps[index + 1]?.before ?? entries.length) > step.before ? step.before : void 0;
1235
+ const source = transition.source;
1236
+ const shape = shapes.get(source);
1237
+ if (decisions.has(source) && shape !== void 0 && shape.branches >= minBranches && !loops.has(transition.id)) {
1238
+ const earlier = openAt.get(source);
1239
+ if (earlier !== void 0) close(earlier, step.before);
1240
+ const { meet, operator } = shape;
1241
+ if (!(operator === "opt" && transition.target === meet)) {
1242
+ const occurrence = {
1243
+ element: source,
1244
+ operator,
1245
+ guard: transition.guard,
1246
+ start: step.before
1247
+ };
1248
+ openAt.set(source, occurrence);
1249
+ if (meet !== void 0) append(waiting, meet, occurrence);
1250
+ }
1251
+ }
1252
+ let label = labels.get(source);
1253
+ if (!decisions.has(source) && shape !== void 0 && shape.branches >= minBranches) {
1254
+ let parallel = openParallel.get(source);
1255
+ if (parallel === void 0 || parallel.taken.has(transition.id)) {
1256
+ parallel = {
1257
+ element: source,
1258
+ meet: shape.meet,
1259
+ outer: label,
1260
+ operands: [],
1261
+ taken: /* @__PURE__ */ new Set()
1262
+ };
1263
+ openParallel.set(source, parallel);
1264
+ parallels.push(parallel);
1265
+ }
1266
+ parallel.taken.add(transition.id);
1267
+ parallel.operands.push({
1268
+ guard: transition.guard,
1269
+ positions: []
1270
+ });
1271
+ label = {
1272
+ parallel,
1273
+ operand: parallel.operands.length - 1
1274
+ };
1275
+ }
1276
+ const holder = after(label, transition.target);
1277
+ if (holder !== void 0 && position !== void 0) {
1278
+ observe?.(1);
1279
+ holder.parallel.operands[holder.operand]?.positions.push(position);
1280
+ }
1281
+ relabel(transition.target, label);
1282
+ for (const occurrence of waiting.get(transition.target) ?? []) close(occurrence, step.before);
1283
+ waiting.delete(transition.target);
1284
+ }
1285
+ for (const occurrence of openAt.values()) close(occurrence, entries.length);
1286
+ for (const parallel of parallels) add(parallel.element, {
1287
+ authored: void 0,
1288
+ operands: parallel.operands,
1289
+ item: derivedItem(parallel.element, "par")
1290
+ });
1291
+ return model.elements.flatMap((element) => found.get(element.id) ?? []);
1292
+ };
1293
+ /**
1294
+ * The authored fragments as candidates. An operand counts when its body is non-empty and wholly on the path; it holds the messages arriving at an element of its body that no earlier operand of the same fragment holds. The positions arriving at each element are found once and shared by every operand holding that element, so an operand is its elements and their shared lists, and matching costs the messages plus the bodies, never a message once per fragment.
1295
+ */
1296
+ const authoredCandidates = (fragments, entries, onPath, observe) => {
1297
+ const arrivals = /* @__PURE__ */ new Map();
1298
+ for (const entry of entries) {
1299
+ observe?.(1);
1300
+ append(arrivals, entry.target, entry.index);
1301
+ }
1302
+ return fragments.map(({ id, operator, operands }) => {
1303
+ const taken = /* @__PURE__ */ new Set();
1304
+ const held = [];
1305
+ for (const operand of operands) {
1306
+ if (operand.body.length === 0 || !operand.body.every((element) => onPath.has(element))) continue;
1307
+ const elements = [];
1308
+ for (const element of operand.body) {
1309
+ observe?.(1);
1310
+ const positions = arrivals.get(element);
1311
+ if (!taken.has(element) && positions !== void 0) elements.push({
1312
+ element,
1313
+ positions
1314
+ });
1315
+ taken.add(element);
1316
+ }
1317
+ if (elements.length > 0) held.push({
1318
+ guard: operand.guard,
1319
+ elements
1320
+ });
1321
+ }
1322
+ return {
1323
+ authored: id,
1324
+ operands: held,
1325
+ item: (drawn) => ({
1326
+ kind: "fragment",
1327
+ fragment: id,
1328
+ operator,
1329
+ operands: drawn
1330
+ })
1331
+ };
1332
+ });
1333
+ };
1334
+ /** How many of the ascending `positions` lie between `from` and `to` inclusive, by two binary searches. */
1335
+ const countBetween = (positions, from, to) => {
1336
+ const firstAtLeast = (value) => {
1337
+ let low = 0;
1338
+ let high = positions.length;
1339
+ while (low < high) {
1340
+ const middle = low + high >>> 1;
1341
+ if ((positions[middle] ?? value) < value) low = middle + 1;
1342
+ else high = middle;
1343
+ }
1344
+ return low;
1345
+ };
1346
+ return firstAtLeast(to + 1) - firstAtLeast(from);
1347
+ };
1348
+ /** The first and last position an operand holds and how many it holds, from its ends or its list's ends. */
1349
+ const extentOf = (held) => {
1350
+ if (held.elements !== void 0) {
1351
+ let first = Number.POSITIVE_INFINITY;
1352
+ let last = Number.NEGATIVE_INFINITY;
1353
+ let count = 0;
1354
+ for (const { positions } of held.elements) {
1355
+ count += positions.length;
1356
+ first = Math.min(first, positions[0] ?? first);
1357
+ last = Math.max(last, positions.at(-1) ?? last);
1358
+ }
1359
+ return count === 0 ? void 0 : {
1360
+ first,
1361
+ last,
1362
+ count
1363
+ };
1364
+ }
1365
+ if (held.positions === void 0) return held.to < held.from ? void 0 : {
1366
+ first: held.from,
1367
+ last: held.to,
1368
+ count: held.to - held.from + 1
1369
+ };
1370
+ const first = held.positions[0];
1371
+ const last = held.positions.at(-1);
1372
+ return first === void 0 || last === void 0 ? void 0 : {
1373
+ first,
1374
+ last,
1375
+ count: held.positions.length
1376
+ };
1377
+ };
1378
+ /** Whether an operand holds every position from `first` to `last`. */
1379
+ const holdsAll = (held, first, last) => {
1380
+ if (held.elements !== void 0) {
1381
+ let count = 0;
1382
+ for (const { positions } of held.elements) count += countBetween(positions, first, last);
1383
+ return count === last - first + 1;
1384
+ }
1385
+ return held.positions === void 0 ? held.from <= first && last <= held.to : countBetween(held.positions, first, last) === last - first + 1;
1386
+ };
1387
+ /** Each operand's body elements as a set, built the first time the operand is asked whether it holds a nested fragment. */
1388
+ const elementSets = /* @__PURE__ */ new WeakMap();
1389
+ /**
1390
+ * Whether a fragment spanning `first` to `last` lies wholly inside operand `slot` of the placed fragment around it, in constant or logarithmic time per check. The outer fragment's messages are consecutive, and both ends of the inner span lie inside it, so a fragment with one operand holds the whole span. A run or list of positions is checked by its ends or by binary search. An operand held by elements holds every message arriving at them, so an authored inner fragment, whose messages are exactly its own elements' and fill the span, fits when its elements are among the operand's; any other inner span is checked against the operand's elements by binary search when they are fewer than the span's positions, and otherwise position by position.
1391
+ */
1392
+ const fits = (outer, slot, inner, { first, last }) => {
1393
+ const { operands } = outer.candidate;
1394
+ const operand = operands[slot];
1395
+ if (operand === void 0) return false;
1396
+ if (operands.length === 1) return true;
1397
+ if (operand.elements === void 0) return holdsAll(operand, first, last);
1398
+ let elements = elementSets.get(operand);
1399
+ if (elements === void 0) {
1400
+ elements = new Set(operand.elements.map(({ element }) => element));
1401
+ elementSets.set(operand, elements);
1402
+ }
1403
+ const held = elements;
1404
+ const innerElements = inner.operands.flatMap((part) => part.elements === void 0 ? [] : [part.elements]);
1405
+ if (innerElements.length === inner.operands.length) return innerElements.every((list) => list.every(({ element }) => held.has(element)));
1406
+ if (operand.elements.length <= last - first + 1) return holdsAll(operand, first, last);
1407
+ for (let position = first; position <= last; position += 1) {
1408
+ const element = outer.elementAt(position);
1409
+ if (element === void 0 || !held.has(element)) return false;
1410
+ }
1411
+ return true;
1412
+ };
1413
+ /**
1414
+ * Which of a fragment's operands holds a position: listed positions are looked up in a map built from the lists, which together hold no more positions than the fragment does, and runs are found by a binary search over their starts. No run is expanded.
1415
+ */
1416
+ const slotIndex = (operands, elementAt, observe) => {
1417
+ if (operands.length === 1) return () => 0;
1418
+ const listed = /* @__PURE__ */ new Map();
1419
+ const byElement = /* @__PURE__ */ new Map();
1420
+ const runs = [];
1421
+ for (const [slot, operand] of operands.entries()) {
1422
+ if (operand.elements !== void 0) {
1423
+ for (const { element } of operand.elements) {
1424
+ observe?.(1);
1425
+ byElement.set(element, slot);
1426
+ }
1427
+ continue;
1428
+ }
1429
+ if (operand.positions === void 0) {
1430
+ runs.push({
1431
+ from: operand.from,
1432
+ to: operand.to,
1433
+ slot
1434
+ });
1435
+ continue;
1436
+ }
1437
+ for (const position of operand.positions) {
1438
+ observe?.(1);
1439
+ listed.set(position, slot);
1440
+ }
1441
+ }
1442
+ runs.sort((a, b) => a.from - b.from);
1443
+ return (position) => {
1444
+ const element = elementAt(position);
1445
+ const found = listed.get(position) ?? (element === void 0 ? void 0 : byElement.get(element));
1446
+ if (found !== void 0) return found;
1447
+ let low = 0;
1448
+ let high = runs.length;
1449
+ while (low < high) {
1450
+ const middle = low + high >>> 1;
1451
+ if ((runs[middle]?.from ?? position) <= position) low = middle + 1;
1452
+ else high = middle;
1453
+ }
1454
+ const run = runs[low - 1];
1455
+ return run !== void 0 && position <= run.to ? run.slot : 0;
1456
+ };
1457
+ };
1458
+ /**
1459
+ * Which placed fragment is innermost at each position, without visiting the positions a fragment covers: fragments are placed largest first, so the innermost at a position is the one placed last among those covering it. A segment tree over the positions records, on the nodes that exactly cover each placed span, when it was placed; the innermost at a position is the latest placement on the path from its leaf to the root. Placing and asking each visit a number of nodes that grows with the logarithm of the number of positions.
1460
+ */
1461
+ const placementTree = (size) => {
1462
+ const latest = Array.from({ length: 2 * size }, () => void 0);
1463
+ return {
1464
+ place: (first, last, time) => {
1465
+ let low = first + size;
1466
+ let high = last + size + 1;
1467
+ while (low < high) {
1468
+ if ((low & 1) === 1) {
1469
+ latest[low] = time;
1470
+ low += 1;
1471
+ }
1472
+ if ((high & 1) === 1) {
1473
+ high -= 1;
1474
+ latest[high] = time;
1475
+ }
1476
+ low >>>= 1;
1477
+ high >>>= 1;
1478
+ }
1479
+ },
1480
+ at: (position) => {
1481
+ let best;
1482
+ for (let node = position + size; node >= 1; node >>>= 1) {
1483
+ const time = latest[node];
1484
+ if (time !== void 0 && (best === void 0 || time > best)) best = time;
1485
+ }
1486
+ return best;
1487
+ }
1488
+ };
1489
+ };
1490
+ /**
1491
+ * Wraps the scenario's messages in the fragments they fall inside: the authored ones first, then those derived from the model's structure.
1492
+ *
1493
+ * A fragment is drawn when it holds at least one message and the messages it holds are consecutive. Larger fragments are placed first; a fragment nests inside a placed one when all its messages lie in one of that fragment's operands, and is left out when it overlaps one without nesting. A derived fragment holding exactly the messages an authored one holds is not drawn: the authored fragment is the author's notation for the same structure.
1494
+ *
1495
+ * Fragments are compared and placed by the ends of their spans, and a segment tree answers which placed fragment is innermost at a position, so no span is ever expanded into its positions; the items are then built in one pass over the messages.
1496
+ * @param path - The scenario; its `observe`, when given, is told of the work done over message positions.
1497
+ * @returns The items and the ids of the authored fragments drawn.
1498
+ */
1499
+ const wrapFragments = (path) => {
1500
+ const { model, entries, onPath, observe } = path;
1501
+ const candidates = [...authoredCandidates(model.fragments, entries, onPath, observe), ...deriveCandidates(path)];
1502
+ const spans = [];
1503
+ const authoredSpans = /* @__PURE__ */ new Set();
1504
+ for (const [order, candidate] of candidates.entries()) {
1505
+ let first = Number.POSITIVE_INFINITY;
1506
+ let last = Number.NEGATIVE_INFINITY;
1507
+ let count = 0;
1508
+ for (const operand of candidate.operands) {
1509
+ const extent = extentOf(operand);
1510
+ if (extent !== void 0) {
1511
+ count += extent.count;
1512
+ first = Math.min(first, extent.first);
1513
+ last = Math.max(last, extent.last);
1514
+ }
1515
+ }
1516
+ const key = `${String(first)}:${String(last)}`;
1517
+ if (count === 0 || last - first + 1 !== count) continue;
1518
+ if (candidate.authored !== void 0) authoredSpans.add(key);
1519
+ else if (authoredSpans.has(key)) continue;
1520
+ spans.push({
1521
+ candidate,
1522
+ first,
1523
+ last,
1524
+ order
1525
+ });
1526
+ }
1527
+ spans.sort((a, b) => b.last - b.first - (a.last - a.first) || a.order - b.order);
1528
+ const tree = placementTree(entries.length);
1529
+ const elementAt = (position) => entries[position]?.target;
1530
+ const placed = [];
1531
+ const innermost = (position) => {
1532
+ const time = tree.at(position);
1533
+ return time === void 0 ? void 0 : placed[time];
1534
+ };
1535
+ for (const { candidate, first, last, order } of spans) {
1536
+ const outer = innermost(first);
1537
+ if (outer !== innermost(last)) continue;
1538
+ let parent;
1539
+ if (outer !== void 0) {
1540
+ const slot = outer.slotOf(first);
1541
+ if (!fits(outer, slot, candidate, {
1542
+ first,
1543
+ last
1544
+ })) continue;
1545
+ parent = {
1546
+ placed: outer,
1547
+ slot
1548
+ };
1549
+ }
1550
+ const node = {
1551
+ candidate,
1552
+ first,
1553
+ last,
1554
+ slotOf: slotIndex(candidate.operands, elementAt, observe),
1555
+ elementAt,
1556
+ parent,
1557
+ order
1558
+ };
1559
+ tree.place(first, last, placed.length);
1560
+ placed.push(node);
1561
+ }
1562
+ const top = [];
1563
+ const contents = new Map(placed.map((node) => [node, node.candidate.operands.map(() => [])]));
1564
+ const contentOf = (holder) => holder === void 0 ? top : contents.get(holder.placed)?.[holder.slot] ?? top;
1565
+ const starting = /* @__PURE__ */ new Map();
1566
+ for (const node of placed) append(starting, node.first, node);
1567
+ for (const entry of entries) {
1568
+ observe?.(1);
1569
+ for (const node of starting.get(entry.index) ?? []) contentOf(node.parent).push({ placed: node });
1570
+ const owner = innermost(entry.index);
1571
+ contentOf(owner === void 0 ? void 0 : {
1572
+ placed: owner,
1573
+ slot: owner.slotOf(entry.index)
1574
+ }).push({ entry });
1575
+ }
1576
+ const built = /* @__PURE__ */ new Map();
1577
+ const itemsOf = (content) => content.flatMap((part) => {
1578
+ if ("entry" in part) return [{
1579
+ kind: "message",
1580
+ message: part.entry.message
1581
+ }];
1582
+ const item = built.get(part.placed);
1583
+ return item === void 0 ? [] : [item];
1584
+ });
1585
+ const drawn = /* @__PURE__ */ new Set();
1586
+ for (const node of placed.toReversed()) {
1587
+ const operands = (contents.get(node) ?? []).map((content, slot) => {
1588
+ const guard = node.candidate.operands[slot]?.guard;
1589
+ return {
1590
+ ...guard === void 0 ? {} : { guard },
1591
+ items: itemsOf(content)
1592
+ };
1593
+ });
1594
+ built.set(node, node.candidate.item(operands));
1595
+ if (node.candidate.authored !== void 0) drawn.add(node.candidate.authored);
1596
+ }
1597
+ return {
1598
+ items: itemsOf(top),
1599
+ drawn
1600
+ };
1601
+ };
1602
+ //#endregion
1603
+ //#region ../../core/graph/projection/dist/sequence.js
1604
+ /**
1605
+ * `toSequence`, telling `observe` of the work done over message positions so a caller can measure it.
1606
+ * @param model - The model to project.
1607
+ * @param scenario - The transitions the path takes, in order.
1608
+ * @param observe - Told of work done over message positions.
1609
+ */
1610
+ const sequenceObserved = (model, scenario, observe) => {
1611
+ const actors = actorMap(model);
1612
+ const elements = new Map(model.elements.map((element) => [element.id, element]));
1613
+ const transitions = new Map(model.transitions.map((transition) => [transition.id, transition]));
1614
+ const eventNames = new Map(model.events.map((event) => [event.id, event.name]));
1615
+ const labelOf = (id) => {
1616
+ const element = elements.get(id);
1617
+ return element?.kind === "activity" || element?.kind === "decision" ? element.label : void 0;
1618
+ };
1619
+ const skipped = [];
1620
+ const lifelines = [];
1621
+ const onLifeline = /* @__PURE__ */ new Set();
1622
+ const messages = [];
1623
+ const entries = [];
1624
+ const steps = [];
1625
+ const shownMessages = /* @__PURE__ */ new Set();
1626
+ const holder = /* @__PURE__ */ new Map();
1627
+ let arrivedAt;
1628
+ const draw = (message, target) => {
1629
+ for (const participant of [message.from, message.to]) if (!onLifeline.has(participant)) {
1630
+ onLifeline.add(participant);
1631
+ lifelines.push(participant);
1632
+ }
1633
+ entries.push({
1634
+ index: messages.length,
1635
+ message,
1636
+ target
1637
+ });
1638
+ messages.push(message);
1639
+ };
1640
+ for (const id of scenario) {
1641
+ const transition = transitions.get(id);
1642
+ if (transition === void 0) throw new Error(`Scenario step "${id}" is not a declared transition`);
1643
+ steps.push({
1644
+ transition,
1645
+ before: entries.length
1646
+ });
1647
+ const source = elements.get(transition.source);
1648
+ const target = elements.get(transition.target);
1649
+ const previous = arrivedAt;
1650
+ arrivedAt = transition.target;
1651
+ if (target?.kind === "message") {
1652
+ shownMessages.add(target.id);
1653
+ holder.set(target.id, target.to);
1654
+ draw({
1655
+ transition: id,
1656
+ from: target.from,
1657
+ to: target.to,
1658
+ label: target.label,
1659
+ element: target.id,
1660
+ mode: target.mode
1661
+ }, target.id);
1662
+ continue;
1663
+ }
1664
+ if (source?.kind === "message") {
1665
+ if (previous !== source.id) {
1666
+ shownMessages.add(source.id);
1667
+ draw({
1668
+ transition: id,
1669
+ from: source.from,
1670
+ to: source.to,
1671
+ label: source.label,
1672
+ element: source.id,
1673
+ mode: source.mode
1674
+ }, source.id);
1675
+ }
1676
+ const to = actors.get(transition.target);
1677
+ holder.set(transition.target, to ?? source.to);
1678
+ continue;
1679
+ }
1680
+ const from = actors.get(transition.source) ?? holder.get(transition.source);
1681
+ const to = actors.get(transition.target);
1682
+ const held = to ?? from;
1683
+ if (held !== void 0) holder.set(transition.target, held);
1684
+ if (from === void 0 || to === void 0) {
1685
+ skipped.push(id);
1686
+ continue;
1687
+ }
1688
+ draw({
1689
+ transition: id,
1690
+ from,
1691
+ to,
1692
+ label: (transition.trigger === void 0 ? void 0 : eventNames.get(transition.trigger)) ?? labelOf(transition.target) ?? id
1693
+ }, transition.target);
1694
+ }
1695
+ const onPath = /* @__PURE__ */ new Set();
1696
+ const taken = new Set(scenario);
1697
+ for (const id of taken) {
1698
+ const transition = transitions.get(id);
1699
+ if (transition !== void 0) {
1700
+ onPath.add(transition.source);
1701
+ onPath.add(transition.target);
1702
+ }
1703
+ }
1704
+ const offPath = model.elements.filter((element) => !onPath.has(element.id));
1705
+ const unshown = model.transitions.filter((transition) => !taken.has(transition.id) && onPath.has(transition.source));
1706
+ const { items, drawn } = wrapFragments({
1707
+ model,
1708
+ steps,
1709
+ entries,
1710
+ onPath,
1711
+ ...observe === void 0 ? {} : { observe }
1712
+ });
1713
+ const loss = [...commonLoss(model, "sequence", {
1714
+ fragments: drawn,
1715
+ messages: shownMessages
1716
+ })];
1717
+ if (offPath.length > 0) loss.push({
1718
+ kind: "scenario",
1719
+ elements: offPath.map((element) => element.id)
1720
+ });
1721
+ if (unshown.length > 0) loss.push({
1722
+ kind: "unshown-branches",
1723
+ transitions: unshown.map((transition) => transition.id)
1724
+ });
1725
+ if (skipped.length > 0) loss.push({
1726
+ kind: "skipped-steps",
1727
+ transitions: skipped
1728
+ });
1729
+ return {
1730
+ lifelines,
1731
+ messages,
1732
+ items,
1733
+ loss
1734
+ };
1735
+ };
1736
+ /**
1737
+ * One path through the process as messages.
1738
+ *
1739
+ * A step between two elements with actors becomes a message, labelled by the transition's event when it has one and by the target's label otherwise. A step arriving at a `message` element draws that message, with its own `from`, `to`, `label` and `mode`, and the step leaving it continues the same message rather than drawing another. An element with no actor that the scenario passes through, such as a fork or join, passes on whoever reached it: a step leaving it is sent by the actor of the step that arrived. A step that still has no sender, or that arrives at an element with no actor, draws nothing and is reported as `skipped-steps`. Branches off the path are not drawn, which is why this direction is lossy and one-to-many.
1740
+ *
1741
+ * `messages` is the flat list. `items` is the same messages with fragments wrapped around the ones that fall inside them: the authored `fragments` the scenario passes through, and those its structure implies (an `alt` or `opt` at a decision, a `loop` back through a decision, a `par` at a fork), each derived fragment naming the decision or fork it comes from. A fragment that cannot be drawn faithfully is left out, and an authored one left out is reported in `loss`.
1742
+ * @param model - The model to project.
1743
+ * @param scenario - The transitions the path takes, in order.
1744
+ * @returns Lifelines in order of first appearance, the messages, the items and what was dropped.
1745
+ * @throws Error when a scenario step is not a declared transition.
1746
+ */
1747
+ const toSequence = (model, scenario) => sequenceObserved(model, scenario, void 0);
1748
+ //#endregion
1749
+ //#region ../../core/graph/domain/dist/facts.js
1750
+ /** The only field of a reserved key. Keys that carry it are resolved from the overlay, so a `Facts` implementation must not use it. */
1751
+ const elementField = "$element";
1752
+ /**
1753
+ * Builds the reserved key that reads another element's run state inside a condition. It resolves to the text `"done"` or `"open"`, and is not found (so the condition is indeterminate) when the overlay says `"unknown"` or the id is not an element of the model.
1754
+ *
1755
+ * The value is the overlay's own state, not the derived status: a condition therefore never depends on the derivation that evaluates it, and cannot form a cycle.
1756
+ * @param id - The element whose state is read.
1757
+ * @returns A key to put in a trilean `reference` node.
1758
+ */
1759
+ const elementStatusKey = (id) => ({ [elementField]: id });
1760
+ /** The only field of the key the package puts to the port to ask whether an input artefact is provided. */
1761
+ const artefactField = "$artefact";
1762
+ /**
1763
+ * Builds the key the package asks the facts port when it needs to know whether an artefact has been provided from outside the process. An artefact is provided exactly when the port answers `{ found: true }` with the boolean `true`; a not-found or `false` answer means it is not.
1764
+ *
1765
+ * A provided artefact satisfies every consumer, whether or not an activity also produces it.
1766
+ * @param id - The artefact.
1767
+ * @returns The key the port is asked.
1768
+ */
1769
+ const artefactKey = (id) => ({ [artefactField]: id });
1770
+ /**
1771
+ * Whether the facts port reports an artefact as provided.
1772
+ * @param facts - The injected source of facts.
1773
+ * @param id - The artefact.
1774
+ */
1775
+ const isProvided = (facts, id) => {
1776
+ const answer = facts(artefactKey(id));
1777
+ return answer.found && answer.value.kind === "boolean" && answer.value.value;
1778
+ };
1779
+ /**
1780
+ * Thrown when a condition uses a node whose evaluation needs a table or a collection from the facts port, which answers single keys only.
1781
+ */
1782
+ var UnsupportedConditionError = class extends Error {
1783
+ /** The kind of reference the condition used. */
1784
+ reference;
1785
+ /**
1786
+ * @param reference - The unsupported kind of reference.
1787
+ */
1788
+ constructor(reference) {
1789
+ super(`A condition uses a ${reference} reference, which the Facts port does not answer: it resolves single keys only`);
1790
+ this.name = "UnsupportedConditionError";
1791
+ this.reference = reference;
1792
+ }
1793
+ };
1794
+ const evaluator = createSyncEvaluator({});
1795
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1796
+ /**
1797
+ * Evaluates every transition's condition.
1798
+ *
1799
+ * A definite true is `taken`, a definite false is `not-taken` and an indeterminate result is `indeterminate`. A transition without a condition is `taken`. Conditions are evaluated for every transition regardless of the state of its source.
1800
+ * @param model - The model whose transitions are evaluated.
1801
+ * @param overlay - Run state, read by `elementStatusKey` references.
1802
+ * @param facts - The injected source of facts.
1803
+ * @returns The outcome of every transition, in transition order.
1804
+ * @throws UnsupportedConditionError when a condition contains a `lookup`, `some`, `every` or fold node.
1805
+ */
1806
+ const evaluateBranches = (model, overlay, facts) => {
1807
+ const elementIds = new Set(model.elements.map(({ id }) => id));
1808
+ const overlayOf = new Map(Object.entries(overlay));
1809
+ const resolvers = {
1810
+ resolveValue: (key) => {
1811
+ if (!isRecord(key) || !(elementField in key)) return facts(key);
1812
+ const id = key[elementField];
1813
+ if (typeof id !== "string" || !elementIds.has(id)) return { found: false };
1814
+ const state = overlayOf.get(id);
1815
+ if (state === "unknown") return { found: false };
1816
+ return {
1817
+ found: true,
1818
+ value: {
1819
+ kind: "text",
1820
+ value: state === "done" ? "done" : "open"
1821
+ }
1822
+ };
1823
+ },
1824
+ resolveLookup: () => {
1825
+ throw new UnsupportedConditionError("lookup");
1826
+ },
1827
+ resolveCollection: () => {
1828
+ throw new UnsupportedConditionError("collection");
1829
+ }
1830
+ };
1831
+ return new Map(model.transitions.map(({ id, condition }) => {
1832
+ if (condition === void 0) return [id, "taken"];
1833
+ const result = evaluator.evaluatePredicate(condition, void 0, resolvers);
1834
+ if (result.status === "indeterminate") return [id, "indeterminate"];
1835
+ return [id, result.value ? "taken" : "not-taken"];
1836
+ }));
1837
+ };
1838
+ //#endregion
1839
+ //#region ../../core/graph/domain/dist/lookup.js
1840
+ /**
1841
+ * Reads a value out of a map built over every element of a model.
1842
+ * @throws UnknownNodeError when the key is absent, which for such a map means the model refers to an element it does not declare.
1843
+ */
1844
+ const lookup = (map, id) => {
1845
+ const value = map.get(id);
1846
+ if (value === void 0) throw new UnknownNodeError(id);
1847
+ return value;
1848
+ };
1849
+ //#endregion
1850
+ //#region ../../core/graph/domain/dist/derive.js
1851
+ /** Which of the derivation's rules decided an element's status, in the order the rules are applied. */
1852
+ const statusRules = [
1853
+ "overlay-done",
1854
+ "overlay-unknown",
1855
+ "unknown-need",
1856
+ "all-cut",
1857
+ "needs-met",
1858
+ "waiting"
1859
+ ];
1860
+ /**
1861
+ * Derives the status of every element and the structures the queries share.
1862
+ *
1863
+ * Elements are visited in dependency order of the control graph. For each element, with its incoming non-loop transitions:
1864
+ *
1865
+ * 1. A transition is cut when its condition is definitely false or its source is `skipped`. The others are live.
1866
+ * 2. `done` when the overlay says `done`.
1867
+ * 3. `unknown` when the overlay says `unknown`, a live transition's condition is indeterminate or its source is `unknown`, or a consumed artefact that is not provided and has no done producer has an `unknown` producer.
1868
+ * 4. `skipped` when it has incoming transitions and every one is cut.
1869
+ * 5. `ready` when every live transition's source is `done` and each consumed artefact is provided or has a done producer; `blocked` otherwise. This single rule is also the join rule: a join, like any element, waits for every incoming source that is not skipped.
1870
+ * 6. A `decision` or `pseudo` element has no work of its own: when the rule above gives it `ready`, it is `done`, so downstream elements are not held up by a step nobody can perform. An overlay `unknown` still applies to it.
1871
+ *
1872
+ * An element with no overlay entry is open. `unknown` dominates `blocked`: an element that has an unknown need is `unknown` even if another need is open.
1873
+ */
1874
+ const analyse = ({ model, overlay, facts }) => {
1875
+ const loops = new Set(loopTransitions(model));
1876
+ const dag = controlDag(model);
1877
+ const cycles = findCycles(dag);
1878
+ if (cycles.length > 0) throw new CycleError(cycles);
1879
+ const branches = evaluateBranches(model, overlay, facts);
1880
+ const elements = new Map(model.elements.map((element) => [element.id, element]));
1881
+ const incoming = new Map(model.elements.map(({ id }) => [id, []]));
1882
+ for (const transition of model.transitions) if (!loops.has(transition.id)) lookup(incoming, transition.target).push(transition.id);
1883
+ const transitions = new Map(model.transitions.map((transition) => [transition.id, transition]));
1884
+ const producers = /* @__PURE__ */ new Map();
1885
+ for (const element of model.elements) if (element.kind === "activity") for (const artefact of element.produces ?? []) producers.set(artefact, [...producers.get(artefact) ?? [], element.id]);
1886
+ const statuses = /* @__PURE__ */ new Map();
1887
+ const liveNeeds = /* @__PURE__ */ new Map();
1888
+ const basis = /* @__PURE__ */ new Map();
1889
+ for (const id of topologicalLayers(dag).layers.flat()) {
1890
+ const element = lookup(elements, id);
1891
+ const edges = lookup(incoming, id).map((transitionId) => {
1892
+ const source = lookup(transitions, transitionId).source;
1893
+ const branch = lookup(branches, transitionId);
1894
+ const sourceStatus = lookup(statuses, source);
1895
+ return {
1896
+ transition: transitionId,
1897
+ source,
1898
+ branch,
1899
+ sourceStatus,
1900
+ cut: branch === "not-taken" || sourceStatus === "skipped"
1901
+ };
1902
+ });
1903
+ const live = edges.filter(({ cut }) => !cut);
1904
+ const dataNeeds = /* @__PURE__ */ new Set();
1905
+ const artefacts = [];
1906
+ let dataUnknown = false;
1907
+ let dataUnmet = false;
1908
+ for (const artefact of element.kind === "activity" ? element.consumes ?? [] : []) {
1909
+ const makers = producers.get(artefact) ?? [];
1910
+ const made = makers.map((maker) => lookup(statuses, maker));
1911
+ const provided = isProvided(facts, artefact);
1912
+ const satisfied = provided || made.includes("done");
1913
+ artefacts.push({
1914
+ artefact,
1915
+ provided,
1916
+ producers: makers.map((maker) => ({
1917
+ element: maker,
1918
+ status: lookup(statuses, maker)
1919
+ })),
1920
+ satisfied
1921
+ });
1922
+ if (satisfied) continue;
1923
+ dataUnmet = true;
1924
+ dataUnknown ||= made.includes("unknown");
1925
+ for (const maker of makers) if (lookup(statuses, maker) !== "skipped") dataNeeds.add(maker);
1926
+ }
1927
+ liveNeeds.set(id, [.../* @__PURE__ */ new Set([...live.map(({ source }) => source), ...dataNeeds])]);
1928
+ const own = overlay[id];
1929
+ let status;
1930
+ let rule;
1931
+ if (own === "done") {
1932
+ status = "done";
1933
+ rule = "overlay-done";
1934
+ } else if (own === "unknown") {
1935
+ status = "unknown";
1936
+ rule = "overlay-unknown";
1937
+ } else if (dataUnknown || live.some(({ branch, sourceStatus }) => branch === "indeterminate" || sourceStatus === "unknown")) {
1938
+ status = "unknown";
1939
+ rule = "unknown-need";
1940
+ } else if (edges.length > 0 && live.length === 0) {
1941
+ status = "skipped";
1942
+ rule = "all-cut";
1943
+ } else if (!dataUnmet && live.every(({ sourceStatus }) => sourceStatus === "done")) {
1944
+ status = element.kind === "decision" || element.kind === "pseudo" ? "done" : "ready";
1945
+ rule = "needs-met";
1946
+ } else {
1947
+ status = "blocked";
1948
+ rule = "waiting";
1949
+ }
1950
+ statuses.set(id, status);
1951
+ basis.set(id, {
1952
+ rule,
1953
+ transitions: edges,
1954
+ artefacts
1955
+ });
1956
+ }
1957
+ return {
1958
+ dag,
1959
+ branches,
1960
+ statuses: new Map(dag.nodes.map((id) => [id, lookup(statuses, id)])),
1961
+ liveNeeds,
1962
+ basis
1963
+ };
1964
+ };
1965
+ /**
1966
+ * The derived status of every element. See `analyse` for the rules; the semantics are documented in the package README.
1967
+ * @param model - The model to read.
1968
+ * @param overlay - Run state by element id.
1969
+ * @param facts - The injected source of facts conditions read, and of which input artefacts are provided (see `artefactKey`).
1970
+ * @returns A status for every element, in model order.
1971
+ * @throws CycleError when the control graph contains an illegal cycle (see `illegalCycles`), since status is undefined on it.
1972
+ * @throws UnknownNodeError when a transition refers to an element the model does not declare.
1973
+ * @throws UnsupportedConditionError when a condition needs a table or collection from the facts port.
1974
+ */
1975
+ const deriveStatuses = (model, overlay, facts) => analyse({
1976
+ model,
1977
+ overlay,
1978
+ facts
1979
+ }).statuses;
1980
+ //#endregion
1981
+ //#region ../../core/graph/domain/dist/progress.js
1982
+ /** Whether an element still has work ahead of it: it is neither finished nor going to be skipped. */
1983
+ const isLive = (status) => status !== "done" && status !== "skipped";
1984
+ /** The live needs of an element that are not done: what it is still waiting for. A finished or skipped element waits on nothing, even when the overlay marked it done ahead of its needs or it consumes an artefact still to be made. */
1985
+ const waitingOn = (analysis, id) => isLive(lookup(analysis.statuses, id)) ? lookup(analysis.liveNeeds, id).filter((need) => lookup(analysis.statuses, need) !== "done") : [];
1986
+ //#endregion
1987
+ //#region ../../core/graph/domain/dist/explain.js
1988
+ /**
1989
+ * Explains an element's status: the rule that decided it, the transitions and artefacts it was decided from, and the chain of unfinished work behind it. The explanation is the derivation's own record, so it always agrees with `deriveStatuses` and `blockedBy`.
1990
+ * @param model - The model to read.
1991
+ * @param overlay - Run state by element id.
1992
+ * @param facts - The injected source of facts conditions read, and of which input artefacts are provided.
1993
+ * @param id - The element asked about.
1994
+ * @returns The explanation.
1995
+ * @throws UnknownNodeError when `id` is not an element.
1996
+ * @throws CycleError when the control graph has an illegal cycle.
1997
+ */
1998
+ const explainStatus = (model, overlay, facts, id) => {
1999
+ const analysis = analyse({
2000
+ model,
2001
+ overlay,
2002
+ facts
2003
+ });
2004
+ const basis = lookup(analysis.basis, id);
2005
+ const reached = /* @__PURE__ */ new Map();
2006
+ const pending = [id];
2007
+ for (let next = pending.pop(); next !== void 0; next = pending.pop()) {
2008
+ if (reached.has(next)) continue;
2009
+ const needs = waitingOn(analysis, next);
2010
+ reached.set(next, needs);
2011
+ pending.push(...needs);
2012
+ }
2013
+ const link = (element) => ({
2014
+ element,
2015
+ status: lookup(analysis.statuses, element),
2016
+ waitingOn: analysis.dag.nodes.filter((node) => lookup(reached, element).includes(node))
2017
+ });
2018
+ return {
2019
+ element: id,
2020
+ status: lookup(analysis.statuses, id),
2021
+ rule: basis.rule,
2022
+ transitions: basis.transitions,
2023
+ artefacts: basis.artefacts,
2024
+ chain: [link(id), ...analysis.dag.nodes.filter((node) => node !== id && reached.has(node)).map(link)]
2025
+ };
2026
+ };
2027
+ //#endregion
2028
+ //#region ../../core/graph/domain/dist/queries.js
2029
+ /**
2030
+ * The elements that can be worked on now: every element whose status is `ready`, in model order. Pure control elements (decisions and pseudo-states) are derived `done` and never appear.
2031
+ * @param model - The model to read.
2032
+ * @param overlay - Run state by element id.
2033
+ * @param facts - The injected source of facts conditions read, and of which input artefacts are provided.
2034
+ * @returns The ready elements.
2035
+ * @throws CycleError when the control graph has an illegal cycle.
2036
+ */
2037
+ const readySet = (model, overlay, facts) => [...analyse({
2038
+ model,
2039
+ overlay,
2040
+ facts
2041
+ }).statuses].filter(([, status]) => status === "ready").map(([id]) => id);
2042
+ /**
2043
+ * What is holding an element back: the minimal set of open elements to finish first.
2044
+ *
2045
+ * Starting from the element's unfinished needs, follows each one's own unfinished needs until it reaches elements that wait on nothing further, and returns exactly those leaves, in model order. Cut transitions (a branch not taken, a skipped source) and provided artefacts are not needs. A leaf is open work that is `ready`, or an element whose own state or condition is `unknown`. An element that is `done`, `skipped` or `ready` is blocked by nothing, and neither is one whose only obstacle is its own unknown state.
2046
+ * @param model - The model to read.
2047
+ * @param overlay - Run state by element id.
2048
+ * @param facts - The injected source of facts conditions read, and of which input artefacts are provided.
2049
+ * @param id - The element asked about.
2050
+ * @returns The leaves of the unfinished-needs closure, in model order.
2051
+ * @throws UnknownNodeError when `id` is not an element.
2052
+ * @throws CycleError when the control graph has an illegal cycle.
2053
+ */
2054
+ const blockedBy = (model, overlay, facts, id) => {
2055
+ const analysis = analyse({
2056
+ model,
2057
+ overlay,
2058
+ facts
2059
+ });
2060
+ lookup(analysis.statuses, id);
2061
+ const leaves = /* @__PURE__ */ new Set();
2062
+ const seen = /* @__PURE__ */ new Set();
2063
+ const pending = [...waitingOn(analysis, id)];
2064
+ for (let next = pending.pop(); next !== void 0; next = pending.pop()) {
2065
+ if (seen.has(next)) continue;
2066
+ seen.add(next);
2067
+ const further = waitingOn(analysis, next);
2068
+ if (further.length === 0) leaves.add(next);
2069
+ else pending.push(...further);
2070
+ }
2071
+ return analysis.dag.nodes.filter((node) => leaves.has(node));
2072
+ };
2073
+ /**
2074
+ * What finishing, delaying or dropping an element affects: the elements that transitively depend on it through paths that are still live.
2075
+ *
2076
+ * Traversal follows each dependent's live needs (see `Analysis.liveNeeds`), so a transition cut by a branch not taken, a skipped element and a loop edge carry no impact, and an element already `done` is neither affected nor traversed through. The element itself is not included.
2077
+ * @param model - The model to read.
2078
+ * @param overlay - Run state by element id.
2079
+ * @param facts - The injected source of facts conditions read, and of which input artefacts are provided.
2080
+ * @param id - The element asked about.
2081
+ * @returns The affected elements, in model order.
2082
+ * @throws UnknownNodeError when `id` is not an element.
2083
+ * @throws CycleError when the control graph has an illegal cycle.
2084
+ */
2085
+ const impact = (model, overlay, facts, id) => {
2086
+ const analysis = analyse({
2087
+ model,
2088
+ overlay,
2089
+ facts
2090
+ });
2091
+ lookup(analysis.statuses, id);
2092
+ const live = analysis.dag.nodes.filter((node) => isLive(lookup(analysis.statuses, node)));
2093
+ const affected = /* @__PURE__ */ new Set();
2094
+ const pending = [id];
2095
+ for (let next = pending.pop(); next !== void 0; next = pending.pop()) for (const node of live) if (!affected.has(node) && node !== id && lookup(analysis.liveNeeds, node).includes(next)) {
2096
+ affected.add(node);
2097
+ pending.push(node);
2098
+ }
2099
+ return live.filter((node) => affected.has(node));
2100
+ };
2101
+ /**
2102
+ * Derives the run again with an element marked `done` in the overlay and reports what changes. Nothing is mutated.
2103
+ * @param model - The model to read.
2104
+ * @param overlay - Run state by element id.
2105
+ * @param facts - The injected source of facts conditions read, and of which input artefacts are provided.
2106
+ * @param id - The element to finish.
2107
+ * @returns The elements that become ready and every status change.
2108
+ * @throws UnknownNodeError when `id` is not an element.
2109
+ * @throws CycleError when the control graph has an illegal cycle.
2110
+ */
2111
+ const whatIfDone = (model, overlay, facts, id) => {
2112
+ const before = analyse({
2113
+ model,
2114
+ overlay,
2115
+ facts
2116
+ }).statuses;
2117
+ lookup(before, id);
2118
+ const changes = [...analyse({
2119
+ model,
2120
+ overlay: {
2121
+ ...overlay,
2122
+ [id]: "done"
2123
+ },
2124
+ facts
2125
+ }).statuses].flatMap(([element, status]) => {
2126
+ const was = lookup(before, element);
2127
+ return was === status ? [] : [{
2128
+ id: element,
2129
+ before: was,
2130
+ after: status
2131
+ }];
2132
+ });
2133
+ return {
2134
+ becomesReady: changes.filter((change) => change.after === "ready").map((change) => change.id),
2135
+ changes
2136
+ };
2137
+ };
2138
+ /**
2139
+ * The heaviest chain through the work that is still ahead: the live elements, those that are neither `done` nor `skipped`, ordered by the live needs that are themselves live.
2140
+ *
2141
+ * A finished or skipped element contributes nothing and does not appear. The chain is computed with `graph-dag`'s `criticalPath`, so its tie-breaking rule holds (the earliest element in model order wins).
2142
+ * @param model - The model to read.
2143
+ * @param overlay - Run state by element id.
2144
+ * @param facts - The injected source of facts conditions read, and of which input artefacts are provided.
2145
+ * @param weight - The cost of an element: finite and not negative.
2146
+ * @returns The path in dependency order and its total weight; empty when nothing is live.
2147
+ * @throws RangeError when `weight` returns a negative or non-finite number.
2148
+ * @throws CycleError when the control graph has an illegal cycle.
2149
+ */
2150
+ const criticalPath = (model, overlay, facts, weight) => {
2151
+ const analysis = analyse({
2152
+ model,
2153
+ overlay,
2154
+ facts
2155
+ });
2156
+ const live = analysis.dag.nodes.filter((node) => isLive(lookup(analysis.statuses, node)));
2157
+ return criticalPath$1(buildDag(live, (id) => lookup(analysis.liveNeeds, id).filter((need) => isLive(lookup(analysis.statuses, need)))), weight);
2158
+ };
2159
+ /**
2160
+ * Every deliverable artefact that is still to be produced, with what is needed to produce it.
2161
+ *
2162
+ * A deliverable is met when it is provided or one of its producers is `done`. An unmet one lists its producers, the unfinished elements that must finish (its unfinished producers and everything those transitively wait on, skipped elements excluded) and the inputs that no one produces and nobody has provided, so a deliverable that can only ever be reached through an unproduced input shows exactly which input is missing.
2163
+ * @param model - The model to read.
2164
+ * @param overlay - Run state by element id.
2165
+ * @param facts - The injected source of facts conditions read, and of which input artefacts are provided.
2166
+ * @returns One entry per unmet deliverable, in declaration order.
2167
+ * @throws CycleError when the control graph has an illegal cycle.
2168
+ */
2169
+ const unmetOutputs = (model, overlay, facts) => {
2170
+ const analysis = analyse({
2171
+ model,
2172
+ overlay,
2173
+ facts
2174
+ });
2175
+ const producersOf = (artefact) => model.elements.flatMap((element) => element.kind === "activity" && element.produces?.includes(artefact) === true ? [element.id] : []);
2176
+ const unmet = [];
2177
+ for (const { id: artefact, deliverable } of model.artefacts) {
2178
+ const producers = producersOf(artefact);
2179
+ if (deliverable !== true || isProvided(facts, artefact) || producers.some((id) => lookup(analysis.statuses, id) === "done")) continue;
2180
+ const needed = /* @__PURE__ */ new Set();
2181
+ const pending = producers.filter((id) => isLive(lookup(analysis.statuses, id)));
2182
+ for (let next = pending.pop(); next !== void 0; next = pending.pop()) {
2183
+ if (needed.has(next)) continue;
2184
+ needed.add(next);
2185
+ pending.push(...waitingOn(analysis, next));
2186
+ }
2187
+ const wanted = /* @__PURE__ */ new Set();
2188
+ for (const element of model.elements) {
2189
+ if (element.kind !== "activity" || !needed.has(element.id)) continue;
2190
+ for (const consumed of element.consumes ?? []) if (!isProvided(facts, consumed) && producersOf(consumed).length === 0) wanted.add(consumed);
2191
+ }
2192
+ unmet.push({
2193
+ artefact,
2194
+ producers,
2195
+ needed: analysis.dag.nodes.filter((id) => needed.has(id)),
2196
+ missingInputs: [...wanted]
2197
+ });
2198
+ }
2199
+ return unmet;
2200
+ };
2201
+ //#endregion
2202
+ export { topologicalLayers as C, immediateDominators as S, toSwimlane as _, unmetOutputs as a, handoffs as b, deriveStatuses as c, artefactKey as d, elementStatusKey as f, toStateMachine as g, stateMachineParts as h, readySet as i, statusRules as l, toSequence as m, criticalPath as n, whatIfDone as o, evaluateBranches as p, impact as r, explainStatus as s, blockedBy as t, UnsupportedConditionError as u, flowchartParts as v, actorMap as w, criticalPath$1 as x, toFlowchart as y };