@graphty/graphty-element 2.6.1 → 3.0.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 (163) hide show
  1. package/dist/ai.js +3 -3
  2. package/dist/catalog.js +53 -54
  3. package/dist/chunks/{AiManager-4iQpsJW1.js → AiManager-Bhh0rR_p.js} +706 -655
  4. package/dist/chunks/GraphSession-DPoTaT3b.js +21175 -0
  5. package/dist/chunks/{GraphtyLogger-B_O67a6c.js → GraphtyLogger-BtcBJQPL.js} +1 -1
  6. package/dist/chunks/{VoiceInputAdapter-Cc6mHXTI.js → VoiceInputAdapter-CdLsJ_nG.js} +1 -1
  7. package/dist/chunks/{XRPivotCameraController-BLa89LXn.js → XRPivotCameraController-CiLJ9Gz6.js} +2 -2
  8. package/dist/chunks/algorithms-qij74zEN.js +6811 -0
  9. package/dist/chunks/{capability-check-Am2zliFj.js → capability-check-BbgTejS3.js} +1 -1
  10. package/dist/chunks/definePalette-BYt2Llxs.js +1333 -0
  11. package/dist/chunks/fields-5uVC1Pll.js +4999 -0
  12. package/dist/chunks/{format-detection-BHwrAVzW.js → format-detection-FKaDMshR.js} +1 -1
  13. package/dist/chunks/{index-BkBLbvui.js → index-Cc_6D9hV.js} +6034 -7127
  14. package/dist/chunks/interpolation-Dk206AhZ.js +105 -0
  15. package/dist/chunks/paletteRegistry-De3CGdst.js +357 -0
  16. package/dist/chunks/parse-SVp77JbE.js +669 -0
  17. package/dist/chunks/{pluginRegistry-Bs8bEkz9.js → pluginRegistry-Ddfl6Mv2.js} +27 -24
  18. package/dist/chunks/{registry-BdGvyZou.js → registry-CgMqldp4.js} +1 -1
  19. package/dist/chunks/{DataSource-BL2UzPff.js → sources-BbAJCDIH.js} +279 -108
  20. package/dist/commands.d.ts +128 -19
  21. package/dist/commands.js +49 -1
  22. package/dist/custom-elements.json +1 -1
  23. package/dist/extend.d.ts +10 -2
  24. package/dist/extend.js +64 -57
  25. package/dist/graphty-catalog.json +6 -3
  26. package/dist/graphty.bundle.js +267177 -240648
  27. package/dist/graphty.js +84 -78
  28. package/dist/index.d.ts +4 -0
  29. package/dist/logging.js +2 -2
  30. package/dist/schema.js +70 -71
  31. package/dist/session.d.ts +5 -6
  32. package/dist/session.js +40 -86
  33. package/dist/src/Edge.d.ts +31 -67
  34. package/dist/src/Graph.d.ts +335 -77
  35. package/dist/src/Node.d.ts +36 -3
  36. package/dist/src/NodeBehavior.d.ts +28 -0
  37. package/dist/src/Styles.d.ts +15 -4
  38. package/dist/src/acceleration/AccelerationController.d.ts +8 -0
  39. package/dist/src/acceleration/narrow.d.ts +9 -1
  40. package/dist/src/acceleration/types.d.ts +10 -0
  41. package/dist/src/ai/AiController.d.ts +12 -0
  42. package/dist/src/ai/AiManager.d.ts +7 -0
  43. package/dist/src/ai/commands/AlgorithmCommands.d.ts +1 -1
  44. package/dist/src/ai/commands/LayoutCommands.d.ts +1 -1
  45. package/dist/src/ai/commands/StyleCommands.d.ts +1 -1
  46. package/dist/src/ai/commands/types.d.ts +20 -1
  47. package/dist/src/algorithms/Algorithm.d.ts +21 -4
  48. package/dist/src/algorithms/BFSAlgorithm.d.ts +0 -9
  49. package/dist/src/algorithms/BellmanFordAlgorithm.d.ts +0 -14
  50. package/dist/src/algorithms/DFSAlgorithm.d.ts +1 -1
  51. package/dist/src/algorithms/FloydWarshallAlgorithm.d.ts +5 -0
  52. package/dist/src/algorithms/GirvanNewmanAlgorithm.d.ts +5 -0
  53. package/dist/src/algorithms/LeidenAlgorithm.d.ts +5 -0
  54. package/dist/src/algorithms/PageRankAlgorithm.d.ts +1 -1
  55. package/dist/src/algorithms/StronglyConnectedComponentsAlgorithm.d.ts +1 -1
  56. package/dist/src/algorithms/metrics/fields.d.ts +23 -1
  57. package/dist/src/algorithms/utils/graphUtils.d.ts +13 -1
  58. package/dist/src/catalog/paletteRegistry.d.ts +4 -4
  59. package/dist/src/catalog/registry.d.ts +3 -2
  60. package/dist/src/catalog/types.d.ts +18 -1
  61. package/dist/src/config/GraphStyle.d.ts +1 -1
  62. package/dist/src/config/StyleTemplate.d.ts +2 -2
  63. package/dist/src/config/xr-config-schema.d.ts +4 -4
  64. package/dist/src/data/CSVDataSource.d.ts +77 -22
  65. package/dist/src/data/ErrorAggregator.d.ts +5 -0
  66. package/dist/src/data/GEXFDataSource.d.ts +12 -61
  67. package/dist/src/data/GraphMLDataSource.d.ts +3 -44
  68. package/dist/src/data/GraphStore.d.ts +322 -15
  69. package/dist/src/data/JsonDataSource.d.ts +43 -1
  70. package/dist/src/data/graph-io-import.d.ts +89 -0
  71. package/dist/src/data/graph-io-records.d.ts +64 -0
  72. package/dist/src/data/lane.d.ts +23 -0
  73. package/dist/src/data/positions.d.ts +13 -0
  74. package/dist/src/data/seedPosition.d.ts +16 -0
  75. package/dist/src/errors/GraphtyError.d.ts +3 -1
  76. package/dist/src/errors/codes.d.ts +23 -0
  77. package/dist/src/events.d.ts +12 -0
  78. package/dist/src/graphty-element.d.ts +149 -54
  79. package/dist/src/input/types.d.ts +2 -0
  80. package/dist/src/layout/D3GraphLayoutEngine.d.ts +17 -3
  81. package/dist/src/layout/FixedLayoutEngine.d.ts +20 -4
  82. package/dist/src/layout/KamadaKawaiLayoutEngine.d.ts +6 -0
  83. package/dist/src/layout/LayoutEngine.d.ts +214 -116
  84. package/dist/src/layout/NGraphLayoutEngine.d.ts +10 -3
  85. package/dist/src/layout/SimulationLayoutEngine.d.ts +8 -3
  86. package/dist/src/managers/AlgorithmManager.d.ts +24 -5
  87. package/dist/src/managers/DataManager.d.ts +258 -181
  88. package/dist/src/managers/EventManager.d.ts +5 -2
  89. package/dist/src/managers/GraphContext.d.ts +7 -0
  90. package/dist/src/managers/InputManager.d.ts +11 -0
  91. package/dist/src/managers/LayoutManager.d.ts +129 -50
  92. package/dist/src/managers/RenderManager.d.ts +14 -1
  93. package/dist/src/managers/UpdateManager.d.ts +20 -0
  94. package/dist/src/screenshot/ScreenshotCapture.d.ts +1 -1
  95. package/dist/src/session/GraphSession.d.ts +83 -6
  96. package/dist/src/session/commands/algo.d.ts +169 -0
  97. package/dist/src/session/commands/config.d.ts +45 -0
  98. package/dist/src/session/commands/data.d.ts +178 -0
  99. package/dist/src/session/commands/doors.d.ts +93 -0
  100. package/dist/src/session/commands/index.d.ts +20 -0
  101. package/dist/src/session/commands/layout.d.ts +104 -0
  102. package/dist/src/session/commands/positions.d.ts +30 -0
  103. package/dist/src/session/commands/sets.d.ts +113 -0
  104. package/dist/src/session/commands/style.d.ts +92 -0
  105. package/dist/src/session/commands/view.d.ts +57 -0
  106. package/dist/src/session/commands/visibility.d.ts +41 -0
  107. package/dist/src/session/data.d.ts +131 -4
  108. package/dist/src/session/index.d.ts +1 -1
  109. package/dist/src/session/planning.d.ts +25 -8
  110. package/dist/src/session/project/Dispatcher.d.ts +905 -0
  111. package/dist/src/session/project/History.d.ts +382 -0
  112. package/dist/src/session/project/arrangement.d.ts +247 -0
  113. package/dist/src/session/project/derive.d.ts +132 -0
  114. package/dist/src/session/project/digest.d.ts +33 -0
  115. package/dist/src/session/project/draft.d.ts +194 -0
  116. package/dist/src/session/project/graphOps.d.ts +304 -0
  117. package/dist/src/session/project/ingest.d.ts +364 -0
  118. package/dist/src/session/project/state.d.ts +145 -0
  119. package/dist/src/session/project/strict.d.ts +68 -0
  120. package/dist/src/session/results/RunResult.d.ts +48 -0
  121. package/dist/src/session/results/statistics.d.ts +20 -0
  122. package/dist/src/session/runs/Run.d.ts +80 -4
  123. package/dist/src/session/runs/RunsApi.d.ts +23 -6
  124. package/dist/src/session/runs/types.d.ts +25 -6
  125. package/dist/src/session/scope/ElementMask.d.ts +14 -0
  126. package/dist/src/session/scope/ScopeApi.d.ts +3 -22
  127. package/dist/src/session/scope/spaces.d.ts +29 -0
  128. package/dist/src/session/sealed.d.ts +22 -0
  129. package/dist/src/session/selection/SelectionApi.d.ts +14 -4
  130. package/dist/src/session/sets/SetsApi.d.ts +13 -5
  131. package/dist/src/session/sets/store.d.ts +54 -53
  132. package/dist/src/session/sets/types.d.ts +5 -2
  133. package/dist/src/session/styles/Layer.d.ts +5 -0
  134. package/dist/src/session/styles/StylesApi.d.ts +68 -17
  135. package/dist/src/session/styles/autoApply.d.ts +64 -53
  136. package/dist/src/session/styles/index.d.ts +3 -3
  137. package/dist/src/session/styles/predicate.d.ts +7 -0
  138. package/dist/src/session/styles/repaint.d.ts +16 -1
  139. package/dist/src/session/styles/sources.d.ts +1 -1
  140. package/dist/src/session/types.d.ts +625 -54
  141. package/dist/src/session/visibility/VisibilityApi.d.ts +38 -18
  142. package/dist/src/session/visibility/filter.d.ts +10 -0
  143. package/dist/src/simple/defineAlgorithm.d.ts +28 -0
  144. package/dist/src/simple/defineLayout.d.ts +35 -0
  145. package/dist/src/simple/defineLogDestination.d.ts +31 -0
  146. package/dist/src/simple/definePalette.d.ts +26 -0
  147. package/dist/src/simple/definition.d.ts +106 -0
  148. package/dist/src/simple/options.d.ts +33 -0
  149. package/dist/src/simple/source.d.ts +49 -0
  150. package/dist/src/simple/types.d.ts +366 -0
  151. package/dist/src/simple/view.d.ts +107 -0
  152. package/dist/webgpu.js +2 -2
  153. package/package.json +10 -12
  154. package/dist/chunks/GraphSession-BhuHSXIo.js +0 -12819
  155. package/dist/chunks/GraphStyle-Cwr55SAE.js +0 -65
  156. package/dist/chunks/algorithms-BJ6DQMOe.js +0 -3777
  157. package/dist/chunks/detect-fyuVnlCT.js +0 -88
  158. package/dist/chunks/interpolation-DY-PNpqX.js +0 -43
  159. package/dist/chunks/optionsFromZod-CKMYSwTz.js +0 -3636
  160. package/dist/chunks/paletteRegistry-BCFSwJGK.js +0 -1196
  161. package/dist/chunks/parse-BMTqt4SS.js +0 -3658
  162. package/dist/src/data/csv-variant-detection.d.ts +0 -29
  163. package/dist/src/data/ingest.d.ts +0 -104
@@ -0,0 +1,4999 @@
1
+ import { remapArray as st, INVALID_INDEX as g, maskTest as C, GraphBuilder as Sn, makeMask as re, maskSet as En } from "@graphty/graph-format";
2
+ import { fromPositionColumn as In, toPositionColumn as $n } from "@graphty/layout";
3
+ import { z as se } from "zod/v4";
4
+ import { c as Ge, G as m, S as xt } from "./pluginRegistry-Ddfl6Mv2.js";
5
+ import { b as Rn, K as Mn, f as Cn } from "./types-DFchv4Ny.js";
6
+ import { b as _n } from "./GraphtyLogger-BtcBJQPL.js";
7
+ import { Graph as Fn, accelerated as it } from "@graphty/algorithms";
8
+ const ge = Ge({
9
+ kind: "layout",
10
+ idOf: (t) => t.descriptor.id,
11
+ descriptorOf: (t) => t.descriptor,
12
+ implementationOf: (t) => t.descriptor,
13
+ builtInIds: () => Rn
14
+ });
15
+ function Tn(t, e) {
16
+ ge.register(t, e);
17
+ }
18
+ function ai() {
19
+ return ge.descriptors();
20
+ }
21
+ function ci(t) {
22
+ return ge.byId(t);
23
+ }
24
+ function ui() {
25
+ ge.clearForTesting();
26
+ }
27
+ const b = 3, Pn = 1024;
28
+ function V(t, e) {
29
+ if (!Number.isInteger(t) || t < 0)
30
+ throw new RangeError(`ElementPositions: ${e} must be a non-negative integer, found ${String(t)}`);
31
+ return t;
32
+ }
33
+ function P(t) {
34
+ return Number.isFinite(Math.fround(t));
35
+ }
36
+ class zt {
37
+ /**
38
+ * Allocate the backing array, every row unplaced and unpinned.
39
+ * @param capacity - rows to reserve before the first growth; a non-negative integer
40
+ */
41
+ constructor(e = Pn) {
42
+ this.components = b, this.rows = 0, this.moves = 0, V(e, "capacity");
43
+ const n = Math.max(1, e);
44
+ this.array = new Float32Array(b * n), this.array.fill(Number.NaN), this.pins = new Uint8Array(n);
45
+ }
46
+ /**
47
+ * Rows the backing array can hold without reallocating.
48
+ * @returns the current capacity in rows
49
+ */
50
+ get capacity() {
51
+ return this.array.length / b;
52
+ }
53
+ /**
54
+ * Moves whenever coordinates are written on purpose: by {@link ElementPositions.write}, which
55
+ * every layout, drag and placement goes through, and by {@link ElementPositions.moved}, which a
56
+ * writer that fills the array {@link ElementPositions.view} lends (a GPU readback, a restore)
57
+ * calls once per batch. Seeding a new row and renumbering rows do not move it: those follow
58
+ * the graph, not the arrangement. The undo history compares it with the generation of its
59
+ * last capture to tell whether the lane has moved since (design/undo/undo-design.md 6.4).
60
+ * @returns the generation
61
+ */
62
+ get generation() {
63
+ return this.moves;
64
+ }
65
+ /** Say that coordinates were written straight into the lent array. */
66
+ moved() {
67
+ this.moves++;
68
+ }
69
+ /**
70
+ * Rows currently in use. Equals the last snapshot's nodeCount.
71
+ * @returns the live row count
72
+ */
73
+ get count() {
74
+ return this.rows;
75
+ }
76
+ /**
77
+ * How many live rows carry real coordinates, by the same test {@link ElementPositions.isPlaced}
78
+ * applies one row at a time.
79
+ *
80
+ * The question behind it is "did the file that loaded this graph place every node?", which is
81
+ * what decides whether the Keep Positions arrangement can be used at all: a fixed layout over a
82
+ * graph where half the rows are NaN draws half a picture. Compare it against
83
+ * {@link ElementPositions.count} to answer that -- equal means every node has somewhere to go.
84
+ *
85
+ * COUNTED ON EVERY READ, and it has to be. The array is lent to the snapshot as a mutable
86
+ * column, so a layout, a drag and a GPU readback all write coordinates without passing through
87
+ * this class; a counter kept up to date by `write()` would miss every one of those and would be
88
+ * most wrong exactly while a layout was running, which is when somebody is asking. The scan is
89
+ * one f32 read per node and touches only the x lane.
90
+ *
91
+ * This is deliberately NOT on `GraphStatistics`. Those are memoised against the snapshot they
92
+ * were computed from, and how many nodes carry a coordinate changes while a layout runs WITHIN
93
+ * one snapshot, so a cached answer would be stale in the one moment it mattered.
94
+ * @returns how many rows in `[0, count)` carry a storable x
95
+ */
96
+ get placedCount() {
97
+ let e = 0;
98
+ for (let n = 0; n < b * this.rows; n += b)
99
+ this.hasStorableX(n) && e++;
100
+ return e;
101
+ }
102
+ /**
103
+ * The exact view to hand to `snapshot.nodes.set("position", ...)`.
104
+ *
105
+ * Bounded by the LIVE ROW COUNT, like every other row accessor here. `subarray` CLAMPS rather
106
+ * than throwing, so without a check a caller that forgot to `grow()` first would get a short
107
+ * array: E_COLUMN_LENGTH from inside graph-format if it is attached, and a layout that silently
108
+ * places only the first `count` nodes if it is not. Bounding by the CAPACITY instead would hand
109
+ * out a writable window over the spare rows -- rows this class reports unplaced, whose NaN fill
110
+ * every later `grow()` and `remap()` depends on, and whose contents the next growth erases.
111
+ * @param nodeCount - the snapshot's node count
112
+ * @returns a subarray of length `3 * nodeCount` over the same buffer
113
+ * @throws RangeError when `nodeCount` is not a non-negative integer, or exceeds the live count
114
+ */
115
+ view(e) {
116
+ if (V(e, "nodeCount"), e > this.rows)
117
+ throw new RangeError(
118
+ `ElementPositions: view(${e}) needs ${e} live rows but only ${this.rows} exist; call grow(${e}) first`
119
+ );
120
+ return this.array.subarray(0, b * e);
121
+ }
122
+ /**
123
+ * Prefix-stable growth: existing rows keep their coordinates, EVERY row at or above the new
124
+ * count is unplaced -- including the spare capacity, which a later grow() will hand out.
125
+ *
126
+ * Past the capacity this REPLACES the array object; see the staleness contract on the class.
127
+ * @param nodeCount - the new row count; may be smaller than the current one (append-only
128
+ * builders never shrink, but a caller that does gets a truncation, not a throw). `grow(0)`
129
+ * is how a dataset is discarded while the reserve is kept
130
+ * @throws RangeError when `nodeCount` is not a non-negative integer
131
+ */
132
+ grow(e) {
133
+ if (V(e, "nodeCount"), e > this.capacity) {
134
+ const n = Math.max(this.capacity * 2, e), r = new Float32Array(b * n);
135
+ r.set(this.array), r.fill(Number.NaN, b * this.rows), this.array = r;
136
+ const s = new Uint8Array(n);
137
+ s.set(this.pins), s.fill(0, this.rows), this.pins = s;
138
+ } else e > this.rows ? (this.array.fill(Number.NaN, b * this.rows, b * e), this.pins.fill(0, this.rows, e)) : e < this.rows && (this.array.fill(Number.NaN, b * e, b * this.rows), this.pins.fill(0, e, this.rows));
139
+ this.rows = e;
140
+ }
141
+ /**
142
+ * Apply a freeze report's `nodeRemap` (previous index space -> new index or INVALID_INDEX).
143
+ *
144
+ * `remapArray` ALLOCATES, so this replaces the array object and collapses the capacity to
145
+ * exactly `nodeCount` (PLAN DECISION 3: a removal is rare and never per frame, so paying one
146
+ * reallocation on the next growth is cheaper than copying the remapped rows a second time into
147
+ * a re-reserved array). Every holder of the old object is stale afterwards, which is why
148
+ * GraphStore re-attaches the column on every freeze and emits `snapshot-replaced`.
149
+ * @param nodeRemap - the report's nodeRemap
150
+ * @param nodeCount - the new snapshot's node count
151
+ * @throws RangeError when `nodeCount` is not a non-negative integer
152
+ */
153
+ remap(e, n) {
154
+ V(n, "nodeCount"), this.array = st(this.array, e, n, Number.NaN, b), this.pins = st(this.pins, e, n, 0, 1), this.rows = n;
155
+ }
156
+ /**
157
+ * Whether the reader has fixed this row's node in place.
158
+ *
159
+ * A row outside the live count is UNPINNED, never pinned, for the same reason
160
+ * {@link ElementPositions.isPlaced} answers false there: a node with no row is a node the
161
+ * graph builder has not taken, and answering "pinned" for one would freeze a node that does
162
+ * not exist yet and that nothing could release.
163
+ * @param index - node index
164
+ * @returns true when the row is inside the live count AND carries a pin
165
+ */
166
+ isPinned(e) {
167
+ return !Number.isInteger(e) || e < 0 || e >= this.rows ? !1 : this.pins[e] === 1;
168
+ }
169
+ /**
170
+ * Record or release a pin, GROWING the lane to reach the row.
171
+ *
172
+ * It grows rather than throwing for the same reason `LayoutEngine.writeNodePosition` does: a
173
+ * node's index is handed out the moment the graph builder takes its record, but its row only
174
+ * appears when the graph is next frozen, and a reader who drags a node in between would
175
+ * otherwise have the pin thrown away in silence.
176
+ *
177
+ * It REFUSES rather than throwing for an index that is not a row number at all -- the
178
+ * `INVALID_INDEX` a record the builder would not take carries for its whole life, or a
179
+ * negative or fractional number. Pinning happens from a pointer gesture, and a throw on that
180
+ * path takes the frame with it.
181
+ * @param index - node index
182
+ * @param pinned - true to pin, false to release
183
+ * @returns true when the lane was written, false when the index names no row
184
+ */
185
+ setPinned(e, n) {
186
+ return e === g || !Number.isInteger(e) || e < 0 ? !1 : (e >= this.rows && this.grow(e + 1), this.pins[e] = n ? 1 : 0, !0);
187
+ }
188
+ /**
189
+ * How many live rows are pinned.
190
+ * @returns the count of pinned rows in `[0, count)`
191
+ */
192
+ get pinnedCount() {
193
+ let e = 0;
194
+ for (let n = 0; n < this.rows; n++)
195
+ this.pins[n] === 1 && e++;
196
+ return e;
197
+ }
198
+ /**
199
+ * The exact view to hand to `snapshot.nodes.set("graphty.pinned", ...)`.
200
+ *
201
+ * Bounded by the live row count, like {@link ElementPositions.view} and for the same reasons.
202
+ * @param nodeCount - the snapshot's node count
203
+ * @returns a subarray of length `nodeCount` over the same buffer
204
+ * @throws RangeError when `nodeCount` is not a non-negative integer, or exceeds the live count
205
+ */
206
+ pinnedView(e) {
207
+ if (V(e, "nodeCount"), e > this.rows)
208
+ throw new RangeError(
209
+ `ElementPositions: pinnedView(${e}) needs ${e} live rows but only ${this.rows} exist; call grow(${e}) first`
210
+ );
211
+ return this.pins.subarray(0, e);
212
+ }
213
+ /**
214
+ * Report whether a row carries real coordinates.
215
+ *
216
+ * A row outside the live count is UNPLACED, never placed: this predicate is used to decide
217
+ * whether an importer seed may be written, and answering "placed" for a row that does not
218
+ * exist is how a coordinate gets thrown away without an error. So is a row whose x is an
219
+ * infinity, which only a writer that bypassed `write()` -- that is, one writing through the
220
+ * column this array is lent to -- can produce; see the class comment.
221
+ * @param index - node index
222
+ * @returns true when the row is inside the live count AND carries a storable x
223
+ */
224
+ isPlaced(e) {
225
+ return !Number.isInteger(e) || e < 0 || e >= this.rows ? !1 : this.hasStorableX(b * e);
226
+ }
227
+ /**
228
+ * Read one row into a caller-supplied object (14.4 rule 7: never return a shared vector).
229
+ * @param index - node index
230
+ * @param out - the object to fill
231
+ * @param out.x - receives the scene-unit x
232
+ * @param out.y - receives the scene-unit y
233
+ * @param out.z - receives the scene-unit z
234
+ * @throws RangeError when `index` is not an integer in `[0, count)`
235
+ */
236
+ read(e, n) {
237
+ const r = this.rowBase(e);
238
+ n.x = this.array[r] ?? Number.NaN, n.y = this.array[r + 1] ?? Number.NaN, n.z = this.array[r + 2] ?? Number.NaN;
239
+ }
240
+ /**
241
+ * Write one row.
242
+ *
243
+ * This is the ONE choke point every layout, every drag and (from E1) every GPU readback goes
244
+ * through, so it is where an unstorable coordinate is stopped. NaN is this class's unplaced
245
+ * marker: letting one in through here would unplace a placed node from the inside, and an
246
+ * infinity would be stored and then reported placed. The test is `isStorableCoordinate`, NOT
247
+ * `Number.isFinite`, because the array is f32: a finite double of 1e39 passes `isFinite` and
248
+ * lands as Infinity. A caller holding such a coordinate has a bug upstream and must drop the
249
+ * update, not hand it on.
250
+ * @param index - node index
251
+ * @param x - scene-unit x
252
+ * @param y - scene-unit y
253
+ * @param z - scene-unit z
254
+ * @throws RangeError when `index` is not an integer in `[0, count)`. A node added since the
255
+ * last freeze has no row yet: freeze first (which grows this array), then write
256
+ * @throws RangeError when any component is NaN, an infinity, or a double that overflows f32
257
+ */
258
+ write(e, n, r, s) {
259
+ const i = this.rowBase(e);
260
+ if (!P(n) || !P(r) || !P(s))
261
+ throw new RangeError(
262
+ `ElementPositions: row ${String(e)} was written the unstorable coordinate (${String(n)}, ${String(r)}, ${String(s)}); NaN is this class's UNPLACED marker, and an infinity -- including one an f32 overflow produces -- poisons the scene bounds`
263
+ );
264
+ this.array[i] = n, this.array[i + 1] = r, this.array[i + 2] = s, this.moves++;
265
+ }
266
+ /**
267
+ * Write a row ONLY when it is unplaced. This is how importer-seeded coordinates reach a new
268
+ * node without overwriting anything a layout or a drag already produced.
269
+ *
270
+ * `false` means exactly one thing -- the row was ALREADY PLACED, by the same test `isPlaced()`
271
+ * applies. A row that does not exist yet throws instead of returning `false`, so a caller that
272
+ * seeds before growing finds out rather than losing the coordinate.
273
+ * @param index - node index
274
+ * @param x - scene-unit x
275
+ * @param y - scene-unit y
276
+ * @param z - scene-unit z
277
+ * @returns true when the row was written, false when it was already placed
278
+ * @throws RangeError when `index` is not an integer in `[0, count)`
279
+ * @throws RangeError when any component is NaN, an infinity, or a double that overflows f32,
280
+ * through `write()`
281
+ */
282
+ fillUnplaced(e, n, r, s) {
283
+ const i = this.rowBase(e);
284
+ return this.hasStorableX(i) ? !1 : (this.write(e, n, r, s), this.moves--, !0);
285
+ }
286
+ /**
287
+ * Whether the row at this offset carries a storable x, which is the one test "placed" means.
288
+ * @param base - the array offset of the row's x component
289
+ * @returns true when the stored x is neither NaN nor an infinity
290
+ */
291
+ hasStorableX(e) {
292
+ return P(this.array[e] ?? Number.NaN);
293
+ }
294
+ /**
295
+ * The array offset of a live row, rejecting anything else.
296
+ * @param index - node index
297
+ * @returns the offset of the row's x component
298
+ */
299
+ rowBase(e) {
300
+ if (!Number.isInteger(e) || e < 0 || e >= this.rows)
301
+ throw new RangeError(
302
+ e === g ? "ElementPositions: INVALID_INDEX is the graph-format 'no node' sentinel, not a row" : `ElementPositions: row ${String(e)} is outside the live range [0, ${this.rows})`
303
+ );
304
+ return b * e;
305
+ }
306
+ }
307
+ const xn = /* @__PURE__ */ Symbol("graphty.writableLane");
308
+ function Lt(t) {
309
+ if (t === void 0)
310
+ return;
311
+ const e = t[xn];
312
+ if (e !== void 0)
313
+ return e;
314
+ const n = t.positions;
315
+ return n instanceof zt ? n : void 0;
316
+ }
317
+ function zn(t) {
318
+ return {
319
+ get capacity() {
320
+ return t().capacity;
321
+ },
322
+ get count() {
323
+ return t().count;
324
+ },
325
+ get placedCount() {
326
+ return t().placedCount;
327
+ },
328
+ get pinnedCount() {
329
+ return t().pinnedCount;
330
+ },
331
+ get generation() {
332
+ return t().generation;
333
+ },
334
+ isPlaced: (e) => t().isPlaced(e),
335
+ isPinned: (e) => t().isPinned(e),
336
+ read: (e, n) => {
337
+ t().read(e, n);
338
+ }
339
+ };
340
+ }
341
+ const M = new xt("layout"), Ln = Object.freeze([
342
+ "arf",
343
+ "bfs",
344
+ "bipartite",
345
+ "circular",
346
+ "d3",
347
+ "fixed",
348
+ "forceatlas2",
349
+ "grid",
350
+ "kamada-kawai",
351
+ "multipartite",
352
+ "ngraph",
353
+ "planar",
354
+ "radial",
355
+ "random",
356
+ "shell",
357
+ "spectral",
358
+ "spiral",
359
+ "spring",
360
+ "spring-electrical"
361
+ ]), Dn = 10;
362
+ function ot(t) {
363
+ return new m({
364
+ code: "E_DUPLICATE_PLUGIN",
365
+ message: `"${t}" is a layout engine the element ships, and a built-in name may not be taken: a saved document that named it yesterday has to mean the same thing today`,
366
+ source: "registry",
367
+ details: { kind: "layout", name: t, builtIn: !0 }
368
+ });
369
+ }
370
+ const S = {};
371
+ function jn(t, e) {
372
+ const n = [], r = /* @__PURE__ */ new Set();
373
+ for (const s of t)
374
+ r.has(s) && n.push(`edge ${s.id} is held twice`), r.add(s), e.get(s.id) !== s && n.push(`edge ${s.id} is held but not drawn`);
375
+ for (const s of e.values())
376
+ r.has(s) || n.push(`edge ${s.id} is drawn but not held`);
377
+ return n;
378
+ }
379
+ const pe = class pe {
380
+ constructor() {
381
+ this.positionArrayAttached = !1, this.hold = null, this.holdRows = 0, this.readonlyPositionArray = zn(() => this.writablePositions);
382
+ }
383
+ /**
384
+ * Add multiple nodes to the layout engine
385
+ * @param nodes - Array of nodes to add
386
+ */
387
+ addNodes(e) {
388
+ for (const n of e)
389
+ this.addNode(n);
390
+ }
391
+ /**
392
+ * Add multiple edges to the layout engine
393
+ * @param edges - Array of edges to add
394
+ */
395
+ addEdges(e) {
396
+ for (const n of e)
397
+ this.addEdge(n);
398
+ }
399
+ /**
400
+ * Take a node out of the layout, before the element disposes the mesh that drew it.
401
+ *
402
+ * Declared here, with a default that does nothing, because it used to be duck-typed by the
403
+ * element's data manager and implemented by none of the nineteen engines that ship here: an
404
+ * author learned it existed by reading the element's source, and got no worked example. An
405
+ * engine that keeps its own node list must override this, or it holds every removed node --
406
+ * and everything that node references -- for as long as the engine lives.
407
+ * @param _n - the node leaving the graph
408
+ */
409
+ removeNode(e) {
410
+ }
411
+ /**
412
+ * The edge half of {@link LayoutEngine.removeNode}, with the same default and the same reason.
413
+ * @param _e - the edge leaving the graph
414
+ */
415
+ removeEdge(e) {
416
+ }
417
+ /**
418
+ * Settle nodes that reached the graph after this layout was already running.
419
+ *
420
+ * THE DEFAULT IS THE ELEMENT'S OWN FALLBACK -- up to ten steps, stopping early if the engine
421
+ * settles -- so a simulation behaves exactly as it did before the hook was declared, and an
422
+ * engine that can place a newcomer without re-running the whole simulation overrides it. It
423
+ * lives on the base class rather than in the manager because the manager cannot tell "did not
424
+ * implement it" from "implemented it as a deliberate no-op", and the difference decides
425
+ * whether ten steps run.
426
+ * @param _nodes - the nodes that have just arrived
427
+ */
428
+ updatePositions(e) {
429
+ for (let n = 0; n < Dn; n++) {
430
+ if (this.isSettled)
431
+ return;
432
+ this.step();
433
+ }
434
+ }
435
+ /**
436
+ * Release whatever this engine holds. The element calls it when the reader switches layouts
437
+ * and when the graph is torn down, and never uses the engine again afterwards.
438
+ *
439
+ * Declared with a do-nothing default for the same reason as `removeNode`:
440
+ * it was duck-typed, undeclared and unimplemented by every engine here.
441
+ */
442
+ dispose() {
443
+ }
444
+ /**
445
+ * Strict state: what is wrong with this engine's hold on the drawn edges, checked after every
446
+ * derivation pass. An engine that keeps a copy of the edges must hold every drawn edge once
447
+ * and nothing else, or a redraw asks it for a position it cannot give. Reads nothing lazily:
448
+ * the check must not change what it checks.
449
+ * @param drawn - The edges the element draws.
450
+ * @returns One sentence per problem; empty when there is none.
451
+ */
452
+ edgeProblems(e) {
453
+ return jn(this.edges, e);
454
+ }
455
+ /**
456
+ * The coordinates this engine publishes, read-only.
457
+ *
458
+ * Read-only because the array is the element's: a write here would move or pin a node with no
459
+ * undo step. The engine writes through `writeNodePosition`; a consumer
460
+ * places and pins nodes through `session.positions`.
461
+ * @returns the coordinates in use, read-only
462
+ */
463
+ get nodePositions() {
464
+ return this.readonlyPositionArray;
465
+ }
466
+ /**
467
+ * The array this engine publishes node coordinates into, writable.
468
+ *
469
+ * Allocated on demand, so reading it is enough to make an engine that has never been handed an
470
+ * element's array produce one of its own. The element reaches it through
471
+ * {@link layoutEngineInternals}.
472
+ * @returns the position array in use
473
+ */
474
+ get writablePositions() {
475
+ return this.positionArray ??= new zt(0), this.positionArray;
476
+ }
477
+ /**
478
+ * Hand this engine the array it must publish into, and stop it adopting any other.
479
+ *
480
+ * This is how a host says "these coordinates are mine": the engine writes into the array the
481
+ * host already lends to its snapshots, so a layout, a drag and a GPU readback all land in the
482
+ * one place and a re-freeze loses none of them.
483
+ * @param positions - the element-owned array
484
+ */
485
+ attachPositions(e) {
486
+ this.positionArray = e, this.positionArrayAttached = !0;
487
+ }
488
+ /**
489
+ * Hold the nodes a scoped layout may not move, or release them all with null.
490
+ *
491
+ * The element calls this on an engine whose class declares `static scoped = true`, after
492
+ * `init()` and after every renumbering of the graph. A set bit is a held row. A row at or past
493
+ * `rows` belongs to a node that arrived after the scope was captured, and is held too: the
494
+ * members of a scoped layout are the ones it started with. An engine that overrides this calls
495
+ * `super.setHoldMask` first and then fixes held nodes in its own state (see
496
+ * {@link LayoutEngineStatics.scoped}).
497
+ * @param mask - One bit per row, set for a row to hold; null holds nothing.
498
+ * @param rows - How many rows the mask covers.
499
+ */
500
+ setHoldMask(e, n) {
501
+ this.hold = e, this.holdRows = e === null ? 0 : n;
502
+ }
503
+ /**
504
+ * The hold mask the element last handed this engine, or null when nothing is held.
505
+ * @returns The mask, which the caller must not change.
506
+ */
507
+ get holdMask() {
508
+ return this.hold;
509
+ }
510
+ /**
511
+ * Whether the element is holding this row still for a scoped layout.
512
+ * @param index - The node's row, or `INVALID_INDEX`.
513
+ * @returns True while a hold is set and the row is held or newer than the hold.
514
+ */
515
+ isHeld(e) {
516
+ const { hold: n } = this;
517
+ return n === null ? !1 : e >= this.holdRows || !Number.isInteger(e) || e < 0 || C(n, e);
518
+ }
519
+ /**
520
+ * Copy every node's current coordinates out of the engine and into the position array.
521
+ *
522
+ * Engines call this at the end of a step, so that by the time anything draws, the array is the
523
+ * answer rather than a copy of it. The default walks the engine's own nodes through
524
+ * {@link LayoutEngine.getNodePosition}, which is correct for any engine but allocates one
525
+ * object per node; an engine that can read its own state without allocating overrides it, and
526
+ * an engine that already writes straight into the array overrides it to do nothing.
527
+ */
528
+ publishPositions() {
529
+ for (const e of this.nodes) {
530
+ const n = this.getNodePosition(e);
531
+ this.writeNodePosition(e, n.x, n.y, n.z ?? 0);
532
+ }
533
+ }
534
+ /**
535
+ * Take the coordinates in the position array as this engine's own, and stay at rest.
536
+ *
537
+ * Undo and redo write where the nodes were into the array and then call this, so the next
538
+ * drag, add or `setRunning(true)` starts from the restored arrangement instead of the one the
539
+ * engine was holding. The default hands every placed node back through
540
+ * `setNodePosition`, which is right for any engine that keeps coordinates of
541
+ * its own; an engine that can adopt the array in one pass overrides it.
542
+ */
543
+ loadArrangement() {
544
+ const e = { x: 0, y: 0, z: 0 };
545
+ for (const n of this.nodes)
546
+ this.readNodePosition(n, e) && this.setNodePosition(n, e);
547
+ }
548
+ /**
549
+ * Read a node's published coordinates into an object the CALLER owns.
550
+ *
551
+ * The point of the out parameter is that a renderer can pass the vector it is about to draw
552
+ * with and allocate nothing per node per frame. A row that no engine has placed answers false
553
+ * and leaves `out` untouched, so the caller keeps whatever it had rather than being handed a
554
+ * NaN or an origin it cannot tell from a real coordinate.
555
+ * @param n - the node to read
556
+ * @param out - the object to fill; a Babylon `Vector3` is one, which is the point
557
+ * @param out.x - receives the scene-unit x
558
+ * @param out.y - receives the scene-unit y
559
+ * @param out.z - receives the scene-unit z
560
+ * @returns true when the node has a placed row
561
+ */
562
+ readNodePosition(e, n) {
563
+ const r = this.positionsFor(e);
564
+ return r.isPlaced(e.index) ? (r.read(e.index, n), !0) : !1;
565
+ }
566
+ /**
567
+ * Publish one node's coordinates, growing the array to reach its row.
568
+ *
569
+ * Three things are silently skipped rather than thrown, because this runs inside a layout step
570
+ * and a throw there kills the frame: a node with no row in the graph (`INVALID_INDEX`, which a
571
+ * record whose id the graph builder would not take carries for its whole life), a node whose
572
+ * index is not a row number at all, and a coordinate that cannot be stored. That last one is
573
+ * the important one -- a force layout that divided by a zero distance produces NaN, and an
574
+ * overflow of the f32 the array stores produces an infinity. Either one, written, would make
575
+ * the row read back as a place: the mesh vanishes and the scene bounds and camera framing go
576
+ * with it. Left alone, the row stays unplaced and the node keeps the coordinates it had.
577
+ *
578
+ * The array is GROWN to reach the row rather than the write being refused. A node's index is
579
+ * handed out the moment its record is taken, but its row only appears when the graph is next
580
+ * frozen, and a layout that ran in between would otherwise be thrown away in silence. Growth is
581
+ * prefix-stable and fills what it adds with NaN, so it cannot disturb a row anything else
582
+ * placed; the one thing it does change is that a node this engine placed before the first
583
+ * freeze counts as placed, which is what makes a file's own coordinates yield to it.
584
+ *
585
+ * A PINNED ROW REFUSES A LAYOUT STEP. This is the whole of "a pin is meaningful under every
586
+ * arrangement": fourteen of the element's nineteen engines implement `pin()` as a no-op and
587
+ * `setNodePosition` as a no-op too, so before this guard a reader who dragged a node under a
588
+ * static layout watched it snap back the next time the layout recomputed. One refusal here
589
+ * covers every engine, including one written by a third party that has never heard of pinning,
590
+ * because every engine reaches the shared array through this method.
591
+ *
592
+ * A DRAG IS NOT A LAYOUT STEP. `intent: "placement"` writes straight through, so a reader can
593
+ * move a pinned node and have it stay where they put it; without that distinction the guard
594
+ * would make a pinned node undraggable, which is the opposite of what a pin is for. The
595
+ * default is `"layout"` so that an engine written before the parameter existed -- a plugin's
596
+ * step loop -- is guarded without knowing it, and only the placement paths have to opt out.
597
+ * @param n - the node being placed
598
+ * @param x - scene-unit x
599
+ * @param y - scene-unit y
600
+ * @param z - scene-unit z
601
+ * @param intent - `"layout"` for a simulation step, `"placement"` for a drag or a replay
602
+ * @returns true when the row was written
603
+ */
604
+ writeNodePosition(e, n, r, s, i = "layout") {
605
+ const { index: o } = e;
606
+ if (o === g || !Number.isInteger(o) || o < 0 || !P(n) || !P(r) || !P(s))
607
+ return !1;
608
+ const a = this.positionsFor(e);
609
+ return i === "layout" && (a.isPinned(o) || this.isHeld(o) && a.isPlaced(o)) ? !1 : (o >= a.count && a.grow(o + 1), a.write(o, n, r, s), !0);
610
+ }
611
+ /**
612
+ * The array to use for this node: the one its own graph owns, unless a host attached one.
613
+ *
614
+ * Resolved on every call rather than cached, because the element REPLACES its array when a
615
+ * dataset is discarded -- the store and everything keyed into it is thrown away and rebuilt --
616
+ * and an engine outlives that. A cached reference would keep publishing into the array of a
617
+ * graph that no longer exists, which is invisible: every write succeeds and nothing draws.
618
+ * @param n - the node being published or read
619
+ * @returns the array to write to and read from
620
+ */
621
+ positionsFor(e) {
622
+ if (!this.positionArrayAttached) {
623
+ const n = Lt(e.parentGraph?.getDataManager?.());
624
+ n !== void 0 && (this.positionArray = n);
625
+ }
626
+ return this.writablePositions;
627
+ }
628
+ /**
629
+ * Get the type identifier for this layout engine
630
+ * @returns The layout engine type string
631
+ */
632
+ get type() {
633
+ return this.constructor.type;
634
+ }
635
+ /**
636
+ * File a layout engine class under the name it declares, and publish what it says about
637
+ * itself to the catalogue.
638
+ *
639
+ * WHAT CHANGED AND WHY. This used to read `cls.type` through a cast and put the class in a
640
+ * map, which meant a class with no `static type` registered under the string "undefined", a
641
+ * second class under a taken name silently replaced the first, and a registered engine
642
+ * reached no catalogue at all -- so a third party's layout could run but could never be
643
+ * offered by a picker, described in a reader's language, or found by `layoutIdForEngine`.
644
+ *
645
+ * A third party's class must declare a `static descriptor` whose `id` equals its
646
+ * `static type`. The element's own nineteen are the one exemption, because their arrangements
647
+ * are authored centrally in the layout catalogue where several engines may sit behind one
648
+ * public name.
649
+ * @param cls - The layout engine class.
650
+ * @param options - How to register it; `strict` refuses a different layout under a taken id.
651
+ * @returns The same class, so a declaration can register itself in one expression.
652
+ * @throws A `GraphtyError` with `E_BAD_COMMAND` when the class declares no `static type`, no
653
+ * `static descriptor`, or a descriptor whose `id` disagrees with its `static type`; or with
654
+ * `E_DUPLICATE_PLUGIN` when the name or the descriptor id is one the element itself ships.
655
+ */
656
+ static register(e, n) {
657
+ const r = e, { type: s, descriptor: i } = r;
658
+ if (typeof s != "string" || s === "")
659
+ throw new m({
660
+ code: "E_BAD_COMMAND",
661
+ message: "a layout engine is filed under its `static type`, and this class declares none",
662
+ source: "registry",
663
+ details: { kind: "layout", field: "type" }
664
+ });
665
+ if (M.get(s) === e)
666
+ return e;
667
+ const o = Ln.includes(s);
668
+ if (i === void 0) {
669
+ if (!o)
670
+ throw new m({
671
+ code: "E_BAD_COMMAND",
672
+ message: `the layout "${s}" declares no \`static descriptor\`, so nothing could offer it: a picker reads the catalogue, and an engine the catalogue does not carry is reachable only by a consumer who already knows its name`,
673
+ source: "registry",
674
+ details: { kind: "layout", name: s, field: "descriptor" }
675
+ });
676
+ if (M.hasOwn(s))
677
+ throw ot(s);
678
+ return M.set(s, e), e;
679
+ }
680
+ if (o)
681
+ throw ot(s);
682
+ if (i.id !== s)
683
+ throw new m({
684
+ code: "E_BAD_COMMAND",
685
+ message: `the layout "${s}" describes itself as "${i.id}". A layout has ONE key: the name \`setLayout\` takes and the name the catalogue publishes are the same string, so nothing has to be named twice and a saved document means one thing`,
686
+ source: "registry",
687
+ details: { kind: "layout", name: s, field: "descriptor.id", id: i.id }
688
+ });
689
+ return Tn(
690
+ {
691
+ descriptor: {
692
+ ...i,
693
+ honoursWeights: r.honoursWeights ?? !1,
694
+ scoped: r.scoped ?? !1
695
+ },
696
+ type: s
697
+ },
698
+ n
699
+ ), M.set(s, e), e;
700
+ }
701
+ /**
702
+ * Get a layout engine instance by type
703
+ * @param type - The layout engine type identifier
704
+ * @param opts - Configuration options for the layout engine
705
+ * @returns A new layout engine instance or null if type not found
706
+ */
707
+ static get(e, n = {}) {
708
+ const r = M.get(e);
709
+ return r ? new r(n) : null;
710
+ }
711
+ /**
712
+ * Get dimension-specific options for this layout
713
+ * @param dimension - The desired dimension (2 or 3)
714
+ * @returns Options object for the dimension or null if unsupported
715
+ */
716
+ static getOptionsForDimension(e) {
717
+ return e > this.maxDimensions ? null : {};
718
+ }
719
+ /**
720
+ * Get dimension-specific options for a layout by type
721
+ * @param type - The layout engine type identifier
722
+ * @param dimension - The desired dimension (2 or 3)
723
+ * @returns Options object for the dimension or null if type not found or unsupported
724
+ */
725
+ static getOptionsForDimensionByType(e, n) {
726
+ const r = M.get(e);
727
+ return r ? r.getOptionsForDimension(n) : null;
728
+ }
729
+ /**
730
+ * Get the Zod-based options schema for this layout
731
+ * @returns The options schema, or an empty object if no schema defined
732
+ */
733
+ static getZodOptionsSchema() {
734
+ return this.zodOptionsSchema ?? {};
735
+ }
736
+ /**
737
+ * Check if this layout has a Zod-based options schema
738
+ * @returns true if the layout has options defined
739
+ */
740
+ static hasZodOptions() {
741
+ return this.zodOptionsSchema !== void 0 && Object.keys(this.zodOptionsSchema).length > 0;
742
+ }
743
+ /**
744
+ * Get a list of all registered layout types
745
+ * @returns Array of registered layout type identifiers
746
+ */
747
+ static getRegisteredTypes() {
748
+ return Array.from(M.keys());
749
+ }
750
+ /**
751
+ * Get a layout class by type
752
+ * @param type - The layout engine type identifier
753
+ * @returns The layout engine class or null if not found
754
+ */
755
+ static getClass(e) {
756
+ return M.get(e) ?? null;
757
+ }
758
+ };
759
+ S.setNodePosition = (e, n, r) => {
760
+ e.setNodePosition(n, r);
761
+ }, S.pin = (e, n) => {
762
+ e.pin(n);
763
+ }, S.unpin = (e, n) => {
764
+ e.unpin(n);
765
+ }, S.positions = (e) => e.writablePositions, S.edgeProblems = (e, n) => e.edgeProblems(n), S.addNode = (e, n) => {
766
+ e.addNode(n);
767
+ }, S.addEdge = (e, n) => {
768
+ e.addEdge(n);
769
+ }, S.addNodes = (e, n) => {
770
+ e.addNodes(n);
771
+ }, S.addEdges = (e, n) => {
772
+ e.addEdges(n);
773
+ }, S.removeNode = (e, n) => {
774
+ e.removeNode(n);
775
+ }, S.removeEdge = (e, n) => {
776
+ e.removeEdge(n);
777
+ }, S.attachPositions = (e, n) => {
778
+ e.attachPositions(n);
779
+ }, pe.honoursWeights = !1, pe.scoped = !1;
780
+ let Se = pe;
781
+ const Un = se.looseObject({
782
+ scalingFactor: se.number().default(100)
783
+ });
784
+ function Hn(t) {
785
+ const { previous: e, next: n, report: r } = t;
786
+ if (e === null || n.nodeCount <= e.nodeCount)
787
+ return null;
788
+ const s = re(n.nodeCount), i = r.nodeRemap;
789
+ for (let c = 0; c < e.nodeCount; c++) {
790
+ const l = i === null ? c : i[c];
791
+ if (l === g)
792
+ return null;
793
+ En(s, l, !0);
794
+ }
795
+ const { src: o, dst: a } = n.edgeList();
796
+ let u = 0;
797
+ for (let c = 0; c < n.edgeCount; c++)
798
+ C(s, o[c]) && C(s, a[c]) && u++;
799
+ return u === e.edgeCount ? s : null;
800
+ }
801
+ class li extends Se {
802
+ /**
803
+ * Create a simple layout engine
804
+ * @param opts - Configuration options including scalingFactor
805
+ */
806
+ constructor(e = {}) {
807
+ super(), this._nodes = [], this._edges = [], this.stale = !0, this.positions = {}, this.result = null, this.scalingFactor = 100, this.#e = null, this.#t = new Float32Array(0), this.#r = null, this.#n = null, this.isSettled = !0;
808
+ const n = Un.parse(e);
809
+ this.scalingFactor = n.scalingFactor;
810
+ }
811
+ #e;
812
+ #t;
813
+ #r;
814
+ #n;
815
+ /**
816
+ * Get dimension-specific options for simple layouts
817
+ * @param dimension - The desired dimension (2 or 3)
818
+ * @returns Options object with dim parameter or null if unsupported
819
+ */
820
+ static getOptionsForDimension(e) {
821
+ return e > this.maxDimensions ? null : { dim: e };
822
+ }
823
+ // basic functionality
824
+ /**
825
+ * Initialize the layout engine
826
+ *
827
+ * Simple layouts compute positions synchronously and don't require initialization.
828
+ */
829
+ async init() {
830
+ }
831
+ /**
832
+ * Add a node to the layout and mark positions as stale
833
+ * @param n - The node to add
834
+ */
835
+ addNode(e) {
836
+ this._nodes.push(e), this.stale = !0;
837
+ }
838
+ /**
839
+ * Add an edge to the layout and mark positions as stale
840
+ * @param e - The edge to add
841
+ */
842
+ addEdge(e) {
843
+ this._edges.push(e), this.stale = !0;
844
+ }
845
+ /**
846
+ * The graph this run arranges: the element's undirected snapshot, or, for an engine driven
847
+ * without an element, a graph built from the nodes and edges it was handed, in that order.
848
+ *
849
+ * Read it in `doLayout`. Reading it may freeze the element's graph, which is how a node added
850
+ * since the last run gets a row.
851
+ * @returns the undirected graph
852
+ */
853
+ get graph() {
854
+ return this.#e ??= this.#s(), this.#e.snapshot;
855
+ }
856
+ /**
857
+ * The coordinates to start this run from, in layout units, `dim` values per row of
858
+ * the protected `graph`: the element's current coordinates when the run follows an
859
+ * add, otherwise null. An unplaced row is NaN.
860
+ * @param dim - components per row
861
+ * @returns the start rows, or null
862
+ */
863
+ startPositions(e) {
864
+ const { snapshot: n, positions: r } = this.#e ?? this.#s();
865
+ return this.#n === null || r === null ? null : In(r.view(n.nodeCount), e, this.scalingFactor, null);
866
+ }
867
+ /**
868
+ * The row of a node named in an option, in the protected `graph`.
869
+ *
870
+ * A key of an options record is always a string, so a string that misses is tried again as the
871
+ * number it spells: `{ 1: [...] }` names the node whose id is the number 1.
872
+ * @param id - the node id, or a record key naming one
873
+ * @returns the row, or `INVALID_INDEX` when the graph has no such node
874
+ */
875
+ rowOfId(e) {
876
+ const { ids: n } = this.graph, r = n.indexOf(e);
877
+ return r === g && typeof e == "string" && e.trim() !== "" ? n.indexOf(Number(e)) : r;
878
+ }
879
+ /**
880
+ * {@link SimpleLayoutEngine.rowOfId} for an option that must name a node.
881
+ * @param id - the node id
882
+ * @param what - what the option names, for the message
883
+ * @returns the row
884
+ * @throws when the graph has no such node
885
+ */
886
+ requireRow(e, n) {
887
+ const r = this.rowOfId(e);
888
+ if (r === g)
889
+ throw new Error(`${n} node ${String(e)} is not in the graph`);
890
+ return r;
891
+ }
892
+ /**
893
+ * Rows of an option that gives coordinates by node id, `dim` values per row of
894
+ * the protected `graph`; a node the record does not give is NaN.
895
+ * @param record - the coordinates by node id, in layout units, or null
896
+ * @param dim - components per row
897
+ * @returns the rows, or null for no record
898
+ */
899
+ rowsOfRecord(e, n) {
900
+ if (e === null)
901
+ return null;
902
+ const r = new Float32Array(n * this.graph.nodeCount).fill(Number.NaN);
903
+ for (const [s, i] of Object.entries(e)) {
904
+ const o = this.rowOfId(s);
905
+ if (o !== g)
906
+ for (let a = 0; a < n; a++)
907
+ r[n * o + a] = i[a] ?? 0;
908
+ }
909
+ return r;
910
+ }
911
+ /**
912
+ * Hear that the element's graph was frozen again.
913
+ *
914
+ * The layout is re-run at the next read. When the freeze only added to the graph this engine
915
+ * last arranged, and the data is not still loading, the re-run keeps every existing node where
916
+ * it is (see the class comment). A load is excluded because its chunks are one graph arriving,
917
+ * not a reader adding to a finished one: a circle whose first chunk was held would be drawn as
918
+ * two overlapping circles.
919
+ * @param change - the freeze
920
+ * @param loading - whether a load is still streaming records in
921
+ */
922
+ reload(e, n) {
923
+ this.stale = !0, this.#n = !n && this.#r !== null && this.#r === e.previous ? Hn(e) : null;
924
+ }
925
+ /**
926
+ * Get the position of a node, computing layout if stale
927
+ *
928
+ * The coordinates come from the shared position array, rounded to the f32 it stores. A node
929
+ * with no row there falls back to what the engine computed, which is every node in an engine
930
+ * driven by hand.
931
+ * @param n - The node to get position for
932
+ * @returns The node's position coordinates
933
+ */
934
+ getNodePosition(e) {
935
+ return this.refresh(), this.publishedOr(e);
936
+ }
937
+ /**
938
+ * Record where the reader has just put a node.
939
+ *
940
+ * A static layout has no per-node state a placement could live in, so the placement is
941
+ * written into the SHARED array, with `"placement"` intent so that it lands even on a pinned
942
+ * row, and into what the engine computed, so that the next publish of the same answer does
943
+ * not put the node back.
944
+ * @param n - the node that moved
945
+ * @param p - where it moved to
946
+ */
947
+ setNodePosition(e, n) {
948
+ const r = n.z ?? 0;
949
+ this.writeNodePosition(e, n.x, n.y, r, "placement"), this.positions[e.id] = [n.x / this.scalingFactor, n.y / this.scalingFactor, r / this.scalingFactor];
950
+ const s = this.#e?.rowOf(e) ?? g;
951
+ s !== g && 3 * s + 2 < this.#t.length && (this.#t[3 * s] = n.x, this.#t[3 * s + 1] = n.y, this.#t[3 * s + 2] = r);
952
+ }
953
+ /**
954
+ * Get the position of an edge based on its endpoints
955
+ * @param e - The edge to get position for
956
+ * @returns The edge's source and destination positions
957
+ */
958
+ getEdgePosition(e) {
959
+ return this.refresh(), {
960
+ src: this.publishedOr(e.srcNode),
961
+ dst: this.publishedOr(e.dstNode)
962
+ };
963
+ }
964
+ /**
965
+ * Copy the computed layout into the shared position array, recomputing it first if it is stale.
966
+ */
967
+ publishPositions() {
968
+ if (this.stale) {
969
+ this.refresh();
970
+ return;
971
+ }
972
+ this.publishComputed();
973
+ }
974
+ // for animated layouts
975
+ /**
976
+ * Step the layout animation
977
+ *
978
+ * Simple layouts are static and don't animate, so stepping has no effect.
979
+ */
980
+ step() {
981
+ }
982
+ /**
983
+ * Take a node out of the layout.
984
+ *
985
+ * WITHOUT THIS the engine holds the removed node -- and through it the node's Babylon mesh,
986
+ * its data record and its endpoints -- for as long as the engine lives, and the frame loop
987
+ * keeps walking it, so a node the reader deleted still draws at wherever it last was. The
988
+ * layout is marked stale, so the next read recomputes it without the node.
989
+ * @param n - the node leaving the graph
990
+ */
991
+ removeNode(e) {
992
+ const n = this._nodes.indexOf(e);
993
+ n >= 0 && this._nodes.splice(n, 1), this.stale = !0;
994
+ }
995
+ /**
996
+ * The edge half of {@link SimpleLayoutEngine.removeNode}, with the same reason.
997
+ * @param e - the edge leaving the graph
998
+ */
999
+ removeEdge(e) {
1000
+ const n = this._edges.indexOf(e);
1001
+ n >= 0 && this._edges.splice(n, 1), this.stale = !0;
1002
+ }
1003
+ /**
1004
+ * Pin a node in place
1005
+ *
1006
+ * A static layout has nothing of its own to hold still -- it recomputes every position from
1007
+ * scratch -- so the pin is kept by the element's position array instead, and
1008
+ * `writeNodePosition` refuses to move a pinned row.
1009
+ */
1010
+ pin() {
1011
+ }
1012
+ /**
1013
+ * Unpin a node
1014
+ *
1015
+ * The element's position array holds the pin; see {@link SimpleLayoutEngine.pin}.
1016
+ */
1017
+ unpin() {
1018
+ }
1019
+ /**
1020
+ * Keep the arrangement in the array instead of recomputing one: a static layout that was
1021
+ * marked stale by the graph change an undo made would otherwise lay the graph out afresh at
1022
+ * the next read and write over what was restored.
1023
+ */
1024
+ loadArrangement() {
1025
+ this.stale = !1, super.loadArrangement();
1026
+ }
1027
+ // properties
1028
+ /**
1029
+ * Get all nodes in the layout
1030
+ * @returns Iterable of nodes
1031
+ */
1032
+ get nodes() {
1033
+ return this._nodes;
1034
+ }
1035
+ /**
1036
+ * Get all edges in the layout
1037
+ * @returns Iterable of edges
1038
+ */
1039
+ get edges() {
1040
+ return this._edges;
1041
+ }
1042
+ /**
1043
+ * Recompute the layout when it is stale, and publish what it produced.
1044
+ *
1045
+ * A simple layout is computed once and then held, so this is the ONE place the shared array is
1046
+ * filled: every reader below goes through here first, which is why a node added after the last
1047
+ * read still gets a row before anything asks for its coordinates.
1048
+ */
1049
+ refresh() {
1050
+ if (!this.stale)
1051
+ return;
1052
+ if (this.#e = null, this.result = null, this._nodes.length === 0) {
1053
+ this.stale = !1, this.#t = new Float32Array(0);
1054
+ return;
1055
+ }
1056
+ this.doLayout(), this.stale = !1;
1057
+ const e = this.#e;
1058
+ this.#t = this.result === null || e === null ? new Float32Array(0) : $n(this.result, this.scalingFactor, null), this.#r = e?.source ?? null;
1059
+ const n = this.#n;
1060
+ if (this.#n = null, n !== null)
1061
+ for (let r = 0; r < this.#t.length / 3; r++)
1062
+ C(n, r) && this.#t.fill(Number.NaN, 3 * r, 3 * r + 3);
1063
+ this.publishComputed();
1064
+ }
1065
+ /**
1066
+ * Read the graph this run arranges. See the protected `graph`.
1067
+ * @returns the loaded graph
1068
+ */
1069
+ #s() {
1070
+ const e = this._nodes[0]?.parentGraph?.getDataManager?.(), n = e;
1071
+ if (typeof n?.getSnapshot == "function" && typeof n.undirected == "function") {
1072
+ const i = n.getSnapshot(), { snapshot: o } = n.undirected(i);
1073
+ return {
1074
+ snapshot: o,
1075
+ source: i,
1076
+ positions: Lt(e) ?? null,
1077
+ rowOf: (a) => a.index < o.nodeCount ? a.index : g
1078
+ };
1079
+ }
1080
+ const r = new Sn({ directed: !1, addMissingNodes: !0 });
1081
+ for (const i of this._nodes)
1082
+ r.addNode(i.id);
1083
+ for (const i of this._edges)
1084
+ r.addEdge(i.srcId, i.dstId);
1085
+ const s = r.freeze({ label: "static-layout" });
1086
+ return { snapshot: s, source: null, positions: null, rowOf: (i) => s.ids.indexOf(i.id) };
1087
+ }
1088
+ /**
1089
+ * Write the computed answer into the shared array, scaled to scene units.
1090
+ *
1091
+ * A node the layout left unplaced (a NaN row, or no entry in `positions`) is LEFT UNPLACED
1092
+ * rather than published at the origin: the two are indistinguishable once stored, and the
1093
+ * origin is a place a reader would draw at.
1094
+ */
1095
+ publishComputed() {
1096
+ const e = this.#e, n = this.#t;
1097
+ for (const r of this._nodes) {
1098
+ if (e !== null && n.length > 0) {
1099
+ const i = e.rowOf(r);
1100
+ i !== g && 3 * i + 2 < n.length && this.writeNodePosition(r, n[3 * i], n[3 * i + 1], n[3 * i + 2]);
1101
+ continue;
1102
+ }
1103
+ const s = this.positions[r.id];
1104
+ !s || s.length === 0 || this.writeNodePosition(
1105
+ r,
1106
+ s[0] * this.scalingFactor,
1107
+ s[1] * this.scalingFactor,
1108
+ (s[2] ?? 0) * this.scalingFactor
1109
+ );
1110
+ }
1111
+ }
1112
+ /**
1113
+ * A node's published row, or what the engine computed when it has no row of its own.
1114
+ *
1115
+ * The fallback is not a rare path: an engine driven directly -- by a test, or by a host that
1116
+ * keeps no graph -- has nodes whose index is `INVALID_INDEX`, and none of them is ever
1117
+ * published. Both branches produce the same arrangement; only the rounding differs.
1118
+ * @param n - the node, when the caller has one
1119
+ * @returns a fresh coordinate triple; the origin for a node nothing placed
1120
+ */
1121
+ publishedOr(e) {
1122
+ const n = { x: 0, y: 0, z: 0 };
1123
+ if (e === void 0 || this.readNodePosition(e, n))
1124
+ return n;
1125
+ const r = this.#e?.rowOf(e) ?? g, s = this.#t;
1126
+ if (r !== g && 3 * r + 2 < s.length && !Number.isNaN(s[3 * r]))
1127
+ return { x: s[3 * r], y: s[3 * r + 1], z: s[3 * r + 2] };
1128
+ const i = this.positions[e.id];
1129
+ return !i || i.length === 0 ? n : {
1130
+ x: i[0] * this.scalingFactor,
1131
+ y: i[1] * this.scalingFactor,
1132
+ z: (i[2] ?? 0) * this.scalingFactor
1133
+ };
1134
+ }
1135
+ }
1136
+ function di(t) {
1137
+ return t === 3 ? 3 : 2;
1138
+ }
1139
+ const Bn = ["forceAtlas2", "fruchtermanReingold", "springElectrical", "release"], Dt = [
1140
+ "pageRank",
1141
+ "sssp",
1142
+ "breadthFirstSearch",
1143
+ "connectedComponents",
1144
+ "weaklyConnectedComponents",
1145
+ "minimumSpanningTree",
1146
+ "hits",
1147
+ "katzCentrality",
1148
+ "eigenvectorCentrality"
1149
+ ];
1150
+ function at(t) {
1151
+ return Dt.includes(t);
1152
+ }
1153
+ function hi(t) {
1154
+ const e = {
1155
+ kind: t.backend
1156
+ };
1157
+ for (const n of Bn) {
1158
+ const r = t[n];
1159
+ typeof r == "function" && (e[n] = r.bind(t));
1160
+ }
1161
+ return e;
1162
+ }
1163
+ function Gn(t, e) {
1164
+ const n = {
1165
+ kind: t.backend
1166
+ };
1167
+ for (const r of Dt) {
1168
+ const s = t[r];
1169
+ if (typeof s == "function") {
1170
+ const i = s.bind(t);
1171
+ n[r] = e === void 0 ? i : (...o) => (e(), i(...o));
1172
+ }
1173
+ }
1174
+ return n;
1175
+ }
1176
+ const Vn = ["auto", "off", "required"], fi = "auto";
1177
+ function pi(t) {
1178
+ return typeof t == "string" && Vn.includes(t);
1179
+ }
1180
+ const ct = "f64", gi = "f32", mi = "acceleration.minNodes", yi = 0, wi = "RTX 4070 SUPER, headless Chromium, 2026-09-27", bi = Object.freeze(
1181
+ {
1182
+ // Above the 50,000-node render ceiling, so not routed to the device today; the kernel's own
1183
+ // resident crossover, because the element cannot hold a graph this large to measure one.
1184
+ breadthFirstSearch: 141e3,
1185
+ // Likewise above the render ceiling, and likewise the kernel's resident crossover.
1186
+ sssp: 107e3,
1187
+ // Measured through the element, and it crosses at the top of what the element can hold.
1188
+ pageRank: 5e4,
1189
+ // Above the render ceiling. Was 50,000, where the device measured 0.51x -- twice as slow.
1190
+ connectedComponents: 132e3,
1191
+ // Interpolated between the kernel's measured 0.72x at 10,000 and 5.71x at 100,000 nodes
1192
+ // against the index-based port; inside the render ceiling, so a graph this large does reach
1193
+ // the device.
1194
+ hits: 15e3,
1195
+ // Likewise, between Katz's 0.36x and 3.66x; eigenvector centrality is costed as the same row.
1196
+ katzCentrality: 28e3,
1197
+ eigenvectorCentrality: 28e3
1198
+ }
1199
+ ), Wn = 12;
1200
+ function vi(t, e = {}) {
1201
+ return (Yn(t) ? qn(t) : Jn(t)).map((r) => {
1202
+ const s = { ...r.meta, ...e.meta?.[r.name] }, i = r.node === null ? Xn(r.name, s, r.failure ?? "the schema could not be converted") : Zn(r.name, r.node, s), o = e.overrides?.[r.name];
1203
+ return o === void 0 ? i : { ...i, ...o };
1204
+ });
1205
+ }
1206
+ function Yn(t) {
1207
+ return typeof t != "object" || t === null ? !1 : "_zod" in t || "_def" in t;
1208
+ }
1209
+ function qn(t) {
1210
+ const e = jt(t);
1211
+ if (e === null)
1212
+ return [];
1213
+ const { properties: n } = e;
1214
+ return n === void 0 ? [] : Object.entries(n).map(([r, s]) => ({ name: r, node: Ut(s, e) }));
1215
+ }
1216
+ function Jn(t) {
1217
+ const e = Object.entries(t), n = {};
1218
+ for (const [i, o] of e)
1219
+ n[i] = o.schema;
1220
+ const r = Kn(n), s = r?.properties;
1221
+ return e.map(([i, o]) => {
1222
+ const a = s?.[i];
1223
+ return r === null || a === void 0 ? {
1224
+ name: i,
1225
+ node: null,
1226
+ failure: "the schema could not be converted to JSON Schema",
1227
+ meta: o.meta
1228
+ } : { name: i, node: Ut(a, r), meta: o.meta };
1229
+ });
1230
+ }
1231
+ function jt(t) {
1232
+ try {
1233
+ return se.toJSONSchema(t, { io: "input", unrepresentable: "any" });
1234
+ } catch {
1235
+ return null;
1236
+ }
1237
+ }
1238
+ function Kn(t) {
1239
+ try {
1240
+ return jt(se.object(t));
1241
+ } catch {
1242
+ return null;
1243
+ }
1244
+ }
1245
+ const ut = "#/$defs/";
1246
+ function Ut(t, e) {
1247
+ const n = t.$ref;
1248
+ if (n === void 0 || !n.startsWith(ut))
1249
+ return t;
1250
+ const r = n.slice(ut.length).replaceAll("~1", "/").replaceAll("~0", "~");
1251
+ return e.$defs?.[r] ?? t;
1252
+ }
1253
+ function Zn(t, e, n) {
1254
+ const r = Ht(e, 0), s = Qn(r), i = {
1255
+ name: t,
1256
+ plainName: n.label ?? Ve(t),
1257
+ technicalName: t,
1258
+ type: s.type
1259
+ }, o = n.description ?? e.description ?? s.node?.description;
1260
+ o !== void 0 && (i.description = o), "default" in e && (i.default = e.default);
1261
+ const a = s.node;
1262
+ if (a !== void 0 && (s.type === "number" || s.type === "integer")) {
1263
+ const c = lt(a.minimum ?? a.exclusiveMinimum), l = lt(a.maximum ?? a.exclusiveMaximum);
1264
+ c !== void 0 && (i.min = c), l !== void 0 && (i.max = l);
1265
+ }
1266
+ const u = n.step ?? a?.multipleOf;
1267
+ return u !== void 0 && (i.step = u), s.values !== void 0 && (i.values = s.values), n.group !== void 0 && (i.group = n.group), n.advanced !== void 0 && (i.advanced = n.advanced), s.unsupportedReason !== void 0 && (i.unsupportedReason = s.unsupportedReason), i;
1268
+ }
1269
+ function Xn(t, e, n) {
1270
+ const r = {
1271
+ name: t,
1272
+ plainName: e.label ?? Ve(t),
1273
+ technicalName: t,
1274
+ type: "unknown",
1275
+ unsupportedReason: n
1276
+ };
1277
+ return e.description !== void 0 && (r.description = e.description), e.step !== void 0 && (r.step = e.step), e.group !== void 0 && (r.group = e.group), e.advanced !== void 0 && (r.advanced = e.advanced), r;
1278
+ }
1279
+ function Ht(t, e) {
1280
+ if (e >= Wn)
1281
+ return { arms: [], nullable: !1, unresolvedRef: !0 };
1282
+ if (t.$ref !== void 0)
1283
+ return { arms: [], nullable: !1, unresolvedRef: !0 };
1284
+ const n = t.anyOf ?? t.oneOf;
1285
+ if (n === void 0)
1286
+ return t.type === "null" ? { arms: [], nullable: !0, unresolvedRef: !1 } : { arms: [t], nullable: !1, unresolvedRef: !1 };
1287
+ const r = { arms: [], nullable: !1, unresolvedRef: !1 };
1288
+ for (const s of n) {
1289
+ const i = Ht(s, e + 1);
1290
+ r.arms.push(...i.arms), r.nullable = r.nullable || i.nullable, r.unresolvedRef = r.unresolvedRef || i.unresolvedRef;
1291
+ }
1292
+ return r;
1293
+ }
1294
+ function Qn(t) {
1295
+ if (t.arms.length === 0)
1296
+ return t.unresolvedRef ? {
1297
+ type: "unknown",
1298
+ unsupportedReason: "the schema is recursive, so it has no single value type"
1299
+ } : {
1300
+ type: "unknown",
1301
+ unsupportedReason: t.nullable ? "the only value the schema accepts is null" : "the schema declares no value type"
1302
+ };
1303
+ const e = tr(t.arms);
1304
+ if (e !== void 0)
1305
+ return { type: "enum", node: t.arms[0], values: e };
1306
+ if (t.arms.length === 1)
1307
+ return er(t.arms[0]);
1308
+ const n = t.arms.map((r) => Bt(r));
1309
+ return n.length === 2 && n.includes("string") && n.includes("number") ? { type: "node-id" } : {
1310
+ type: "unknown",
1311
+ unsupportedReason: `the schema is a union of ${n.join(" and ")}, which has no single control`
1312
+ };
1313
+ }
1314
+ function er(t) {
1315
+ switch (Bt(t)) {
1316
+ case "integer":
1317
+ return { type: "integer", node: t };
1318
+ case "number":
1319
+ return { type: "number", node: t };
1320
+ case "boolean":
1321
+ return { type: "boolean", node: t };
1322
+ case "string":
1323
+ return { type: "string", node: t };
1324
+ case "array":
1325
+ return {
1326
+ type: "unknown",
1327
+ node: t,
1328
+ unsupportedReason: "an array option has no descriptor type; give it one with an override"
1329
+ };
1330
+ case "object":
1331
+ return {
1332
+ type: "unknown",
1333
+ node: t,
1334
+ unsupportedReason: "an object or record option has no descriptor type; give it one with an override"
1335
+ };
1336
+ default:
1337
+ return {
1338
+ type: "unknown",
1339
+ node: t,
1340
+ unsupportedReason: "the Zod construct has no JSON Schema type, so its values cannot be classified"
1341
+ };
1342
+ }
1343
+ }
1344
+ function tr(t) {
1345
+ const e = [];
1346
+ for (const r of t)
1347
+ if (r.enum !== void 0)
1348
+ e.push(...r.enum);
1349
+ else if ("const" in r)
1350
+ e.push(r.const);
1351
+ else
1352
+ return;
1353
+ if (e.length === 0)
1354
+ return;
1355
+ const n = [];
1356
+ for (const r of e) {
1357
+ if (typeof r != "string" && typeof r != "number" && typeof r != "boolean")
1358
+ return;
1359
+ const s = String(r);
1360
+ n.push({ value: s, label: Ve(s) });
1361
+ }
1362
+ return n;
1363
+ }
1364
+ function Bt(t) {
1365
+ const { type: e } = t;
1366
+ return typeof e == "string" ? e : Array.isArray(e) && e.length > 0 ? e[0] : "none";
1367
+ }
1368
+ function lt(t) {
1369
+ if (!(t === Number.MAX_SAFE_INTEGER || t === -Number.MAX_SAFE_INTEGER))
1370
+ return t;
1371
+ }
1372
+ function Ve(t) {
1373
+ const e = t.replace(/([a-z0-9])([A-Z])/gu, "$1 $2").replace(/[_-]+/gu, " ").trim();
1374
+ return e === "" ? t : e.split(/\s+/u).map((n) => n.charAt(0).toUpperCase() + n.slice(1)).join(" ");
1375
+ }
1376
+ const me = Ge({
1377
+ kind: "camera",
1378
+ idOf: (t) => t.descriptor.id,
1379
+ descriptorOf: (t) => t.descriptor,
1380
+ implementationOf: (t) => t.compute,
1381
+ builtInIds: () => Mn
1382
+ });
1383
+ function Oi(t, e) {
1384
+ const n = t.descriptor;
1385
+ if (n === void 0 || typeof n != "object")
1386
+ throw new m({
1387
+ code: "E_BAD_COMMAND",
1388
+ message: "registerCameraView takes a camera view with a descriptor",
1389
+ source: "registry",
1390
+ details: { kind: "camera", field: "descriptor" }
1391
+ });
1392
+ if (!Array.isArray(n.modes) || n.modes.length === 0)
1393
+ throw new m({
1394
+ code: "E_BAD_COMMAND",
1395
+ message: `the camera view "${String(n.id)}" declares no drawing modes, so nothing could ever offer it: a view says where it works with \`modes\`, and the element refuses the rest`,
1396
+ source: "registry",
1397
+ details: { kind: "camera", name: String(n.id), field: "modes" }
1398
+ });
1399
+ if (!Array.isArray(n.options))
1400
+ throw new m({
1401
+ code: "E_BAD_COMMAND",
1402
+ message: `the camera view "${String(n.id)}" declares no options list. A view that takes no configuration declares an empty one, so a form has something to render and the element has something to check a caller's values against`,
1403
+ source: "registry",
1404
+ details: { kind: "camera", name: String(n.id), field: "options" }
1405
+ });
1406
+ if (typeof t.compute != "function")
1407
+ throw new m({
1408
+ code: "E_BAD_COMMAND",
1409
+ message: `the camera view "${String(n.id)}" was registered without a compute function`,
1410
+ source: "registry",
1411
+ details: { kind: "camera", name: String(n.id), field: "compute" }
1412
+ });
1413
+ me.register(t, e);
1414
+ }
1415
+ function Ni() {
1416
+ return me.descriptors();
1417
+ }
1418
+ function Ai(t) {
1419
+ return me.byId(t);
1420
+ }
1421
+ function ki() {
1422
+ me.clearForTesting();
1423
+ }
1424
+ const ye = Ge({
1425
+ kind: "algorithm",
1426
+ idOf: (t) => t.descriptor.key,
1427
+ descriptorOf: (t) => t.descriptor,
1428
+ implementationOf: (t) => t.descriptor,
1429
+ builtInIds: () => Cn
1430
+ });
1431
+ function nr(t, e) {
1432
+ if (t.descriptor.key !== t.type)
1433
+ throw new m({
1434
+ code: "E_BAD_COMMAND",
1435
+ message: `the algorithm registered as "${t.namespace}:${t.type}" publishes the catalogue key "${t.descriptor.key}". An algorithm has one name: make "descriptor.key" equal "static type".`,
1436
+ source: "registry",
1437
+ details: {
1438
+ kind: "algorithm",
1439
+ field: "descriptor.key",
1440
+ key: t.descriptor.key,
1441
+ type: t.type,
1442
+ namespace: t.namespace
1443
+ }
1444
+ });
1445
+ if (t.descriptor.fields.find((r) => r.name === "runs") !== void 0)
1446
+ throw new m({
1447
+ code: "E_BAD_COMMAND",
1448
+ message: `the algorithm "${t.namespace}:${t.type}" publishes a field named "runs", which is reserved. Name the field something else.`,
1449
+ source: "registry",
1450
+ details: { kind: "algorithm", field: "descriptor.fields", name: "runs", reason: "reserved-field" }
1451
+ });
1452
+ ye.register(t, e);
1453
+ }
1454
+ function Si() {
1455
+ return ye.descriptors();
1456
+ }
1457
+ function Ei(t) {
1458
+ return ye.byId(t);
1459
+ }
1460
+ function Ii() {
1461
+ ye.clearForTesting();
1462
+ }
1463
+ const rr = {
1464
+ fixed: ["kind", "nodes", "edges", "reading"],
1465
+ rule: ["kind", "where", "reading"],
1466
+ path: ["kind", "nodes", "edges", "directed"]
1467
+ }, Gt = ["source", "target", "id", "key", "ordinal", "among"];
1468
+ function $(t) {
1469
+ const e = {};
1470
+ for (const n of Object.keys(t).sort())
1471
+ t[n] !== void 0 && (e[n] = t[n]);
1472
+ return e;
1473
+ }
1474
+ function _(t) {
1475
+ return t === 0 ? 0 : t;
1476
+ }
1477
+ function Vt(t, e) {
1478
+ return t === e ? 0 : t < e ? -1 : 1;
1479
+ }
1480
+ function H(t, e) {
1481
+ return typeof t == "number" ? typeof e == "number" ? t - e : -1 : typeof e == "number" ? 1 : Vt(String(t), String(e));
1482
+ }
1483
+ function Wt(t, e) {
1484
+ for (const n of Gt) {
1485
+ const r = t[n], s = e[n];
1486
+ if (r === void 0 || s === void 0) {
1487
+ if (r !== s)
1488
+ return r === void 0 ? -1 : 1;
1489
+ continue;
1490
+ }
1491
+ const i = H(r, s);
1492
+ if (i !== 0)
1493
+ return i;
1494
+ }
1495
+ return Vt(JSON.stringify(t), JSON.stringify(e));
1496
+ }
1497
+ function J(t, e) {
1498
+ const n = [...t].sort(e);
1499
+ return n.filter((r, s) => s === 0 || e(n[s - 1], r) !== 0);
1500
+ }
1501
+ function $i(t) {
1502
+ return J(t, (e, n) => Wt(e, n));
1503
+ }
1504
+ function Ri(t) {
1505
+ return J(t.map(_), H);
1506
+ }
1507
+ function We(t) {
1508
+ const e = t, n = { ...e };
1509
+ for (const r of Gt)
1510
+ n[r] = _(e[r]);
1511
+ return $(n);
1512
+ }
1513
+ function Yt(t) {
1514
+ return J(
1515
+ t.map(We),
1516
+ (e, n) => Wt(e, n)
1517
+ );
1518
+ }
1519
+ function sr(t) {
1520
+ return t === void 0 || t.length === 0 ? void 0 : Yt(t);
1521
+ }
1522
+ function ir(t) {
1523
+ if (t === null)
1524
+ return null;
1525
+ if (!Array.isArray(t))
1526
+ return We(t);
1527
+ const e = Yt(t);
1528
+ return e.length === 1 ? e[0] : e;
1529
+ }
1530
+ const or = /* @__PURE__ */ new Set([
1531
+ "expression",
1532
+ "edges",
1533
+ "range",
1534
+ "categories",
1535
+ "degree",
1536
+ "component",
1537
+ "neighborhood",
1538
+ "threshold"
1539
+ ]);
1540
+ function ar(t) {
1541
+ if (typeof t != "object" || t === null)
1542
+ return t;
1543
+ const e = t;
1544
+ return typeof e.runId == "string" ? e.runId : typeof e.id == "string" ? e.id : t;
1545
+ }
1546
+ function cr(t) {
1547
+ if (typeof t != "object" || t === null || Array.isArray(t))
1548
+ return t;
1549
+ const e = t, { key: n } = e, r = typeof n == "object" && n !== null && !Array.isArray(n) ? $({ ...n, value: _(n.value) }) : n;
1550
+ return $({ ...e, result: ar(e.result), key: r });
1551
+ }
1552
+ function Ee(t) {
1553
+ if (typeof t != "object" || t === null || Array.isArray(t))
1554
+ return t;
1555
+ const e = t, { kind: n } = e;
1556
+ if (n === "all" || n === "any")
1557
+ return $({ ...e, of: Array.isArray(e.of) ? e.of.map(Ee) : e.of });
1558
+ if (n === "not")
1559
+ return $({ ...e, of: Ee(e.of) });
1560
+ if (n === "member")
1561
+ return $({ ...e, of: ur(e.of) });
1562
+ if (n === "item")
1563
+ return $({ ...e, item: cr(e.item) });
1564
+ if (typeof n == "string" && or.has(n)) {
1565
+ const r = {};
1566
+ for (const [s, i] of Object.entries(e))
1567
+ r[s] = s === "seeds" && Array.isArray(i) ? i.map(_) : _(i);
1568
+ return $(r);
1569
+ }
1570
+ return t;
1571
+ }
1572
+ function ur(t) {
1573
+ if (typeof t != "object" || t === null || Array.isArray(t))
1574
+ return t;
1575
+ const e = t;
1576
+ return ie(e, ["define"]) && ie(e, ["nodes"]) ? t : typeof e.define == "object" && e.define !== null ? { define: qt(e.define) } : Array.isArray(e.nodes) ? { nodes: J(e.nodes.map(_), H) } : t;
1577
+ }
1578
+ function ie(t, e) {
1579
+ return Object.keys(t).some((n) => t[n] !== void 0 && !e.includes(n));
1580
+ }
1581
+ function qt(t) {
1582
+ const e = t;
1583
+ switch (t.kind) {
1584
+ case "fixed": {
1585
+ const n = ie(e, rr.fixed), { reading: r, edges: s } = t, i = t.nodes.map(_);
1586
+ return $({
1587
+ ...e,
1588
+ nodes: n ? i : J(i, H),
1589
+ edges: n ? s?.map(We) : sr(s),
1590
+ reading: r === "clipped" ? "listed" : r
1591
+ });
1592
+ }
1593
+ case "rule": {
1594
+ const n = Ee(t.where), r = typeof n == "object" && n.kind === "expression" && !ie(n, ["kind", "where"]) ? n.where : n;
1595
+ return $({ ...e, where: r });
1596
+ }
1597
+ case "path": {
1598
+ const n = t.edges?.map(ir);
1599
+ return $({
1600
+ ...e,
1601
+ nodes: t.nodes.map(_),
1602
+ edges: n === void 0 || n.length === 0 ? void 0 : n,
1603
+ directed: t.directed === !1 ? void 0 : t.directed
1604
+ });
1605
+ }
1606
+ default:
1607
+ return t;
1608
+ }
1609
+ }
1610
+ const Ie = { a: 0, b: 0 }, Ye = 2166136261, oe = 16777619, qe = 461845907, ae = 2246822507, $e = 35, lr = 36, Jt = 105, dr = 107, Kt = 111, ce = new DataView(new ArrayBuffer(8)), Zt = new Float64Array(ce.buffer), Xt = new Uint32Array(ce.buffer), W = new Float64Array(4), Qt = new Uint8Array(new Uint32Array([1]).buffer)[0] === 1;
1611
+ let j = Ye, U = qe;
1612
+ function F() {
1613
+ j = Ye, U = qe;
1614
+ }
1615
+ function R(t) {
1616
+ j = Math.imul(j ^ t, oe) >>> 0, U = Math.imul(U ^ t, ae) >>> 0;
1617
+ }
1618
+ function O(t) {
1619
+ if (R($e), !Qt) {
1620
+ ce.setFloat64(0, t === 0 ? 0 : t, !0);
1621
+ for (let r = 0; r < 8; r++)
1622
+ R(ce.getUint8(r));
1623
+ return;
1624
+ }
1625
+ Zt[0] = t === 0 ? 0 : t;
1626
+ let e = j, n = U;
1627
+ for (let r = 0; r < 2; r++) {
1628
+ const s = Xt[r];
1629
+ for (let i = 0; i < 32; i += 8) {
1630
+ const o = s >>> i & 255;
1631
+ e = Math.imul(e ^ o, oe) >>> 0, n = Math.imul(n ^ o, ae) >>> 0;
1632
+ }
1633
+ }
1634
+ j = e, U = n;
1635
+ }
1636
+ function Je(t) {
1637
+ R(lr);
1638
+ for (let e = 0; e < t.length; e++)
1639
+ R(t.charCodeAt(e));
1640
+ }
1641
+ function ue(t) {
1642
+ typeof t == "number" ? O(t) : Je(t);
1643
+ }
1644
+ function le(t) {
1645
+ let e = t ^ t >>> 16;
1646
+ return e = Math.imul(e, 2246822507), e ^= e >>> 13, e = Math.imul(e, 3266489909), (e ^ e >>> 16) >>> 0;
1647
+ }
1648
+ function T() {
1649
+ return { a: le(j), b: le(U) };
1650
+ }
1651
+ function Re(t) {
1652
+ return F(), ue(t), T();
1653
+ }
1654
+ function de(t, e) {
1655
+ if (!Qt)
1656
+ return F(), O(t.a), O(t.b), O(e.a), O(e.b), T();
1657
+ let n = Ye, r = qe;
1658
+ W[0] = t.a, W[1] = t.b, W[2] = e.a, W[3] = e.b;
1659
+ for (let s = 0; s < 4; s++) {
1660
+ Zt[0] = W[s], n = Math.imul(n ^ $e, oe) >>> 0, r = Math.imul(r ^ $e, ae) >>> 0;
1661
+ for (let i = 0; i < 2; i++) {
1662
+ const o = Xt[i];
1663
+ for (let a = 0; a < 32; a += 8) {
1664
+ const u = o >>> a & 255;
1665
+ n = Math.imul(n ^ u, oe) >>> 0, r = Math.imul(r ^ u, ae) >>> 0;
1666
+ }
1667
+ }
1668
+ }
1669
+ return { a: le(n), b: le(r) };
1670
+ }
1671
+ function hr(t) {
1672
+ if (F(), t.id !== void 0)
1673
+ R(Jt), ue(t.id);
1674
+ else if (t.key !== void 0)
1675
+ R(dr), ue(t.key);
1676
+ else if (t.ordinal !== void 0 && t.among !== void 0)
1677
+ R(Kt), O(t.ordinal), O(t.among);
1678
+ else
1679
+ throw new Error("an edge member needs an id, a key, or an ordinal with among");
1680
+ return T();
1681
+ }
1682
+ function Ke(t) {
1683
+ return Re(t);
1684
+ }
1685
+ function en(t, e) {
1686
+ const n = Re(t.source), r = Re(t.target), s = e ? de(n, r) : Me(n, r);
1687
+ return de(s, hr(t));
1688
+ }
1689
+ function fr(t, e, n, r, s, i) {
1690
+ const o = n ? de(t, e) : { a: t.a + e.a >>> 0, b: t.b + e.b >>> 0 };
1691
+ let a;
1692
+ return r !== void 0 ? (F(), R(Jt), ue(r), a = T()) : ((s !== dt || i !== ht) && (F(), R(Kt), O(s), O(i), dt = s, ht = i, ft = T()), a = ft), de(o, a);
1693
+ }
1694
+ let dt = -1, ht = -1, ft = Ie;
1695
+ function Me(t, e) {
1696
+ return { a: t.a + e.a >>> 0, b: t.b + e.b >>> 0 };
1697
+ }
1698
+ function Mi(t, e) {
1699
+ return { a: t.a - e.a >>> 0, b: t.b - e.b >>> 0 };
1700
+ }
1701
+ function we(t) {
1702
+ return t.a.toString(16).padStart(8, "0") + t.b.toString(16).padStart(8, "0");
1703
+ }
1704
+ function he(t, e) {
1705
+ return { count: t, sum: we(e) };
1706
+ }
1707
+ function Ci(t, e, n) {
1708
+ const r = {
1709
+ ...n === void 0 || n.count === 0 ? {} : { edges: he(n.count, n.sum) },
1710
+ kind: "fixed",
1711
+ nodes: he(e.count, e.sum),
1712
+ reading: t
1713
+ };
1714
+ return F(), Je(JSON.stringify(r)), `r1:${we(T())}`;
1715
+ }
1716
+ function _i(t) {
1717
+ const e = qt(t);
1718
+ let n = e;
1719
+ if (e.kind === "fixed") {
1720
+ let r = Ie;
1721
+ for (const i of e.nodes)
1722
+ r = Me(r, Ke(i));
1723
+ const s = { ...e, nodes: he(e.nodes.length, r) };
1724
+ if (e.edges !== void 0) {
1725
+ let i = Ie;
1726
+ for (const o of e.edges)
1727
+ i = Me(i, en(o, !0));
1728
+ s.edges = he(e.edges.length, i);
1729
+ }
1730
+ n = s;
1731
+ }
1732
+ return F(), Je(JSON.stringify(n)), `r1:${we(T())}`;
1733
+ }
1734
+ function Fi(t, e) {
1735
+ return F(), O(t.count), O(t.sum.a), O(t.sum.b), O(e.count), O(e.sum.a), O(e.sum.b), `d1:${we(T())}`;
1736
+ }
1737
+ function pr(t) {
1738
+ return String(t);
1739
+ }
1740
+ function gr(t) {
1741
+ if (!/^\d+$/.test(t))
1742
+ return g;
1743
+ const e = Number(t);
1744
+ return Number.isSafeInteger(e) ? e : g;
1745
+ }
1746
+ function mr(t, e) {
1747
+ const n = gr(e);
1748
+ return n === g ? g : t.edgeIndexOf(n);
1749
+ }
1750
+ function Ti() {
1751
+ return { next: 0 };
1752
+ }
1753
+ function tn(t) {
1754
+ return `graphty:e${t}`;
1755
+ }
1756
+ function Pi(t, e, n) {
1757
+ switch (t) {
1758
+ case "keep":
1759
+ return { kind: "add" };
1760
+ case "error":
1761
+ return { kind: "refuse" };
1762
+ case "first":
1763
+ return { kind: "drop" };
1764
+ case "sum":
1765
+ return { kind: "merge", weight: e + n, replaceRecord: !1 };
1766
+ case "min":
1767
+ return { kind: "merge", weight: Math.min(e, n), replaceRecord: !1 };
1768
+ case "max":
1769
+ return { kind: "merge", weight: Math.max(e, n), replaceRecord: !1 };
1770
+ default:
1771
+ return { kind: "merge", weight: n, replaceRecord: !0 };
1772
+ }
1773
+ }
1774
+ const Ce = "graphty.edgeId", X = {
1775
+ /** Node: `hashNodeId` of the node id, two uint32 lanes. */
1776
+ nodeHash: "graphty.nodeHash",
1777
+ /** Edge: `hashEdgeMember` of the edge's stable identity, two uint32 lanes. */
1778
+ edgeHash: "graphty.edgeHash",
1779
+ /** Edge: its position among its pair's surviving edges in its load; -1 for a session edge. */
1780
+ edgeOrdinal: "graphty.edgeOrdinal",
1781
+ /** Edge: its pair's surviving edge count in its load; -1 for a session edge. */
1782
+ edgeAmong: "graphty.edgeAmong"
1783
+ }, yr = "graphty.edgePairsOrdered";
1784
+ function wr(t, e, n, r, s) {
1785
+ const i = t.length, o = new Uint32Array(i), a = new Uint32Array(i);
1786
+ let u = 0;
1787
+ for (let p = 0; p < i; p++) {
1788
+ const [I, B] = e.endpoints(t[p]), G = !n && B < I;
1789
+ o[p] = G ? B : I, a[p] = G ? I : B, u = Math.max(u, o[p] + 1, a[p] + 1);
1790
+ }
1791
+ const { perm: c, bytes: l } = br(o, a, u);
1792
+ t.byteLength + o.byteLength + a.byteLength + l;
1793
+ const d = e.hashOf === void 0 ? (p) => Ke(e.idOf(p)) : e.hashOf.bind(e);
1794
+ let h = 0, f = -1, N = { a: 0, b: 0 };
1795
+ for (; h < i; ) {
1796
+ const p = c[h];
1797
+ let I = h + 1;
1798
+ for (; I < i && o[c[I]] === o[p] && a[c[I]] === a[p]; )
1799
+ I++;
1800
+ o[p] !== f && (f = o[p], N = d(f));
1801
+ const B = d(a[p]), G = I - h;
1802
+ for (let Z = h; Z < I; Z++) {
1803
+ const nt = c[Z], rt = Z - h;
1804
+ s(
1805
+ t[nt],
1806
+ rt,
1807
+ G,
1808
+ fr(N, B, n, r(nt), rt, G)
1809
+ );
1810
+ }
1811
+ h = I;
1812
+ }
1813
+ }
1814
+ function br(t, e, n) {
1815
+ const r = t.length;
1816
+ if (n > 4 * r) {
1817
+ const u = new Uint32Array(r);
1818
+ for (let c = 0; c < r; c++)
1819
+ u[c] = c;
1820
+ return u.sort((c, l) => t[c] - t[l] || e[c] - e[l] || c - l), { perm: u, bytes: u.byteLength };
1821
+ }
1822
+ const s = new Uint32Array(n + 1), i = new Uint32Array(r), o = new Uint32Array(r), a = (u, c, l) => {
1823
+ s.fill(0);
1824
+ for (let d = 0; d < r; d++)
1825
+ s[u[d] + 1]++;
1826
+ for (let d = 0; d < n; d++)
1827
+ s[d + 1] += s[d];
1828
+ for (let d = 0; d < r; d++) {
1829
+ const h = c === null ? d : c[d];
1830
+ l[s[u[h]]++] = h;
1831
+ }
1832
+ };
1833
+ return a(e, null, i), a(t, i, o), { perm: o, bytes: s.byteLength + i.byteLength + o.byteLength };
1834
+ }
1835
+ function xi(t, e, n, r, s) {
1836
+ const [i, o] = t.endpoints(e);
1837
+ return en(
1838
+ { source: t.idOf(i), target: t.idOf(o), id: r ?? tn(n) },
1839
+ s
1840
+ );
1841
+ }
1842
+ function nn(t) {
1843
+ const e = t.graph.typed(yr, "u8");
1844
+ return e === null ? t.directed : e.data[0] === 1;
1845
+ }
1846
+ function zi(t, e) {
1847
+ if (e || typeof t != "object" || t === null)
1848
+ return t;
1849
+ const { source: n, target: r } = t, s = (i) => typeof i == "string" || typeof i == "number";
1850
+ return !s(n) || !s(r) || H(r, n) >= 0 ? t : { ...t, source: r, target: n };
1851
+ }
1852
+ function vr(t) {
1853
+ return {
1854
+ endpoints: (e) => [t.edgeSource(e), t.edgeTarget(e)],
1855
+ idOf: (e) => t.ids.idOf(e)
1856
+ };
1857
+ }
1858
+ const pt = /* @__PURE__ */ new WeakMap();
1859
+ function Or(t) {
1860
+ const e = t.nodes.typed(X.nodeHash, "u32"), n = t.edges.typed(X.edgeHash, "u32"), r = t.edges.typed(X.edgeOrdinal, "i32"), s = t.edges.typed(X.edgeAmong, "i32");
1861
+ if (e !== null && n !== null && r !== null && s !== null)
1862
+ return {
1863
+ nodeHash: e.data,
1864
+ edgeHash: n.data,
1865
+ edgeOrdinal: r.data,
1866
+ edgeAmong: s.data
1867
+ };
1868
+ let i = pt.get(t);
1869
+ return i === void 0 && (i = Nr(t), pt.set(t, i)), i;
1870
+ }
1871
+ function Nr(t) {
1872
+ const e = new Uint32Array(2 * t.nodeCount);
1873
+ for (let o = 0; o < t.nodeCount; o++) {
1874
+ const { a, b: u } = Ke(t.ids.idOf(o));
1875
+ e[2 * o] = a, e[2 * o + 1] = u;
1876
+ }
1877
+ const n = new Uint32Array(2 * t.edgeCount), r = new Int32Array(t.edgeCount), s = new Int32Array(t.edgeCount), i = new Uint32Array(t.edgeCount);
1878
+ for (let o = 0; o < i.length; o++)
1879
+ i[o] = o;
1880
+ return wr(
1881
+ i,
1882
+ vr(t),
1883
+ nn(t),
1884
+ () => {
1885
+ },
1886
+ (o, a, u, c) => {
1887
+ r[o] = a, s[o] = u, n[2 * o] = c.a, n[2 * o + 1] = c.b;
1888
+ }
1889
+ ), { nodeHash: e, edgeHash: n, edgeOrdinal: r, edgeAmong: s };
1890
+ }
1891
+ function Li(t, e, n) {
1892
+ let r = t.ids.idOf(t.edgeSource(e)), s = t.ids.idOf(t.edgeTarget(e));
1893
+ if (!nn(t) && H(s, r) < 0 && ([r, s] = [s, r]), n !== void 0)
1894
+ return { source: r, target: s, id: n };
1895
+ const { edgeOrdinal: i, edgeAmong: o } = Or(t), a = i[e];
1896
+ if (a >= 0)
1897
+ return { source: r, target: s, ordinal: a, among: o[e] };
1898
+ const u = t.edges.typed(Ce, "u32");
1899
+ if (u === null || !u.isSet(e))
1900
+ throw new Error(`edge ${e} has neither an ordinal nor a counter to mint an id from`);
1901
+ return { source: r, target: s, id: tn(u.data[e]) };
1902
+ }
1903
+ const Ar = 256 * 1024 * 1024, kr = 1.5, gt = /* @__PURE__ */ new WeakMap();
1904
+ let Sr = 1;
1905
+ function Er(t) {
1906
+ if (t === null)
1907
+ return 0;
1908
+ let e = gt.get(t);
1909
+ return e === void 0 && (e = Sr++, gt.set(t, e)), e;
1910
+ }
1911
+ function Ir(t, e) {
1912
+ let n = 2166136261, r = 16777619 ^ t.length;
1913
+ for (const s of [t, e]) {
1914
+ for (let i = 0; i < s.length; i++) {
1915
+ const o = s[i];
1916
+ n = Math.imul(n ^ o, 16777619), r = Math.imul(r ^ (o >>> 16 | o << 16), 16777619) ^ i;
1917
+ }
1918
+ n = Math.imul(n ^ s.length, 16777619);
1919
+ }
1920
+ return `${(n >>> 0).toString(16)}${(r >>> 0).toString(16)}`;
1921
+ }
1922
+ function mt(t, e) {
1923
+ if (t === e)
1924
+ return !0;
1925
+ if (t.length !== e.length)
1926
+ return !1;
1927
+ for (let n = 0; n < t.length; n++)
1928
+ if (t[n] !== e[n])
1929
+ return !1;
1930
+ return !0;
1931
+ }
1932
+ function yt(t) {
1933
+ const e = /* @__PURE__ */ new Set(), n = [...t];
1934
+ let r = 0;
1935
+ for (; n.length > 0; ) {
1936
+ const s = n.pop();
1937
+ if (!(s === null || typeof s != "object" || e.has(s))) {
1938
+ if (e.add(s), ArrayBuffer.isView(s)) {
1939
+ r += s.byteLength;
1940
+ continue;
1941
+ }
1942
+ if (!(s instanceof ArrayBuffer)) {
1943
+ if (s instanceof Map)
1944
+ for (const [i, o] of s)
1945
+ n.push(i, o);
1946
+ else if (s instanceof Set)
1947
+ for (const i of s)
1948
+ n.push(i);
1949
+ for (const i of Reflect.ownKeys(s)) {
1950
+ const o = Object.getOwnPropertyDescriptor(s, i);
1951
+ o !== void 0 && "value" in o && n.push(o.value);
1952
+ }
1953
+ }
1954
+ }
1955
+ }
1956
+ return r;
1957
+ }
1958
+ function wt(t) {
1959
+ return t.byteLength({ columns: !0, ids: !0 });
1960
+ }
1961
+ class $r {
1962
+ /**
1963
+ * An empty cache.
1964
+ * @param options - The release hook and, for tests, the byte bound.
1965
+ * @param options.release - Frees an accelerator's device buffers for a snapshot nothing uses.
1966
+ * @param options.limit - A fixed byte bound instead of max(256 MB, 1.5 x the full snapshot).
1967
+ */
1968
+ constructor(e = {}) {
1969
+ this.options = e, this.entries = /* @__PURE__ */ new Map(), this.draining = /* @__PURE__ */ new Set(), this.reservations = /* @__PURE__ */ new Map(), this.waiters = [], this.fullBytes = 0, this.disposed = !1;
1970
+ }
1971
+ /**
1972
+ * The byte bound now.
1973
+ * @returns The bound.
1974
+ */
1975
+ get bound() {
1976
+ return this.options.limit ?? Math.max(Ar, Math.ceil(kr * this.fullBytes));
1977
+ }
1978
+ /**
1979
+ * The bytes the live entries hold, draining ones included.
1980
+ * @returns The byte count.
1981
+ */
1982
+ get bytes() {
1983
+ return yt([...this.live()].map(vt));
1984
+ }
1985
+ /**
1986
+ * Every live entry, draining ones included, least recently used first. For the accounting test.
1987
+ * @returns The entries.
1988
+ */
1989
+ list() {
1990
+ return [...this.live()].map((e) => ({
1991
+ key: e.key,
1992
+ snapshot: e.snapshot,
1993
+ edgeRemap: e.edgeRemap,
1994
+ nodeOrigin: e.nodeOrigin,
1995
+ nodes: e.nodes,
1996
+ edges: e.edges,
1997
+ held: e.holders.size > 0,
1998
+ marked: e.marked
1999
+ }));
2000
+ }
2001
+ /**
2002
+ * A cached input, held for a run on a hit.
2003
+ * @param holder - The run.
2004
+ * @param membership - What it is derived for.
2005
+ * @param orientation - The orientation.
2006
+ * @param simplify - The merge policy.
2007
+ * @returns The input, or undefined on a miss.
2008
+ */
2009
+ get(e, n, r, s) {
2010
+ this.sync(n);
2011
+ const i = bt(n, r, s), o = this.entries.get(i);
2012
+ if (!(o === void 0 || !mt(o.nodes, n.nodes) || !mt(o.edges, n.edges)))
2013
+ return this.entries.delete(i), this.entries.set(i, o), o.holders.add(e), o;
2014
+ }
2015
+ /**
2016
+ * Cache an input a run derived, held for it, then evict unheld entries past the bound.
2017
+ * @param holder - The run.
2018
+ * @param membership - What it was derived for.
2019
+ * @param orientation - The orientation.
2020
+ * @param simplify - The merge policy.
2021
+ * @param input - The derived input.
2022
+ * @param full - The full snapshot it was derived from, whose bytes set the bound.
2023
+ * @returns The input.
2024
+ */
2025
+ put(e, n, r, s, i, o) {
2026
+ this.sync(n), this.fullBytes = wt(o);
2027
+ const a = bt(n, r, s), u = this.entries.get(a);
2028
+ u !== void 0 && (this.entries.delete(a), this.evictEntry(u));
2029
+ const c = {
2030
+ ...i,
2031
+ key: a,
2032
+ serial: n.serial,
2033
+ store: n.store,
2034
+ nodes: n.nodes,
2035
+ edges: n.edges,
2036
+ holders: /* @__PURE__ */ new Set([e]),
2037
+ marked: this.disposed
2038
+ };
2039
+ return this.disposed ? this.draining.add(c) : (this.entries.set(a, c), this.shrink()), c;
2040
+ }
2041
+ /**
2042
+ * Reserve room for a run's derivation before it starts. Evicts unheld entries to make room;
2043
+ * waits while a DIFFERENT run holds or reserves what would free it; refuses `E_TOO_LARGE`
2044
+ * when nothing else holds anything and it still does not fit. A run that already holds an
2045
+ * input is admitted at once: it never waits on itself.
2046
+ * @param holder - The run.
2047
+ * @param estimate - The bytes its derivation is expected to take.
2048
+ * @param full - The full snapshot, whose bytes set the bound.
2049
+ * @param signal - Aborts the wait.
2050
+ * @returns Resolves once the run may derive.
2051
+ */
2052
+ async reserve(e, n, r, s) {
2053
+ for (this.fullBytes = wt(r); ; ) {
2054
+ if (s?.throwIfAborted(), this.holds(e))
2055
+ return;
2056
+ const i = this.bound - this.pending(e) - n;
2057
+ if (this.shrink(i), this.bytes <= i) {
2058
+ this.reservations.set(e, n);
2059
+ return;
2060
+ }
2061
+ if (!this.othersHold(e))
2062
+ throw new m({
2063
+ code: "E_TOO_LARGE",
2064
+ message: `A scoped run needs about ${String(n)} bytes for its input, and the derived-input cache holds at most ${String(this.bound)}.`,
2065
+ source: "run",
2066
+ details: { reason: "derived-input", estimate: n, bound: this.bound }
2067
+ });
2068
+ await this.nextRelease(s);
2069
+ }
2070
+ }
2071
+ /**
2072
+ * A run published or aborted: it lets go of every input it held and its reservation. A marked
2073
+ * input with no holder left is released; waiting runs try again.
2074
+ * @param holder - The run.
2075
+ */
2076
+ releaseHolder(e) {
2077
+ this.reservations.delete(e);
2078
+ for (const n of [...this.live()])
2079
+ n.holders.delete(e) && n.holders.size === 0 && n.marked && this.free(n);
2080
+ this.shrink(), this.wake();
2081
+ }
2082
+ /** The graph froze: every entry is over a snapshot that has gone. */
2083
+ freeze() {
2084
+ for (const e of [...this.entries.values()])
2085
+ this.entries.delete(e.key), this.evictEntry(e);
2086
+ this.wake();
2087
+ }
2088
+ /** The graph is being torn down: release what nothing holds, mark the rest, cache nothing more. */
2089
+ dispose() {
2090
+ this.disposed = !0, this.freeze();
2091
+ }
2092
+ /**
2093
+ * Mark every entry over another snapshot or store than this membership's.
2094
+ * @param membership - The membership now being asked for.
2095
+ */
2096
+ sync(e) {
2097
+ for (const n of [...this.entries.values()])
2098
+ (n.serial !== e.serial || n.store !== e.store) && (this.entries.delete(n.key), this.evictEntry(n));
2099
+ }
2100
+ /**
2101
+ * Evict unheld entries, least recently used first, until the bytes fit.
2102
+ * @param budget - The bytes to fit in; the bound by default.
2103
+ */
2104
+ shrink(e = this.bound) {
2105
+ for (const n of [...this.entries.values()]) {
2106
+ if (this.bytes <= e)
2107
+ return;
2108
+ n.holders.size === 0 && (this.entries.delete(n.key), this.evictEntry(n));
2109
+ }
2110
+ }
2111
+ /**
2112
+ * Take an entry out of the cache: released at once when unheld, else marked and drained.
2113
+ * @param entry - It.
2114
+ */
2115
+ evictEntry(e) {
2116
+ e.marked = !0, e.holders.size === 0 ? this.free(e) : this.draining.add(e);
2117
+ }
2118
+ /**
2119
+ * Release an entry's snapshot, unless another live entry still reaches the same one.
2120
+ * @param entry - It.
2121
+ */
2122
+ free(e) {
2123
+ this.draining.delete(e);
2124
+ for (const n of this.live())
2125
+ if (n !== e && n.snapshot === e.snapshot)
2126
+ return;
2127
+ this.options.release?.(e.snapshot);
2128
+ }
2129
+ /**
2130
+ * Every live entry: cached and draining.
2131
+ * @yields Each entry.
2132
+ */
2133
+ *live() {
2134
+ yield* this.entries.values(), yield* this.draining;
2135
+ }
2136
+ /**
2137
+ * Whether a run holds anything.
2138
+ * @param holder - The run.
2139
+ * @returns True when it does.
2140
+ */
2141
+ holds(e) {
2142
+ for (const n of this.live())
2143
+ if (n.holders.has(e))
2144
+ return !0;
2145
+ return !1;
2146
+ }
2147
+ /**
2148
+ * Whether a run other than this one holds an input or a reservation.
2149
+ * @param holder - The run asking.
2150
+ * @returns True when another does.
2151
+ */
2152
+ othersHold(e) {
2153
+ for (const n of this.reservations.keys())
2154
+ if (n !== e)
2155
+ return !0;
2156
+ for (const n of this.live())
2157
+ for (const r of n.holders)
2158
+ if (r !== e)
2159
+ return !0;
2160
+ return !1;
2161
+ }
2162
+ /**
2163
+ * The bytes other runs reserved and have not yet derived.
2164
+ * @param holder - The run asking, left out.
2165
+ * @returns The byte count.
2166
+ */
2167
+ pending(e) {
2168
+ let n = 0;
2169
+ for (const [r, s] of this.reservations) {
2170
+ if (r === e)
2171
+ continue;
2172
+ const i = yt([...this.live()].filter((o) => o.holders.has(r)).map(vt));
2173
+ n += Math.max(0, s - i);
2174
+ }
2175
+ return n;
2176
+ }
2177
+ /**
2178
+ * Resolves the next time a run lets go or the graph freezes.
2179
+ * @param signal - Rejects the wait when aborted.
2180
+ * @returns The wait.
2181
+ */
2182
+ nextRelease(e) {
2183
+ return new Promise((n, r) => {
2184
+ const s = () => {
2185
+ this.waiters = this.waiters.filter((o) => o !== i), r(
2186
+ e?.reason instanceof Error ? e.reason : new DOMException("The run was cancelled.", "AbortError")
2187
+ );
2188
+ }, i = () => {
2189
+ e?.removeEventListener("abort", s), n();
2190
+ };
2191
+ this.waiters.push(i), e?.addEventListener("abort", s, { once: !0 });
2192
+ });
2193
+ }
2194
+ /** Let every waiting run try again. */
2195
+ wake() {
2196
+ const e = this.waiters;
2197
+ this.waiters = [];
2198
+ for (const n of e)
2199
+ n();
2200
+ }
2201
+ }
2202
+ function bt(t, e, n) {
2203
+ return `${String(Er(t.store))}:${String(t.serial)}:${Ir(t.nodes, t.edges)}:${e}:${n}`;
2204
+ }
2205
+ function vt(t) {
2206
+ return [t.snapshot, t.edgeRemap, t.nodeOrigin, t.nodes, t.edges];
2207
+ }
2208
+ const fe = /* @__PURE__ */ new WeakMap();
2209
+ function Ze(t) {
2210
+ return t.constructor.scopeInput === "subgraph";
2211
+ }
2212
+ function Rr(t) {
2213
+ return Ze(t) ? fe.get(t) : void 0;
2214
+ }
2215
+ function Mr(t) {
2216
+ return fe.get(t)?.scope() ?? null;
2217
+ }
2218
+ function _e(t) {
2219
+ return t === "undirected" ? "undirected" : "declared";
2220
+ }
2221
+ function rn(t, e) {
2222
+ if (e === null)
2223
+ return t;
2224
+ if (t === null)
2225
+ return e;
2226
+ const n = new Uint32Array(t.length);
2227
+ for (let r = 0; r < t.length; r++) {
2228
+ const s = t[r];
2229
+ n[r] = s === g ? g : e[s];
2230
+ }
2231
+ return n;
2232
+ }
2233
+ function Cr(t, e, n, r) {
2234
+ const s = n === "undirected" ? t.undirected(e) : null, i = s === null ? e : s.snapshot, o = r !== "none" && i.flags.multigraph ? i.simplified({ weights: r }) : null;
2235
+ return {
2236
+ snapshot: o === null ? i : o.snapshot,
2237
+ edgeRemap: rn(s?.edgeRemap ?? null, o?.edgeRemap ?? null),
2238
+ nodeOrigin: null
2239
+ };
2240
+ }
2241
+ function Fe(t, e) {
2242
+ return {
2243
+ snapshot: e.snapshot,
2244
+ edgeRemap: rn(t.edgeRemap, e.edgeRemap),
2245
+ nodeOrigin: t.nodeOrigin
2246
+ };
2247
+ }
2248
+ function _r(t, e) {
2249
+ const n = e.inducedSubgraph({ mask: t.nodes }), r = n.edgeRemap, s = re(n.snapshot.edgeCount);
2250
+ let i = 0;
2251
+ const { edges: o } = t;
2252
+ for (let u = 0; u < o.length; u++) {
2253
+ let c = o[u];
2254
+ for (; c !== 0; ) {
2255
+ const l = c & -c, d = u * 32 + (31 - Math.clz32(l));
2256
+ if (c ^= l, d >= e.edgeCount)
2257
+ continue;
2258
+ const h = r === null ? d : r[d];
2259
+ h !== g && (s[h >>> 5] |= 1 << (h & 31), i++);
2260
+ }
2261
+ }
2262
+ const a = { snapshot: n.snapshot, edgeRemap: r, nodeOrigin: n.nodeOrigin };
2263
+ return i === n.snapshot.edgeCount ? a : Fe(a, n.snapshot.filterEdges(s));
2264
+ }
2265
+ function Fr(t, e, n, r, s) {
2266
+ const { inputs: i, holder: o } = t, a = i.get(o, e, r, s);
2267
+ if (a !== void 0)
2268
+ return a;
2269
+ const u = i.get(o, e, "declared", "none") ?? i.put(o, e, "declared", "none", _r(e, n), n);
2270
+ let c = u;
2271
+ return r === "undirected" && c.snapshot.directed && (c = Fe(c, c.snapshot.toUndirected())), s !== "none" && c.snapshot.flags.multigraph && (c = Fe(c, c.snapshot.simplified({ weights: s }))), c === u ? u : i.put(o, e, r, s, c, n);
2272
+ }
2273
+ function sn(t, e, n, r) {
2274
+ const s = t.getSnapshot(), i = n?.simplify ?? "sum", o = r?.scope() ?? null;
2275
+ if (o !== null && o.graph !== s)
2276
+ throw new Error("A run's scope was resolved against a snapshot that is no longer the graph.");
2277
+ const a = o?.resolution, u = a === void 0 || a.nodeCount === s.nodeCount && a.edgeCount === s.edgeCount ? null : a;
2278
+ let c = null, l = u?.nodes ?? null, d = u?.edges ?? null;
2279
+ const h = {
2280
+ graph: s,
2281
+ whole: u === null,
2282
+ nodeCount: u?.nodeCount ?? s.nodeCount,
2283
+ edgeCount: u?.edgeCount ?? s.edgeCount,
2284
+ derived() {
2285
+ return c ??= u === null || r === void 0 ? Cr(t, s, e, i) : Fr(r, u, s, e, i), c;
2286
+ },
2287
+ subgraph() {
2288
+ return h.derived().snapshot;
2289
+ }
2290
+ };
2291
+ return Object.defineProperties(h, {
2292
+ nodes: {
2293
+ enumerable: !0,
2294
+ get: () => (l ??= re(s.nodeCount, !0), l)
2295
+ },
2296
+ edges: {
2297
+ enumerable: !0,
2298
+ get: () => (d ??= re(s.edgeCount, !0), d)
2299
+ }
2300
+ }), h;
2301
+ }
2302
+ function Di(t) {
2303
+ const { graph: e, nodes: n, whole: r } = t, s = [];
2304
+ for (let i = 0; i < e.nodeCount; i++)
2305
+ (r || C(n, i)) && s.push(e.ids.idOf(i));
2306
+ return s;
2307
+ }
2308
+ function ji(t) {
2309
+ const { graph: e, edges: n, whole: r } = t, s = e.edges.typed(Ce, "u32");
2310
+ if (s === null)
2311
+ throw new Error(`The graph carries no "${Ce}" column to name its edges by.`);
2312
+ const { src: i, dst: o } = e.edgeList(), a = [];
2313
+ for (let u = 0; u < e.edgeCount; u++)
2314
+ (r || C(n, u)) && a.push({
2315
+ id: pr(s.data[u]),
2316
+ row: u,
2317
+ source: e.ids.idOf(i[u]),
2318
+ target: e.ids.idOf(o[u])
2319
+ });
2320
+ return a;
2321
+ }
2322
+ const Te = /* @__PURE__ */ new WeakMap();
2323
+ function Tr(t) {
2324
+ let e = Te.get(t);
2325
+ return e === void 0 && (e = new $r({
2326
+ release: (n) => {
2327
+ const { accelerator: r } = t.acceleration, s = r?.release;
2328
+ if (typeof s == "function")
2329
+ try {
2330
+ s.call(r, n);
2331
+ } catch (i) {
2332
+ console.warn("graphty: an accelerator threw while releasing a derived input", i);
2333
+ }
2334
+ }
2335
+ }), Te.set(t, e)), e;
2336
+ }
2337
+ function Ui(t) {
2338
+ return Te.get(t);
2339
+ }
2340
+ function Pr(t) {
2341
+ const { graph: e, resolution: n } = t, r = e.nodeCount + e.edgeCount, s = e.byteLength({ columns: !0, ids: !0 });
2342
+ return r === 0 ? 0 : Math.ceil(s * (n.nodeCount + n.edgeCount) / r);
2343
+ }
2344
+ async function Hi(t, e, n, r, s) {
2345
+ const i = Tr(e), o = {};
2346
+ fe.set(t, { inputs: i, holder: o, scope: n });
2347
+ try {
2348
+ if (Ze(t)) {
2349
+ const a = n();
2350
+ a !== null && (a.resolution.nodeCount !== a.graph.nodeCount || a.resolution.edgeCount !== a.graph.edgeCount) && await i.reserve(o, Pr(a), a.graph, r);
2351
+ }
2352
+ return await s();
2353
+ } finally {
2354
+ fe.delete(t), i.releaseHolder(o);
2355
+ }
2356
+ }
2357
+ class k extends Error {
2358
+ /**
2359
+ * Creates an option validation error
2360
+ * @param optionKey - The key of the option that failed validation
2361
+ * @param message - The validation error message
2362
+ */
2363
+ constructor(e, n) {
2364
+ super(`Option '${e}': ${n}`), this.optionKey = e, this.name = "OptionValidationError";
2365
+ }
2366
+ }
2367
+ function xr(t, e, n) {
2368
+ if (e == null) {
2369
+ if (n.required)
2370
+ throw new k(t, "is required but was not provided");
2371
+ return;
2372
+ }
2373
+ switch (n.type) {
2374
+ case "number":
2375
+ Ot(t, e, n, !1);
2376
+ break;
2377
+ case "integer":
2378
+ Ot(t, e, n, !0);
2379
+ break;
2380
+ case "boolean":
2381
+ if (typeof e != "boolean")
2382
+ throw new k(t, `must be a boolean, got ${typeof e}`);
2383
+ break;
2384
+ case "string":
2385
+ if (typeof e != "string")
2386
+ throw new k(t, `must be a string, got ${typeof e}`);
2387
+ break;
2388
+ case "select":
2389
+ zr(t, e, n);
2390
+ break;
2391
+ case "nodeId":
2392
+ if (typeof e != "string" && typeof e != "number")
2393
+ throw new k(t, `must be a string or number (node ID), got ${typeof e}`);
2394
+ break;
2395
+ default:
2396
+ throw new k(t, `has unknown type '${n.type}'`);
2397
+ }
2398
+ }
2399
+ function Ot(t, e, n, r) {
2400
+ if (typeof e != "number")
2401
+ throw new k(t, `must be a number, got ${typeof e}`);
2402
+ if (Number.isNaN(e))
2403
+ throw new k(t, "must not be NaN");
2404
+ if (!Number.isFinite(e))
2405
+ throw new k(t, "must be finite");
2406
+ if (r && !Number.isInteger(e))
2407
+ throw new k(t, `must be an integer, got ${e}`);
2408
+ if (n.min !== void 0 && e < n.min)
2409
+ throw new k(t, `must be >= ${n.min}, got ${e}`);
2410
+ if (n.max !== void 0 && e > n.max)
2411
+ throw new k(t, `must be <= ${n.max}, got ${e}`);
2412
+ }
2413
+ function zr(t, e, n) {
2414
+ if (!n.options || n.options.length === 0)
2415
+ throw new k(t, "is a select type but has no options defined");
2416
+ if (!n.options.map((s) => s.value).includes(e)) {
2417
+ const s = n.options.map((i) => `'${String(i.value)}'`).join(", ");
2418
+ throw new k(t, `must be one of [${s}], got '${String(e)}'`);
2419
+ }
2420
+ }
2421
+ function Lr(t, e) {
2422
+ const n = {};
2423
+ for (const [r, s] of Object.entries(t)) {
2424
+ const o = e?.[r] ?? s.default;
2425
+ xr(r, o, s), n[r] = o;
2426
+ }
2427
+ return n;
2428
+ }
2429
+ function Bi(t) {
2430
+ return t;
2431
+ }
2432
+ function Dr(t, e, n = sn(t, _e(e))) {
2433
+ return jr(n.subgraph(), e);
2434
+ }
2435
+ function Gi(t) {
2436
+ const e = t.getSnapshot();
2437
+ return e.flags.multigraph ? e.edgeCount - e.simplified({ weights: "sum" }).snapshot.edgeCount : 0;
2438
+ }
2439
+ function jr(t, e) {
2440
+ const n = new Fn({
2441
+ directed: e !== "undirected"
2442
+ }), { ids: r } = t;
2443
+ for (let a = 0; a < t.nodeCount; a++)
2444
+ n.addNode(r.idOf(a));
2445
+ const { src: s, dst: i, weights: o } = t.edgeList();
2446
+ for (let a = 0; a < t.edgeCount; a++) {
2447
+ const u = r.idOf(s[a]), c = r.idOf(i[a]), l = o === null ? 1 : o[a];
2448
+ n.addEdge(u, c, l);
2449
+ }
2450
+ return n;
2451
+ }
2452
+ const Q = new xt("algorithm"), Nt = /* @__PURE__ */ new WeakMap();
2453
+ function Ur(t, e, n) {
2454
+ if (t.scopeInput !== void 0 && t.scopeInput !== e)
2455
+ throw new m({
2456
+ code: "E_BAD_COMMAND",
2457
+ message: `the algorithm registered as "${n}" publishes scopeInput "${t.scopeInput}" and its class declares "${e}". Declare it once, as "static scopeInput", and leave it out of the descriptor.`,
2458
+ source: "registry",
2459
+ details: {
2460
+ kind: "algorithm",
2461
+ field: "descriptor.scopeInput",
2462
+ key: t.key,
2463
+ declared: e,
2464
+ published: t.scopeInput
2465
+ }
2466
+ });
2467
+ let r = Nt.get(t);
2468
+ r === void 0 && (r = /* @__PURE__ */ new Map(), Nt.set(t, r));
2469
+ let s = r.get(e);
2470
+ return s === void 0 && (s = { ...t, scopeInput: e }, r.set(e, s)), s;
2471
+ }
2472
+ const tt = class tt {
2473
+ /**
2474
+ * Getter for schema options
2475
+ *
2476
+ * Algorithms that use the new schema-based options should access
2477
+ * options via this getter.
2478
+ * @returns The resolved schema options
2479
+ */
2480
+ get schemaOptions() {
2481
+ return this._schemaOptions;
2482
+ }
2483
+ /**
2484
+ * Creates a new algorithm instance
2485
+ * @param g - The graph to run the algorithm on
2486
+ * @param options - Optional configuration options (uses schema defaults if not provided)
2487
+ */
2488
+ constructor(e, n) {
2489
+ this.graph = e, this._schemaOptions = this.resolveOptions(n);
2490
+ }
2491
+ /**
2492
+ * The `@graphty/algorithms` Graph this run reads, built from the element's graph snapshot.
2493
+ *
2494
+ * This is the ONLY way an algorithm should obtain its input. The `Node` and `Edge` objects the
2495
+ * data manager also holds are render objects -- each `Node` builds a Babylon mesh in its
2496
+ * constructor -- and reading the graph out of them ties every algorithm to a renderer and to
2497
+ * whatever part of a data load the scene has caught up with.
2498
+ * @param mode - the shape this algorithm needs; see {@link AlgorithmGraphMode}
2499
+ * @returns a freshly built Graph for the algorithm package
2500
+ */
2501
+ algorithmGraph(e) {
2502
+ return Dr(this.graph.getDataManager(), e, this.input(_e(e)));
2503
+ }
2504
+ /**
2505
+ * The graph this run computes over, in one orientation: its scope's compact snapshot when the
2506
+ * class declares {@link Algorithm.scopeInput} and runs as a run, else the whole graph. Both
2507
+ * seams below read through it.
2508
+ * @param orientation - `"declared"` or `"undirected"`.
2509
+ * @param options - How parallel edges merge; the class's {@link Algorithm.parallelEdges} by
2510
+ * default, else `"sum"`.
2511
+ * @returns The input.
2512
+ * @internal
2513
+ */
2514
+ input(e, n) {
2515
+ const r = n?.simplify ?? this.constructor.parallelEdges, s = r === void 0 ? n : { ...n, simplify: r };
2516
+ return sn(this.graph.getDataManager(), e, s, Rr(this));
2517
+ }
2518
+ /**
2519
+ * One edge's record, by the id an input named it by: for an attribute the snapshot does not
2520
+ * carry yet, such as a flow capacity. It is not a topology read -- the ids come from the input
2521
+ * -- and it goes away once the store carries attribute columns.
2522
+ * @param id - The edge's session id, from `scopeEdges`.
2523
+ * @returns The record the edge was loaded from, or undefined.
2524
+ * @internal
2525
+ */
2526
+ edgeRecord(e) {
2527
+ return this.graph.getDataManager().getEdge(e)?.data;
2528
+ }
2529
+ /**
2530
+ * The route an algorithm with an accelerated implementation takes.
2531
+ *
2532
+ * It is the counterpart of {@link algorithmGraph} for the algorithms `@graphty/algorithms`
2533
+ * can dispatch: instead of copying the snapshot into an object graph, the work runs over the
2534
+ * snapshot itself, on the attached accelerator or on the index-based CPU port, and the adapter
2535
+ * writes one loop over an index-aligned result either way.
2536
+ *
2537
+ * THE DECISION IS TAKEN ONCE, HERE, BEFORE ANY WORK STARTS. The controller answers "the policy
2538
+ * is off", "no accelerator", "below `acceleration.minNodes`" or "this accelerator does not
2539
+ * implement that" up front, and under `acceleration="required"` it throws `E_NO_ACCELERATOR`
2540
+ * rather than answering quietly. Two answers stay on the CPU even under `"required"`, because
2541
+ * the device is not the element's to offer for them: a capability the element does not
2542
+ * forward (betweenness and closeness today) never asks the controller, and a call the
2543
+ * dispatcher itself keeps on the CPU port (an option or a graph shape the device's kernel is
2544
+ * not defined for) runs there. Both say `f64`. After the work has started there is no second decision: a
2545
+ * failure from the accelerator propagates with its code and fails the run, because a number
2546
+ * that silently came from somewhere else is worse than no number.
2547
+ * @param capability - The accelerator member this work would use, such as `"pageRank"`.
2548
+ * @param mode - The shape this algorithm needs; see {@link AlgorithmGraphMode}. `"undirected"`
2549
+ * takes the snapshot's undirected view, which is what collapses a reciprocal pair into one
2550
+ * edge.
2551
+ * @param options - What the decision needs to know about this run.
2552
+ * @param options.accelerable - False when the options of this run are ones no accelerator
2553
+ * answers, such as a walk that stops at a target, so the decision is the CPU port's (and
2554
+ * `E_NO_ACCELERATOR` under `acceleration="required"`). A capability the element does not
2555
+ * forward to an accelerator is never accelerable, whatever this says.
2556
+ * @returns The snapshot, the edge map onto it, and the runner.
2557
+ * @example
2558
+ * ```ts
2559
+ * const { snapshot, run } = this.accelerated("connectedComponents", "undirected");
2560
+ * const { value, precision } = await run((dispatch, s) => dispatch.connectedComponents(s));
2561
+ * const group = value.labels[snapshot.ids.indexOf(nodeId)];
2562
+ * ```
2563
+ */
2564
+ accelerated(e, n, r) {
2565
+ const { snapshot: s, edgeRemap: i } = this.input(_e(n)).derived(), o = this.graph.acceleration, a = {
2566
+ capability: e,
2567
+ nodeCount: s.nodeCount,
2568
+ forwarded: (r?.accelerable ?? !0) && at(e)
2569
+ };
2570
+ return {
2571
+ snapshot: s,
2572
+ edgeRemap: i,
2573
+ run: async (u) => {
2574
+ if (at(e)) {
2575
+ let c = !1;
2576
+ const l = await o.run(
2577
+ a,
2578
+ (d) => u(
2579
+ it(
2580
+ Gn(d, () => {
2581
+ c = !0;
2582
+ })
2583
+ ),
2584
+ s
2585
+ )
2586
+ );
2587
+ if (l.accelerated) {
2588
+ if (c)
2589
+ return { value: l.value, precision: l.precision };
2590
+ if (o.policy === "required")
2591
+ throw new m({
2592
+ code: "E_NO_ACCELERATOR",
2593
+ message: `acceleration is required, but the accelerator does not answer this "${e}" run as asked, so it ran on the CPU`,
2594
+ source: "acceleration",
2595
+ details: { policy: "required", capability: e, nodeCount: s.nodeCount }
2596
+ });
2597
+ return { value: l.value, precision: ct };
2598
+ }
2599
+ }
2600
+ return { value: await u(it(null), s), precision: ct };
2601
+ }
2602
+ };
2603
+ }
2604
+ /**
2605
+ * The dense row of a node the reader named in an option.
2606
+ *
2607
+ * A search takes its source as an id and the snapshot answers in indices, so this is where the
2608
+ * two meet -- and where an id that names no node in the graph is reported as what it is: an
2609
+ * option whose value is outside the permitted range, carrying the option's name and what was
2610
+ * passed, rather than a silent empty result or a search from row zero.
2611
+ * @param snapshot - The graph the work runs over.
2612
+ * @param option - The option the id came from, named in the error.
2613
+ * @param id - The node id the reader gave.
2614
+ * @returns The node's dense row.
2615
+ * @throws A `GraphtyError` with `E_OPTION_RANGE` when the graph has no such node.
2616
+ */
2617
+ nodeIndex(e, n, r) {
2618
+ const s = e.ids.indexOf(r);
2619
+ if (s === g)
2620
+ throw new m({
2621
+ code: "E_OPTION_RANGE",
2622
+ message: `the graph has no node "${String(r)}", so "${n}" names nothing to run from`,
2623
+ source: "run",
2624
+ details: { option: n, value: r }
2625
+ });
2626
+ return s;
2627
+ }
2628
+ /**
2629
+ * Resolves and validates options against the schema
2630
+ * @param options - User-provided options (partial)
2631
+ * @returns Fully resolved options with defaults applied
2632
+ */
2633
+ resolveOptions(e) {
2634
+ const n = this.constructor.optionsSchema;
2635
+ return Object.keys(n).length === 0 ? {} : Lr(n, e);
2636
+ }
2637
+ /**
2638
+ * Gets the algorithm type
2639
+ * @returns The algorithm type identifier
2640
+ */
2641
+ get type() {
2642
+ return this.constructor.type;
2643
+ }
2644
+ /**
2645
+ * Gets the algorithm namespace
2646
+ * @returns The algorithm namespace identifier
2647
+ */
2648
+ get namespace() {
2649
+ return this.constructor.namespace;
2650
+ }
2651
+ /**
2652
+ * Compute this algorithm and publish what it produced as a result object.
2653
+ *
2654
+ * This is the entry point the run machinery calls, and it is the one that makes an algorithm
2655
+ * startable as a `Run`: it takes a signal it must throw from, a progress channel, a yield, and
2656
+ * the run id the result is published under -- and it RETURNS the result rather than writing it
2657
+ * somewhere a caller has to go looking for. `run()` is the 1.10 entry point beside it, which
2658
+ * returns nothing and can be neither watched nor stopped.
2659
+ *
2660
+ * The default refuses, because an algorithm that has not been migrated genuinely cannot answer
2661
+ * a run: it publishes through side effects under its own names and has no result object to
2662
+ * hand back. Both shipped families -- a metric and a declared algorithm -- override it.
2663
+ * @param _context - A signal, a progress channel and a yield.
2664
+ * @param runId - The id the result is published under.
2665
+ * @param _fields - The catalogue's descriptors for this algorithm's fields, when the caller
2666
+ * holds them.
2667
+ * @returns The result, or undefined when there was nothing to compute.
2668
+ * @throws A `GraphtyError` with code `E_UNSUPPORTED` when this algorithm has no result to
2669
+ * publish.
2670
+ */
2671
+ publishResult(e, n, r) {
2672
+ return Promise.reject(
2673
+ new m({
2674
+ code: "E_UNSUPPORTED",
2675
+ message: `The "${this.namespace}:${this.type}" algorithm writes its result through side effects and cannot be started as a run.`,
2676
+ source: "run",
2677
+ target: { kind: "run", id: n },
2678
+ details: { algorithm: `${this.namespace}:${this.type}` }
2679
+ })
2680
+ );
2681
+ }
2682
+ /**
2683
+ * Registers an algorithm class in the global registry
2684
+ * @param cls - The algorithm class to register
2685
+ * @param options - Whether a different class under a key already taken throws instead of
2686
+ * replacing it.
2687
+ * @returns The registered algorithm class
2688
+ */
2689
+ static register(e, n) {
2690
+ const r = e, s = String(r.type), i = String(r.namespace), { descriptor: o, cost: a, costUnits: u, version: c } = r;
2691
+ return o !== void 0 && nr(
2692
+ {
2693
+ descriptor: Ur(o, r.scopeInput ?? "none", `${i}:${s}`),
2694
+ namespace: i,
2695
+ type: s,
2696
+ ...a === void 0 ? {} : { cost: a },
2697
+ ...u === void 0 ? {} : { costUnits: u },
2698
+ ...c === void 0 ? {} : { version: c }
2699
+ },
2700
+ n
2701
+ ), Q.set(`${i}:${s}`, e), e;
2702
+ }
2703
+ /**
2704
+ * Gets an algorithm instance from the registry
2705
+ * @param g - The graph to run the algorithm on
2706
+ * @param namespace - The algorithm namespace
2707
+ * @param type - The algorithm type
2708
+ * @param options - Optional algorithm-specific options to pass to constructor
2709
+ * @returns A new instance of the algorithm, or null if not found
2710
+ */
2711
+ static get(e, n, r, s) {
2712
+ const i = Q.get(`${n}:${r}`);
2713
+ return i ? new i(e, s) : null;
2714
+ }
2715
+ /**
2716
+ * Gets an algorithm class from the registry
2717
+ * @param namespace - The algorithm namespace
2718
+ * @param type - The algorithm type
2719
+ * @returns The algorithm class, or null if not found
2720
+ */
2721
+ static getClass(e, n) {
2722
+ return Q.get(`${e}:${n}`) ?? null;
2723
+ }
2724
+ /**
2725
+ * Get the options schema for this algorithm
2726
+ * @returns The options schema, or an empty object if no options defined
2727
+ * @deprecated Use getZodOptionsSchema() instead
2728
+ */
2729
+ static getOptionsSchema() {
2730
+ return this.optionsSchema;
2731
+ }
2732
+ /**
2733
+ * Check if this algorithm has configurable options
2734
+ * @returns true if the algorithm has at least one option defined
2735
+ * @deprecated Use hasZodOptions() instead
2736
+ */
2737
+ static hasOptions() {
2738
+ return Object.keys(this.optionsSchema).length > 0;
2739
+ }
2740
+ /**
2741
+ * Get the Zod-based options schema for this algorithm.
2742
+ * @returns The Zod options schema, or an empty object if no schema defined
2743
+ */
2744
+ static getZodOptionsSchema() {
2745
+ return this.zodOptionsSchema ?? {};
2746
+ }
2747
+ /**
2748
+ * Check if this algorithm has a Zod-based options schema.
2749
+ * @returns true if the algorithm has a Zod options schema defined
2750
+ */
2751
+ static hasZodOptions() {
2752
+ return this.zodOptionsSchema !== void 0 && Object.keys(this.zodOptionsSchema).length > 0;
2753
+ }
2754
+ /**
2755
+ * Get all registered algorithm names.
2756
+ * @param namespace - Optional namespace to filter by
2757
+ * @returns Array of algorithm names in "namespace:type" format
2758
+ */
2759
+ static getRegisteredAlgorithms(e) {
2760
+ const n = [];
2761
+ for (const r of Q.keys())
2762
+ (!e || r.startsWith(`${e}:`)) && n.push(r);
2763
+ return n.sort();
2764
+ }
2765
+ /**
2766
+ * Get all registered algorithm types.
2767
+ * This method is provided for API consistency with DataSource.
2768
+ * @returns Array of algorithm keys in "namespace:type" format
2769
+ * @since 1.5.0
2770
+ * @example
2771
+ * ```typescript
2772
+ * const types = Algorithm.getRegisteredTypes();
2773
+ * console.log('Available algorithms:', types);
2774
+ * // ['graphty:betweenness', 'graphty:closeness', 'graphty:degree', ...]
2775
+ * ```
2776
+ */
2777
+ static getRegisteredTypes() {
2778
+ return this.getRegisteredAlgorithms();
2779
+ }
2780
+ };
2781
+ tt.optionsSchema = {};
2782
+ let Pe = tt;
2783
+ const At = 3, Hr = 0.1;
2784
+ function y(t, e) {
2785
+ return Number.isInteger(t) ? t.toLocaleString(e) : Number(t.toFixed(At)).toLocaleString(e, { maximumFractionDigits: At });
2786
+ }
2787
+ function Br(t, e, n) {
2788
+ const r = t.fields.find((s) => s.name === e);
2789
+ return r === void 0 ? e : n === "technical" ? r.technicalName : r.plainName.toLowerCase();
2790
+ }
2791
+ function ve(t, e, n) {
2792
+ const r = t.fields.find((s) => s.name === e)?.unit;
2793
+ return r === void 0 ? "" : n === 1 && r.endsWith("s") ? ` ${r.slice(0, -1)}` : ` ${r}`;
2794
+ }
2795
+ function q(t, e) {
2796
+ const n = t.graph[e];
2797
+ return typeof n == "number" && Number.isFinite(n) ? n : void 0;
2798
+ }
2799
+ function Gr(t) {
2800
+ return t[0];
2801
+ }
2802
+ function Vr(t, e, n) {
2803
+ const { locale: r, audience: s } = n, i = Br(t, "value", s), o = Gr(e.top);
2804
+ if (o === void 0 || e.median === null)
2805
+ return `Nothing was measured, so there is no ${i} to report.`;
2806
+ const a = [
2807
+ `${o.label} has the highest ${i}, at ${y(o.value, r)}${ve(t, "value", o.value)}.`,
2808
+ `The typical element sits at ${y(e.median, r)}${ve(t, "value", e.median)}.`
2809
+ ];
2810
+ return e.measured > 0 && e.tiedAtMin / e.measured >= Hr && e.min !== null && a.push(
2811
+ `${y(e.tiedAtMin, r)} of ${y(e.measured, r)} sit at the lowest value, ${y(e.min, r)}${ve(t, "value", e.min)}.`
2812
+ ), e.count > e.measured && a.push(`${y(e.count - e.measured, r)} were not measured.`), a.join(" ");
2813
+ }
2814
+ function Wr(t, e, n) {
2815
+ const { locale: r } = n, s = e.groups ?? [];
2816
+ if (s.length === 0)
2817
+ return "Nothing was grouped, so there are no groups to report.";
2818
+ const i = s[0], o = [
2819
+ `${y(s.length, r)} ${s.length === 1 ? "group" : "groups"} were found,`,
2820
+ `the largest holding ${y(i.size, r)} of ${y(e.measured, r)}.`
2821
+ ], a = q(t, "modularity");
2822
+ return a !== void 0 && o.push(`Modularity is ${y(a, r)}.`), o.join(" ");
2823
+ }
2824
+ function Yr(t, e) {
2825
+ const { locale: n } = e, r = q(t, "hops"), s = q(t, "cost");
2826
+ if (r === void 0 && s === void 0)
2827
+ return "No route was found.";
2828
+ const i = [];
2829
+ return r !== void 0 && i.push(`The route runs ${y(r, n)} ${r === 1 ? "hop" : "hops"}.`), s !== void 0 && i.push(`Its total cost is ${y(s, n)}.`), i.join(" ");
2830
+ }
2831
+ function qr(t, e, n) {
2832
+ const { locale: r } = n, s = q(t, "count") ?? e.measured, i = t.shape === "edge-set" ? "edge" : "node";
2833
+ return s === 0 ? `No ${i}s were selected.` : `${y(s, r)} ${s === 1 ? i : `${i}s`} were selected.`;
2834
+ }
2835
+ function Jr(t, e) {
2836
+ const { pairs: n } = t.graph, r = Array.isArray(n) ? n.length : 0;
2837
+ return r === 0 ? "No pairs were found." : `${y(r, e.locale)} ${r === 1 ? "pair was" : "pairs were"} found.`;
2838
+ }
2839
+ function Kr(t, e) {
2840
+ const n = q(t, "steps");
2841
+ return n === void 0 || n === 0 ? "The series is empty." : `The series covers ${y(n, e.locale)} ${n === 1 ? "step" : "steps"}.`;
2842
+ }
2843
+ function kt(t, e) {
2844
+ return t.measured === 0 ? "The run produced no values." : `The run covered ${y(t.measured, e.locale)} of ${y(t.count, e.locale)}.`;
2845
+ }
2846
+ function Zr(t, e) {
2847
+ const n = t.summary(), { shape: r } = t;
2848
+ switch (r) {
2849
+ case "node-metric":
2850
+ case "edge-metric":
2851
+ return Vr(t, n, e);
2852
+ case "community":
2853
+ case "layered-grouping":
2854
+ case "category-table":
2855
+ return Wr(t, n, e);
2856
+ case "path":
2857
+ return Yr(t, e);
2858
+ case "node-set":
2859
+ case "edge-set":
2860
+ return qr(t, n, e);
2861
+ case "pair-list":
2862
+ return Jr(t, e);
2863
+ case "temporal":
2864
+ return Kr(t, e);
2865
+ case "fact":
2866
+ return kt(n, e);
2867
+ default:
2868
+ return kt(n, e);
2869
+ }
2870
+ }
2871
+ function Vi(t, e) {
2872
+ const n = e === "node", r = n ? t.nodeValue : t.edgeValue, s = n ? t.nodeHas : t.edgeHas, i = n ? t.nodeIdOf : t.edgeIdOf;
2873
+ return {
2874
+ value: r,
2875
+ has: s ?? ((o, a) => Xr(r(o, a))),
2876
+ idOf: i ?? null
2877
+ };
2878
+ }
2879
+ function Xr(t) {
2880
+ return t != null;
2881
+ }
2882
+ function te(t) {
2883
+ return t == null || t === !1 || t === "" ? !1 : Array.isArray(t) ? t.length > 0 : typeof t == "object" ? Object.keys(t).length > 0 : !0;
2884
+ }
2885
+ function xe(t, e) {
2886
+ if (t === e)
2887
+ return !0;
2888
+ if (Array.isArray(t) && Array.isArray(e))
2889
+ return t.length === e.length && t.every((n, r) => xe(n, e[r]));
2890
+ if (St(t) && St(e)) {
2891
+ const n = Object.keys(t);
2892
+ return n.length === Object.keys(e).length && n.every((r) => xe(t[r], e[r]));
2893
+ }
2894
+ return !1;
2895
+ }
2896
+ function St(t) {
2897
+ return typeof t == "object" && t !== null && !Array.isArray(t);
2898
+ }
2899
+ function w(t, e, n, r = {}) {
2900
+ return new m({
2901
+ code: "E_BAD_SELECTOR",
2902
+ message: `${t} (at character ${String(n)} of ${JSON.stringify(e)})`,
2903
+ source: "style",
2904
+ details: { ...r, position: n, where: e }
2905
+ });
2906
+ }
2907
+ const Qr = Object.freeze({
2908
+ "[": "index, slice, wildcard and filter expressions",
2909
+ "]": "index, slice, wildcard and filter expressions",
2910
+ "{": "multi-select hashes",
2911
+ "}": "multi-select hashes",
2912
+ ",": "multi-select lists",
2913
+ "*": "wildcards",
2914
+ "@": "the current-node reference",
2915
+ ":": "slices"
2916
+ }), es = ["&&", "||", "==", "!=", "<=", ">=", "!", "<", ">", ".", "(", ")"];
2917
+ function on(t) {
2918
+ return /[A-Za-z_]/.test(t);
2919
+ }
2920
+ function an(t) {
2921
+ return /[A-Za-z0-9_]/.test(t);
2922
+ }
2923
+ function Oe(t, e, n) {
2924
+ for (let r = e + 1; r < t.length; r++) {
2925
+ if (t[r] === "\\") {
2926
+ r++;
2927
+ continue;
2928
+ }
2929
+ if (t[r] === n)
2930
+ return r;
2931
+ }
2932
+ throw w(`A ${n} is opened and never closed`, t, e, { delimiter: n });
2933
+ }
2934
+ function ts(t) {
2935
+ let e = "";
2936
+ for (let n = 0; n < t.length; n++) {
2937
+ if (t[n] === "\\" && (t[n + 1] === "'" || t[n + 1] === "\\")) {
2938
+ e += t[n + 1], n++;
2939
+ continue;
2940
+ }
2941
+ e += t[n];
2942
+ }
2943
+ return e;
2944
+ }
2945
+ function ns(t, e, n) {
2946
+ const r = n.replace(/\\`/g, "`");
2947
+ try {
2948
+ return JSON.parse(r);
2949
+ } catch {
2950
+ throw w(
2951
+ `A literal between backticks must be JSON, so a bare word needs quotes: write \`"${r}"\` rather than \`${r}\``,
2952
+ t,
2953
+ e,
2954
+ { literal: r }
2955
+ );
2956
+ }
2957
+ }
2958
+ function rs(t, e, n) {
2959
+ try {
2960
+ const r = JSON.parse(n);
2961
+ if (typeof r == "string")
2962
+ return r;
2963
+ } catch {
2964
+ }
2965
+ throw w(`A quoted attribute name follows JSON's rules for a string, and ${n} does not`, t, e, {
2966
+ name: n
2967
+ });
2968
+ }
2969
+ function ss(t) {
2970
+ const e = [];
2971
+ let n = 0;
2972
+ for (; n < t.length; ) {
2973
+ const r = t.charAt(n);
2974
+ if (/\s/.test(r)) {
2975
+ n++;
2976
+ continue;
2977
+ }
2978
+ const s = Qr[r];
2979
+ if (s !== void 0)
2980
+ throw w(`A selector does not support ${s}`, t, n, { construct: s });
2981
+ if (r === "|" && t.charAt(n + 1) !== "|")
2982
+ throw w("A selector does not support pipe expressions", t, n, {
2983
+ construct: "pipe expressions"
2984
+ });
2985
+ if (r === "&" && t.charAt(n + 1) !== "&")
2986
+ throw w("A selector does not support expression references", t, n, {
2987
+ construct: "expression references"
2988
+ });
2989
+ const i = es.find((o) => t.startsWith(o, n));
2990
+ if (i !== void 0) {
2991
+ e.push({ kind: "operator", text: i, at: n }), n += i.length;
2992
+ continue;
2993
+ }
2994
+ if (r === "`") {
2995
+ const o = Oe(t, n, "`");
2996
+ e.push({
2997
+ kind: "literal",
2998
+ text: "",
2999
+ value: ns(t, n, t.slice(n + 1, o)),
3000
+ at: n
3001
+ }), n = o + 1;
3002
+ continue;
3003
+ }
3004
+ if (r === "'") {
3005
+ const o = Oe(t, n, "'");
3006
+ e.push({ kind: "literal", text: "", value: ts(t.slice(n + 1, o)), at: n }), n = o + 1;
3007
+ continue;
3008
+ }
3009
+ if (r === '"') {
3010
+ const o = Oe(t, n, '"');
3011
+ e.push({ kind: "identifier", text: rs(t, n, t.slice(n, o + 1)), at: n }), n = o + 1;
3012
+ continue;
3013
+ }
3014
+ if (on(r)) {
3015
+ let o = n + 1;
3016
+ for (; o < t.length && an(t.charAt(o)); )
3017
+ o++;
3018
+ e.push({ kind: "identifier", text: t.slice(n, o), at: n }), n = o;
3019
+ continue;
3020
+ }
3021
+ throw /[0-9-]/.test(r) ? w("A number in a selector goes between backticks, so write `5` rather than 5", t, n, {
3022
+ character: r
3023
+ }) : w(`${JSON.stringify(r)} is not something a selector can contain`, t, n, {
3024
+ character: r
3025
+ });
3026
+ }
3027
+ return e.push({ kind: "end", text: "", at: t.length }), e;
3028
+ }
3029
+ const is = Object.freeze({
3030
+ "!=": "!=",
3031
+ "<": "<",
3032
+ "<=": "<=",
3033
+ "==": "==",
3034
+ ">": ">",
3035
+ ">=": ">="
3036
+ });
3037
+ function x(t) {
3038
+ return t.tokens[t.index];
3039
+ }
3040
+ function z(t, e) {
3041
+ const n = x(t);
3042
+ return n.kind === "operator" && n.text === e;
3043
+ }
3044
+ function os(t) {
3045
+ const e = x(t), n = [];
3046
+ for (; ; ) {
3047
+ const r = x(t);
3048
+ if (r.kind !== "identifier")
3049
+ throw w("A `.` must be followed by an attribute name", t.where, r.at);
3050
+ if (r.text.includes("."))
3051
+ throw w(
3052
+ `A quoted attribute name may not contain a dot: ${JSON.stringify(r.text)} would be indistinguishable from two names`,
3053
+ t.where,
3054
+ r.at,
3055
+ { segment: r.text }
3056
+ );
3057
+ if (t.index++, z(t, "("))
3058
+ throw w(
3059
+ `A selector does not support functions, so ${r.text}(...) cannot be called here`,
3060
+ t.where,
3061
+ r.at,
3062
+ { construct: "functions", function: r.text }
3063
+ );
3064
+ if (n.push(r.text), !z(t, "."))
3065
+ return { kind: "path", path: n.join("."), at: e.at };
3066
+ t.index++;
3067
+ }
3068
+ }
3069
+ function as(t) {
3070
+ const e = x(t);
3071
+ if (e.kind === "literal")
3072
+ return t.index++, { kind: "literal", value: e.value };
3073
+ if (e.kind === "identifier")
3074
+ return os(t);
3075
+ if (z(t, "(")) {
3076
+ t.index++;
3077
+ const n = cn(t);
3078
+ if (!z(t, ")"))
3079
+ throw w("A `(` is opened and never closed", t.where, e.at);
3080
+ return t.index++, { kind: "group", inner: n };
3081
+ }
3082
+ throw w(
3083
+ e.kind === "end" ? "The selector ends where an attribute name, a literal or a `(` should be" : `${JSON.stringify(e.text)} is where an attribute name, a literal or a \`(\` should be`,
3084
+ t.where,
3085
+ e.at
3086
+ );
3087
+ }
3088
+ function ze(t) {
3089
+ if (!z(t, "!"))
3090
+ return as(t);
3091
+ const e = x(t);
3092
+ t.index++;
3093
+ const n = ze(t);
3094
+ if (n.kind === "path" && n.path.includes("."))
3095
+ throw w(
3096
+ `In JMESPath \`!\` binds tighter than \`.\`, so !${n.path} means (!${n.path.split(".")[0]})${n.path.slice(n.path.indexOf("."))} rather than the opposite of ${n.path}. Write !(${n.path}) for that`,
3097
+ t.where,
3098
+ e.at,
3099
+ { path: n.path }
3100
+ );
3101
+ return { kind: "not", operand: n };
3102
+ }
3103
+ function Et(t) {
3104
+ const e = ze(t), n = x(t), r = n.kind === "operator" ? is[n.text] : void 0;
3105
+ return r === void 0 ? e : (t.index++, { kind: "compare", operator: r, left: e, right: ze(t) });
3106
+ }
3107
+ function It(t) {
3108
+ let e = Et(t);
3109
+ for (; z(t, "&&"); )
3110
+ t.index++, e = { kind: "and", left: e, right: Et(t) };
3111
+ return e;
3112
+ }
3113
+ function cn(t) {
3114
+ let e = It(t);
3115
+ for (; z(t, "||"); )
3116
+ t.index++, e = { kind: "or", left: e, right: It(t) };
3117
+ return e;
3118
+ }
3119
+ function cs(t) {
3120
+ const e = { where: t, tokens: ss(t), index: 0 }, n = cn(e), r = x(e);
3121
+ if (r.kind !== "end")
3122
+ throw w(
3123
+ `${JSON.stringify(r.text)} is left over at the end of the selector`,
3124
+ t,
3125
+ r.at
3126
+ );
3127
+ return n;
3128
+ }
3129
+ function Y(t, e) {
3130
+ switch (t.kind) {
3131
+ case "path":
3132
+ e.includes(t.path) || e.push(t.path);
3133
+ return;
3134
+ case "group":
3135
+ Y(t.inner, e);
3136
+ return;
3137
+ case "not":
3138
+ Y(t.operand, e);
3139
+ return;
3140
+ case "and":
3141
+ case "or":
3142
+ case "compare":
3143
+ Y(t.left, e), Y(t.right, e);
3144
+ return;
3145
+ default:
3146
+ return;
3147
+ }
3148
+ }
3149
+ function E(t, e) {
3150
+ switch (t.kind) {
3151
+ case "path": {
3152
+ const { path: n } = t, { value: r } = e;
3153
+ return (s) => {
3154
+ const i = r(s, n);
3155
+ return i === void 0 ? null : i;
3156
+ };
3157
+ }
3158
+ case "literal": {
3159
+ const { value: n } = t;
3160
+ return () => n;
3161
+ }
3162
+ case "group":
3163
+ return E(t.inner, e);
3164
+ case "not": {
3165
+ const n = E(t.operand, e);
3166
+ return (r) => !te(n(r));
3167
+ }
3168
+ case "and": {
3169
+ const n = E(t.left, e), r = E(t.right, e);
3170
+ return (s) => {
3171
+ const i = n(s);
3172
+ return te(i) ? r(s) : i;
3173
+ };
3174
+ }
3175
+ case "or": {
3176
+ const n = E(t.left, e), r = E(t.right, e);
3177
+ return (s) => {
3178
+ const i = n(s);
3179
+ return te(i) ? i : r(s);
3180
+ };
3181
+ }
3182
+ default:
3183
+ return ds(t.operator, t.left, t.right, e);
3184
+ }
3185
+ }
3186
+ const us = Object.freeze({
3187
+ "<": (t, e) => t < e,
3188
+ "<=": (t, e) => t <= e,
3189
+ ">": (t, e) => t > e,
3190
+ ">=": (t, e) => t >= e
3191
+ });
3192
+ function ls(t, e) {
3193
+ return t.kind === "literal" ? t : e.kind === "literal" ? e : null;
3194
+ }
3195
+ function ds(t, e, n, r) {
3196
+ if (t === "==" || t === "!=") {
3197
+ const a = t === "==", u = e.kind === "literal", c = ls(e, n), l = u ? n : e;
3198
+ if (c !== null && c.value === null && l.kind === "path") {
3199
+ const { path: f } = l, { has: N } = r;
3200
+ return (p) => N(p, f) !== a;
3201
+ }
3202
+ const d = E(e, r), h = E(n, r);
3203
+ if (c !== null && c.value !== null && typeof c.value != "object") {
3204
+ const { value: f } = c, N = u ? h : d;
3205
+ return (p) => N(p) === f === a;
3206
+ }
3207
+ return (f) => xe(d(f), h(f)) === a;
3208
+ }
3209
+ const s = E(e, r), i = E(n, r), o = us[t];
3210
+ return (a) => {
3211
+ const u = s(a), c = i(a);
3212
+ return typeof u == "number" && typeof c == "number" ? o(u, c) : null;
3213
+ };
3214
+ }
3215
+ function L(t, e) {
3216
+ switch (t.kind) {
3217
+ case "compare":
3218
+ case "not": {
3219
+ const n = E(t, e);
3220
+ return (r) => n(r) === !0;
3221
+ }
3222
+ case "group":
3223
+ return L(t.inner, e);
3224
+ case "and": {
3225
+ const n = L(t.left, e), r = L(t.right, e);
3226
+ return (s) => n(s) && r(s);
3227
+ }
3228
+ case "or": {
3229
+ const n = L(t.left, e), r = L(t.right, e);
3230
+ return (s) => n(s) || r(s);
3231
+ }
3232
+ default: {
3233
+ const n = E(t, e);
3234
+ return (r) => te(n(r));
3235
+ }
3236
+ }
3237
+ }
3238
+ function hs(t) {
3239
+ return t.split(".").map((e) => fs(e) ? e : JSON.stringify(e)).join(".");
3240
+ }
3241
+ function fs(t) {
3242
+ if (t === "" || !on(t[0]))
3243
+ return !1;
3244
+ for (let e = 1; e < t.length; e++)
3245
+ if (!an(t[e]))
3246
+ return !1;
3247
+ return !0;
3248
+ }
3249
+ function Wi(t, e) {
3250
+ const { has: n } = t;
3251
+ return (r) => n(r, e);
3252
+ }
3253
+ function Yi(t, e) {
3254
+ const { idOf: n } = t;
3255
+ if (n === null)
3256
+ throw new m({
3257
+ code: "E_UNSUPPORTED",
3258
+ message: 'This session cannot evaluate an "ids" selector, because it cannot say which id sits at which row. Painting the layer anyway would colour elements it never named.',
3259
+ source: "style",
3260
+ details: { match: "ids" }
3261
+ });
3262
+ return (r) => e.has(n(r));
3263
+ }
3264
+ function qi(t, e, n) {
3265
+ const { value: r } = t;
3266
+ return (s) => {
3267
+ const i = n();
3268
+ if (i === void 0)
3269
+ return !1;
3270
+ const o = r(s, e);
3271
+ return typeof o == "number" && Number.isFinite(o) && o >= i;
3272
+ };
3273
+ }
3274
+ function Ji(t, e) {
3275
+ return (n) => {
3276
+ const r = t.bits(e);
3277
+ return r !== null && C(r, n);
3278
+ };
3279
+ }
3280
+ function Ki(t, e) {
3281
+ const n = cs(t), r = [];
3282
+ if (Y(n, r), r.length === 0) {
3283
+ let s = n;
3284
+ for (; s.kind === "group"; )
3285
+ s = s.inner;
3286
+ const i = s.kind === "literal" && typeof s.value == "string";
3287
+ throw w(
3288
+ i ? "The selector is a quoted string literal, which is always true, so it would match every element. Remove the outer quotes so it is read as an expression" : 'The selector reads no attribute of the element, so it answers the same for every element. Write { match: "everything" } for a layer that really is meant to paint the whole graph',
3289
+ t,
3290
+ 0,
3291
+ { constant: !0 }
3292
+ );
3293
+ }
3294
+ return { paths: Object.freeze(r), test: L(n, e) };
3295
+ }
3296
+ const Le = "results", ps = "$";
3297
+ function ne(t, e) {
3298
+ return e === void 0 ? `${Le}.${t}` : `${Le}.${t}.${e}`;
3299
+ }
3300
+ function gs(t) {
3301
+ return `Group ${String(t)}`;
3302
+ }
3303
+ function un(t, e) {
3304
+ const n = Number(t), r = Number(e);
3305
+ return Number.isFinite(n) && Number.isFinite(r) && String(n) === String(t) && String(r) === String(e) ? n - r : String(t).localeCompare(String(e));
3306
+ }
3307
+ const ln = {
3308
+ // -- per element ---------------------------------------------------------------------
3309
+ value: {
3310
+ meaning: "The number this metric measured for this element.",
3311
+ scope: "element",
3312
+ types: ["number", "integer"]
3313
+ },
3314
+ rank: {
3315
+ meaning: "Where this element sits when every measured element is ordered best first, starting at 1.",
3316
+ scope: "element",
3317
+ types: ["integer"]
3318
+ },
3319
+ percentile: {
3320
+ meaning: "The share of measured elements this one ranks at or above, from 0 to 1.",
3321
+ scope: "element",
3322
+ types: ["number"]
3323
+ },
3324
+ group: {
3325
+ meaning: "Which group this node was placed in.",
3326
+ scope: "element",
3327
+ types: ["integer", "string"]
3328
+ },
3329
+ groupSize: {
3330
+ meaning: "How many nodes share this node's group.",
3331
+ scope: "element",
3332
+ types: ["integer"]
3333
+ },
3334
+ level: {
3335
+ meaning: "How many levels out from the start this node sits, counting the start as 0.",
3336
+ scope: "element",
3337
+ types: ["integer"]
3338
+ },
3339
+ levelSize: {
3340
+ meaning: "How many nodes share this node's level.",
3341
+ scope: "element",
3342
+ types: ["integer"]
3343
+ },
3344
+ category: {
3345
+ meaning: "The category this node was sorted into.",
3346
+ scope: "element",
3347
+ types: ["string"]
3348
+ },
3349
+ score: {
3350
+ meaning: "How strongly this node belongs to its category.",
3351
+ scope: "element",
3352
+ types: ["number"]
3353
+ },
3354
+ onPath: {
3355
+ meaning: "Whether this element is on the route the run found.",
3356
+ scope: "element",
3357
+ types: ["boolean"]
3358
+ },
3359
+ order: {
3360
+ meaning: "This node's position along the route, counting the source as 0.",
3361
+ scope: "element",
3362
+ types: ["integer"]
3363
+ },
3364
+ in: {
3365
+ meaning: "Whether this element is in the set the run selected.",
3366
+ scope: "element",
3367
+ types: ["boolean"]
3368
+ },
3369
+ // -- per graph -----------------------------------------------------------------------
3370
+ min: {
3371
+ meaning: "The lowest value any measured element carries.",
3372
+ scope: "graph",
3373
+ types: ["number"]
3374
+ },
3375
+ max: {
3376
+ meaning: "The highest value any measured element carries.",
3377
+ scope: "graph",
3378
+ types: ["number"]
3379
+ },
3380
+ median: {
3381
+ meaning: "The middle value once the measured elements are ordered.",
3382
+ scope: "graph",
3383
+ types: ["number"]
3384
+ },
3385
+ mean: {
3386
+ meaning: "The average value across the measured elements.",
3387
+ scope: "graph",
3388
+ types: ["number"]
3389
+ },
3390
+ measured: {
3391
+ meaning: "How many elements the run produced a value for. Smaller than the scope when some elements have nothing to measure. Distinct from RunResult.measured, which counts the nodes and edges the run looked at.",
3392
+ scope: "graph",
3393
+ types: ["integer"]
3394
+ },
3395
+ normalization: {
3396
+ meaning: 'How the values were scaled before publication: "max", "min-max" or "none".',
3397
+ scope: "graph",
3398
+ types: ["string"]
3399
+ },
3400
+ tiedAtMin: {
3401
+ meaning: "How many measured elements sit at the lowest value, which is what says whether a colour ramp is about to paint most of the graph one colour.",
3402
+ scope: "graph",
3403
+ types: ["integer"]
3404
+ },
3405
+ groupCount: {
3406
+ meaning: "How many groups the partition has.",
3407
+ scope: "graph",
3408
+ types: ["integer"]
3409
+ },
3410
+ modularity: {
3411
+ meaning: "How much better this partition is than a random one, from -0.5 to 1.",
3412
+ scope: "graph",
3413
+ types: ["number"]
3414
+ },
3415
+ sizes: {
3416
+ meaning: "The size of each group or level, largest first.",
3417
+ scope: "graph",
3418
+ types: ["table"]
3419
+ },
3420
+ levelCount: {
3421
+ meaning: "How many levels the walk reached.",
3422
+ scope: "graph",
3423
+ types: ["integer"]
3424
+ },
3425
+ categories: {
3426
+ meaning: "One row per category, with its name and how many elements fell into it.",
3427
+ scope: "graph",
3428
+ types: ["table"]
3429
+ },
3430
+ length: {
3431
+ meaning: "How many nodes are on the route.",
3432
+ scope: "graph",
3433
+ types: ["integer"]
3434
+ },
3435
+ cost: {
3436
+ meaning: "What the route costs in total, summing the weight of every edge on it.",
3437
+ scope: "graph",
3438
+ types: ["number"]
3439
+ },
3440
+ hops: {
3441
+ meaning: "How many edges are on the route.",
3442
+ scope: "graph",
3443
+ types: ["integer"]
3444
+ },
3445
+ count: {
3446
+ meaning: "How many elements are in the set.",
3447
+ scope: "graph",
3448
+ types: ["integer"]
3449
+ },
3450
+ pairs: {
3451
+ meaning: "One row per scored pair of elements, best first.",
3452
+ scope: "graph",
3453
+ types: ["table"]
3454
+ },
3455
+ steps: {
3456
+ meaning: "One row per time step, with the step's window and what was visible in it.",
3457
+ scope: "graph",
3458
+ types: ["table"]
3459
+ },
3460
+ series: {
3461
+ meaning: "One row per tracked quantity, carrying its value at every step.",
3462
+ scope: "graph",
3463
+ types: ["table"]
3464
+ },
3465
+ rates: {
3466
+ meaning: "One row per tracked quantity, carrying how fast it changed between steps.",
3467
+ scope: "graph",
3468
+ types: ["table"]
3469
+ },
3470
+ changeThreshold: {
3471
+ meaning: "The rate of change above which a step counts as a change rather than drift.",
3472
+ scope: "graph",
3473
+ types: ["number"]
3474
+ }
3475
+ }, Zi = Object.keys(ln), Xe = {
3476
+ "node-metric": {
3477
+ shape: "node-metric",
3478
+ primaryField: "value",
3479
+ nodeFields: ["value", "rank", "percentile"],
3480
+ edgeFields: [],
3481
+ graphFields: ["min", "max", "median", "mean", "measured", "normalization", "tiedAtMin"],
3482
+ optionalGraphFields: [],
3483
+ headlineScalar: !1,
3484
+ layer: "encoding"
3485
+ },
3486
+ "edge-metric": {
3487
+ shape: "edge-metric",
3488
+ primaryField: "value",
3489
+ nodeFields: [],
3490
+ edgeFields: ["value", "rank", "percentile"],
3491
+ graphFields: ["min", "max", "median", "mean", "measured", "normalization", "tiedAtMin"],
3492
+ optionalGraphFields: [],
3493
+ headlineScalar: !1,
3494
+ layer: "encoding"
3495
+ },
3496
+ community: {
3497
+ shape: "community",
3498
+ primaryField: "group",
3499
+ nodeFields: ["group", "groupSize"],
3500
+ edgeFields: [],
3501
+ graphFields: ["groupCount", "sizes"],
3502
+ // Only an algorithm that scores its own partition can publish modularity. Label
3503
+ // propagation and connected components do not, and a required field they cannot fill
3504
+ // would be a number invented to satisfy a table.
3505
+ optionalGraphFields: ["modularity"],
3506
+ headlineScalar: !1,
3507
+ layer: "encoding"
3508
+ },
3509
+ "layered-grouping": {
3510
+ shape: "layered-grouping",
3511
+ primaryField: "level",
3512
+ nodeFields: ["level", "levelSize"],
3513
+ edgeFields: [],
3514
+ graphFields: ["levelCount", "sizes"],
3515
+ optionalGraphFields: [],
3516
+ headlineScalar: !1,
3517
+ layer: "encoding"
3518
+ },
3519
+ "category-table": {
3520
+ shape: "category-table",
3521
+ primaryField: "category",
3522
+ nodeFields: ["category", "score", "rank"],
3523
+ edgeFields: [],
3524
+ graphFields: ["categories"],
3525
+ optionalGraphFields: [],
3526
+ headlineScalar: !1,
3527
+ layer: "encoding"
3528
+ },
3529
+ path: {
3530
+ shape: "path",
3531
+ primaryField: "onPath",
3532
+ nodeFields: ["onPath", "order"],
3533
+ // The edges of the route carry membership but not a position: an edge's place in the
3534
+ // route is the order of the node it leaves.
3535
+ edgeFields: ["onPath"],
3536
+ graphFields: ["length", "cost", "hops"],
3537
+ optionalGraphFields: [],
3538
+ headlineScalar: !1,
3539
+ layer: "highlight"
3540
+ },
3541
+ "node-set": {
3542
+ shape: "node-set",
3543
+ primaryField: "in",
3544
+ nodeFields: ["in"],
3545
+ edgeFields: [],
3546
+ graphFields: ["count"],
3547
+ optionalGraphFields: [],
3548
+ headlineScalar: !0,
3549
+ layer: "highlight"
3550
+ },
3551
+ "edge-set": {
3552
+ shape: "edge-set",
3553
+ primaryField: "in",
3554
+ nodeFields: [],
3555
+ edgeFields: ["in"],
3556
+ graphFields: ["count"],
3557
+ optionalGraphFields: [],
3558
+ headlineScalar: !0,
3559
+ layer: "highlight"
3560
+ },
3561
+ "pair-list": {
3562
+ shape: "pair-list",
3563
+ primaryField: "pairs",
3564
+ nodeFields: [],
3565
+ edgeFields: [],
3566
+ graphFields: ["pairs"],
3567
+ optionalGraphFields: [],
3568
+ headlineScalar: !1,
3569
+ layer: "none"
3570
+ },
3571
+ temporal: {
3572
+ shape: "temporal",
3573
+ primaryField: "series",
3574
+ nodeFields: [],
3575
+ edgeFields: [],
3576
+ graphFields: ["steps", "series", "rates", "changeThreshold"],
3577
+ optionalGraphFields: [],
3578
+ headlineScalar: !1,
3579
+ layer: "none"
3580
+ },
3581
+ fact: {
3582
+ shape: "fact",
3583
+ primaryField: null,
3584
+ nodeFields: [],
3585
+ edgeFields: [],
3586
+ graphFields: [],
3587
+ optionalGraphFields: [],
3588
+ headlineScalar: !1,
3589
+ layer: "none"
3590
+ }
3591
+ };
3592
+ function De(t) {
3593
+ return Xe[t];
3594
+ }
3595
+ function Xi(t) {
3596
+ return Xe[t].layer === "highlight";
3597
+ }
3598
+ function Qi(t, e) {
3599
+ const n = Xe[t], r = [], s = [
3600
+ { names: n.nodeFields, kind: "node" },
3601
+ { names: n.edgeFields, kind: "edge" },
3602
+ { names: n.graphFields, kind: "graph" }
3603
+ ];
3604
+ for (const { names: i, kind: o } of s)
3605
+ for (const a of i) {
3606
+ const u = e.find((l) => l.name === a && l.kind === o);
3607
+ if (u === void 0) {
3608
+ r.push({
3609
+ field: a,
3610
+ kind: o,
3611
+ reason: `shape "${t}" requires a ${o} field named "${a}"`
3612
+ });
3613
+ continue;
3614
+ }
3615
+ const c = ln[a].types;
3616
+ c.includes(u.type) || r.push({
3617
+ field: a,
3618
+ kind: o,
3619
+ reason: `${o} field "${a}" is typed "${u.type}", not ${c.map((l) => `"${l}"`).join(" or ")}`
3620
+ });
3621
+ }
3622
+ return n.headlineScalar && !ms(n, e) && r.push({
3623
+ field: null,
3624
+ kind: "graph",
3625
+ reason: `shape "${t}" requires one graph-level scalar of its own beside "count"`
3626
+ }), r;
3627
+ }
3628
+ function ms(t, e) {
3629
+ const n = [...t.graphFields, ...t.optionalGraphFields];
3630
+ return e.some((r) => r.kind === "graph" && !n.includes(r.name));
3631
+ }
3632
+ const ys = 3;
3633
+ function ws(t, e) {
3634
+ if (t === e)
3635
+ return 0;
3636
+ const n = new Uint32Array(e.length + 1), r = new Uint32Array(e.length + 1);
3637
+ for (let s = 0; s <= e.length; s++)
3638
+ n[s] = s;
3639
+ for (let s = 1; s <= t.length; s++) {
3640
+ r[0] = s;
3641
+ for (let i = 1; i <= e.length; i++) {
3642
+ const o = n[i - 1] + (t[s - 1] === e[i - 1] ? 0 : 1);
3643
+ r[i] = Math.min(r[i - 1] + 1, n[i] + 1, o);
3644
+ }
3645
+ n.set(r);
3646
+ }
3647
+ return n[e.length];
3648
+ }
3649
+ function bs(t, e, n = ys) {
3650
+ const r = t.toLowerCase(), s = e.map((i) => ({
3651
+ candidate: i,
3652
+ distance: ws(r, i.toLowerCase())
3653
+ }));
3654
+ return s.sort((i, o) => i.distance - o.distance || i.candidate.localeCompare(o.candidate)), Object.freeze(s.slice(0, Math.max(n, 0)).map((i) => i.candidate));
3655
+ }
3656
+ function je(t) {
3657
+ return typeof t == "string" ? t : "runId" in t ? t.runId : t.id;
3658
+ }
3659
+ function vs(t) {
3660
+ return typeof t == "string" ? void 0 : t.shape;
3661
+ }
3662
+ function Os(t, e) {
3663
+ return t.fields.some((n) => n.name === e) || e in t.graph;
3664
+ }
3665
+ class Ns {
3666
+ #e;
3667
+ /**
3668
+ * Build the API over a registry.
3669
+ * @param registry - Where runs are looked up.
3670
+ */
3671
+ constructor(e) {
3672
+ this.#e = e;
3673
+ }
3674
+ /**
3675
+ * The published path of a run's field.
3676
+ *
3677
+ * With no field the path names the run's primary field -- `value` for a metric, `group` for a
3678
+ * partition, `onPath` for a route -- so a caller binds an encoding to a run without knowing
3679
+ * what that algorithm calls its number. A `fact` result has no primary field and addresses
3680
+ * its whole result object instead.
3681
+ * @param run - The run, its result, or its id.
3682
+ * @param field - The field name; the shape's primary field when absent.
3683
+ * @returns The path.
3684
+ */
3685
+ path(e, n) {
3686
+ const r = je(e);
3687
+ if (n !== void 0)
3688
+ return ne(r, n);
3689
+ const s = vs(e) ?? this.#e.entry(r)?.shape, i = s === void 0 ? null : De(s).primaryField;
3690
+ return i === null ? ne(r) : ne(r, i);
3691
+ }
3692
+ /**
3693
+ * The same field, written so a selector expression can read it.
3694
+ *
3695
+ * The quoting is the whole point: a run id carries its algorithm's name, and a hyphenated
3696
+ * name lexes its hyphen as subtraction, so a path pasted into an expression unquoted is a
3697
+ * refused selector rather than a comparison. Nothing here decides WHICH field -- that is
3698
+ * {@link ResultsApi.path}'s job and this defers to it -- so the two can never name different
3699
+ * columns.
3700
+ * @param run - The run, its result, or its id.
3701
+ * @param field - The field name; the shape's primary field when absent.
3702
+ * @returns The path with every segment quoted that needs it.
3703
+ */
3704
+ term(e, n) {
3705
+ return hs(n === void 0 ? this.path(e) : this.path(e, n));
3706
+ }
3707
+ /**
3708
+ * One run's result.
3709
+ *
3710
+ * The answer always comes from the registry, even when the caller passed a result object: the
3711
+ * question is what this session holds, and a result the session never registered is not it.
3712
+ * @param run - The run, its result, or its id.
3713
+ * @returns The result, or undefined when the session holds no such run or it has not
3714
+ * finished.
3715
+ */
3716
+ get(e) {
3717
+ return this.#e.entry(je(e))?.result;
3718
+ }
3719
+ /**
3720
+ * Whether a run, or one of its fields, is available to read.
3721
+ * @param run - The run, its result, or its id.
3722
+ * @param field - The field name; asks only about the run itself when absent.
3723
+ * @returns True when the path would resolve.
3724
+ */
3725
+ has(e, n) {
3726
+ const r = this.get(e);
3727
+ return r === void 0 ? !1 : n === void 0 || Os(r, n);
3728
+ }
3729
+ /**
3730
+ * Every run that has published a result, as an expression editor reads them.
3731
+ * @returns One root per finished run, in the order the runs were started.
3732
+ */
3733
+ get roots() {
3734
+ const e = [];
3735
+ for (const n of this.#e.entries())
3736
+ n.result !== void 0 && e.push(Object.freeze({ runId: n.id, label: n.label, fields: n.result.fields }));
3737
+ return Object.freeze(e);
3738
+ }
3739
+ }
3740
+ const dn = /* @__PURE__ */ new WeakMap();
3741
+ function eo(t, e) {
3742
+ const n = dn.get(t)?.entry(je(e));
3743
+ return n?.result === void 0 ? void 0 : n.execution;
3744
+ }
3745
+ function to(t) {
3746
+ const e = new Ns(t);
3747
+ return dn.set(e, t), e;
3748
+ }
3749
+ const As = 20, Ne = 100, ks = 100, Ss = Object.freeze([]), Es = Object.freeze(["max", "min-max", "none"]);
3750
+ function hn(t) {
3751
+ return typeof t == "string" && Es.includes(t);
3752
+ }
3753
+ function no(t) {
3754
+ return {
3755
+ length: t.length,
3756
+ get: (e) => t[e]
3757
+ };
3758
+ }
3759
+ const Is = Object.freeze({
3760
+ measured: 0,
3761
+ min: Number.NaN,
3762
+ max: Number.NaN,
3763
+ mean: Number.NaN,
3764
+ median: Number.NaN,
3765
+ tiedAtMin: 0,
3766
+ smallestPositive: null
3767
+ });
3768
+ function fn(t) {
3769
+ const { length: e } = t, n = new Float64Array(e);
3770
+ let r = 0;
3771
+ for (let h = 0; h < e; h++) {
3772
+ const f = t.get(h);
3773
+ Number.isFinite(f) && (n[r] = f, r++);
3774
+ }
3775
+ if (r === 0)
3776
+ return { length: e, ...Is };
3777
+ let s = Number.POSITIVE_INFINITY, i = Number.NEGATIVE_INFINITY, o = Number.POSITIVE_INFINITY, a = 0, u = 0;
3778
+ for (let h = 0; h < r; h++) {
3779
+ const f = n[h];
3780
+ f < s && (s = f), f > i && (i = f), f > 0 && f < o && (o = f);
3781
+ const N = f - u, p = a + N;
3782
+ u = p - a - N, a = p;
3783
+ }
3784
+ const c = n.slice(0, r).sort(), l = c[Math.floor((r - 1) / 2)];
3785
+ let d = 0;
3786
+ for (; d < r && c[d] === s; )
3787
+ d++;
3788
+ return {
3789
+ length: e,
3790
+ measured: r,
3791
+ min: s,
3792
+ max: i,
3793
+ mean: a / r,
3794
+ median: l,
3795
+ tiedAtMin: d,
3796
+ smallestPositive: Number.isFinite(o) ? o : null
3797
+ };
3798
+ }
3799
+ function pn(t) {
3800
+ const e = fn(t);
3801
+ return { view: Object.freeze({
3802
+ length: t.length,
3803
+ get: (r) => t.get(r),
3804
+ min: e.min,
3805
+ max: e.max,
3806
+ mean: e.mean,
3807
+ median: e.median
3808
+ }), statistics: e };
3809
+ }
3810
+ function ro(t) {
3811
+ const e = (s) => t[s].value, n = (s) => t[s].id, r = gn(t.length, e, n);
3812
+ return Ue(r, r.length, e, n);
3813
+ }
3814
+ function gn(t, e, n) {
3815
+ const r = [];
3816
+ for (let i = 0; i < t; i++)
3817
+ Number.isFinite(e(i)) && r.push(i);
3818
+ const s = [];
3819
+ for (const i of r)
3820
+ s[i] = String(n(i));
3821
+ return r.sort((i, o) => {
3822
+ const a = e(i), u = e(o);
3823
+ if (a !== u)
3824
+ return u - a;
3825
+ const c = s[i], l = s[o];
3826
+ return c === l ? 0 : c < l ? -1 : 1;
3827
+ }), Uint32Array.from(r);
3828
+ }
3829
+ function Ue(t, e, n, r) {
3830
+ const s = t.length, i = [];
3831
+ let o = 0, a = Number.NaN;
3832
+ for (let u = 0; u < Math.min(e, s); u++) {
3833
+ const c = n(t[u]);
3834
+ c !== a && (o = u + 1, a = c), i.push(
3835
+ Object.freeze({ id: r(t[u]), value: c, rank: o, percentile: (s - o + 1) / s })
3836
+ );
3837
+ }
3838
+ return Object.freeze(i);
3839
+ }
3840
+ function $s(t, e) {
3841
+ let n = Math.min(e, t.length);
3842
+ for (; n > 0 && n < t.length && t[n].rank === t[n - 1].rank; )
3843
+ n--;
3844
+ if (n === t.length || n === e)
3845
+ return Object.freeze({ entries: t.slice(0, n), leftOut: null, reason: null });
3846
+ const { value: r } = t[n];
3847
+ let s = n;
3848
+ for (; s < t.length && t[s].value === r; )
3849
+ s++;
3850
+ const i = s - n, o = `${String(i)} tie at ${String(r)}, and taking them would make ${String(n + i)}, more than the ${String(e)} asked for, so ${n === 0 ? "none are" : `only the top ${String(n)} are`} taken.`;
3851
+ return Object.freeze({
3852
+ entries: t.slice(0, n),
3853
+ leftOut: Object.freeze({ value: r, count: i }),
3854
+ reason: o
3855
+ });
3856
+ }
3857
+ function Rs(t) {
3858
+ const { smallestPositive: e } = t;
3859
+ if (t.measured === 0 || !(t.max > 0) || e === null)
3860
+ return !1;
3861
+ const n = t.min > 0 ? t.min : e;
3862
+ return Math.log10(t.max) > Math.log10(n);
3863
+ }
3864
+ function Ms(t) {
3865
+ return t.measured === 0 || !(t.median > 0) || t.max / t.median <= ks ? "linear" : Rs(t) ? "log" : "linear";
3866
+ }
3867
+ function Cs(t, e, n, r) {
3868
+ if (!(e > t))
3869
+ return { binCount: 1, indexOf: () => 0, rangeOf: () => [t, e] };
3870
+ if (r) {
3871
+ const i = e - t + 1, o = Math.ceil(i / Math.min(i, n)), a = Math.ceil(i / o);
3872
+ return {
3873
+ binCount: a,
3874
+ indexOf: (u) => Math.min(Math.floor((u - t) / o), a - 1),
3875
+ rangeOf: (u) => {
3876
+ const c = t + u * o;
3877
+ return [c, Math.min(c + o - 1, e)];
3878
+ }
3879
+ };
3880
+ }
3881
+ const s = (e - t) / n;
3882
+ return {
3883
+ binCount: n,
3884
+ indexOf: (i) => Math.min(Math.floor((i - t) / s), n - 1),
3885
+ rangeOf: (i) => [
3886
+ t + i * s,
3887
+ i === n - 1 ? e : t + (i + 1) * s
3888
+ ]
3889
+ };
3890
+ }
3891
+ function _s(t, e, n, r, s) {
3892
+ const i = t > 0 ? 0 : 1, o = i === 0 ? t : n;
3893
+ if (!(e > 0) || o === null || !(o > 0))
3894
+ return null;
3895
+ const a = Math.log10(o), u = Math.log10(e);
3896
+ if (!(u > a))
3897
+ return null;
3898
+ const c = r - i;
3899
+ if (c < 1)
3900
+ return null;
3901
+ const l = (u - a) / c;
3902
+ return {
3903
+ binCount: r,
3904
+ indexOf: (d) => {
3905
+ if (!(d > 0))
3906
+ return 0;
3907
+ const h = Math.floor((Math.log10(d) - a) / l);
3908
+ return i + Math.min(Math.max(h, 0), c - 1);
3909
+ },
3910
+ rangeOf: (d) => {
3911
+ if (d < i)
3912
+ return [t, 0];
3913
+ const h = d - i, f = h === 0 ? o : 10 ** (a + h * l), N = h === c - 1 ? e : 10 ** (a + (h + 1) * l);
3914
+ if (!s)
3915
+ return [f, N];
3916
+ const p = h === 0 ? o : Math.ceil(f);
3917
+ return [p, h === c - 1 ? e : Math.max(p, Math.ceil(N) - 1)];
3918
+ }
3919
+ };
3920
+ }
3921
+ function Fs(t) {
3922
+ if (t === void 0)
3923
+ return As;
3924
+ if (!Number.isInteger(t) || t < 1 || t > Ne)
3925
+ throw new m({
3926
+ code: "E_OPTION_RANGE",
3927
+ source: "run",
3928
+ message: `A histogram takes between 1 and ${Ne} bins; ${String(t)} was asked for.`,
3929
+ details: { option: "bins", value: t, min: 1, max: Ne }
3930
+ });
3931
+ return t;
3932
+ }
3933
+ function Ts(t, e) {
3934
+ const n = /* @__PURE__ */ new Map();
3935
+ for (let r = 0; r < t.length; r++) {
3936
+ const s = t.get(r);
3937
+ if (!Number.isFinite(s))
3938
+ continue;
3939
+ const i = n.get(s);
3940
+ if (i === void 0) {
3941
+ if (n.size >= e)
3942
+ return null;
3943
+ n.set(s, 1);
3944
+ continue;
3945
+ }
3946
+ n.set(s, i + 1);
3947
+ }
3948
+ return n;
3949
+ }
3950
+ function Ps(t, e) {
3951
+ const n = Fs(e?.bins), r = e?.integerValued ?? !1, s = fn(t), i = Ms(s), o = Ts(t, n);
3952
+ if (o !== null) {
3953
+ if (o.size === 0)
3954
+ return Object.freeze({
3955
+ bins: Ss,
3956
+ // Nothing was measured, so nothing is on any axis. Reported as linear rather
3957
+ // than as the request, because "log scale" over an empty chart is the same false
3958
+ // caption this whole return type exists to prevent.
3959
+ scale: "linear",
3960
+ suggestedScale: "linear",
3961
+ binning: "empty"
3962
+ });
3963
+ const d = [...o.entries()].sort((h, f) => h[0] - f[0]).map(([h, f]) => Object.freeze({ from: h, to: h, count: f }));
3964
+ return Object.freeze({
3965
+ bins: Object.freeze(d),
3966
+ // One bar per distinct value has no bands to space, so neither axis was applied to
3967
+ // it. Saying "linear" here is what stops a caption claiming a logarithmic layout of
3968
+ // a chart that has none.
3969
+ scale: "linear",
3970
+ suggestedScale: i,
3971
+ binning: "per-value"
3972
+ });
3973
+ }
3974
+ const u = e?.scale === "log" || e?.scale === "auto" && i === "log" ? _s(s.min, s.max, s.smallestPositive, n, r) : null, c = u ?? Cs(s.min, s.max, n, r), l = new Array(c.binCount).fill(0);
3975
+ for (let d = 0; d < t.length; d++) {
3976
+ const h = t.get(d);
3977
+ Number.isFinite(h) && (l[c.indexOf(h)] += 1);
3978
+ }
3979
+ return Object.freeze({
3980
+ bins: Object.freeze(
3981
+ l.map((d, h) => {
3982
+ const [f, N] = c.rangeOf(h);
3983
+ return Object.freeze({ from: f, to: N, count: d });
3984
+ })
3985
+ ),
3986
+ // `plan` is null exactly when a logarithmic layout was asked for and could not be built,
3987
+ // which is the case a caption must not get wrong.
3988
+ scale: u === null ? "linear" : "log",
3989
+ suggestedScale: i,
3990
+ binning: "banded"
3991
+ });
3992
+ }
3993
+ const xs = 10, zs = 10, be = /* @__PURE__ */ Symbol("missing");
3994
+ class mn {
3995
+ constructor() {
3996
+ this.ids = [], this.positions = /* @__PURE__ */ new Map();
3997
+ }
3998
+ get size() {
3999
+ return this.ids.length;
4000
+ }
4001
+ idOf(e) {
4002
+ return this.ids[e];
4003
+ }
4004
+ indexOf(e) {
4005
+ return this.positions.get(e) ?? -1;
4006
+ }
4007
+ }
4008
+ function Ls(t) {
4009
+ return 64 * t.size;
4010
+ }
4011
+ function $t(t) {
4012
+ const e = new mn(), n = [];
4013
+ for (const s of t ?? []) {
4014
+ let i = e.positions.get(s.id);
4015
+ i === void 0 && (i = e.ids.length, e.positions.set(s.id, i), e.ids.push(s.id)), n.push(i);
4016
+ }
4017
+ const r = { index: e, token: null, length: e.ids.length, columns: /* @__PURE__ */ new Map() };
4018
+ return (t ?? []).forEach((s, i) => {
4019
+ for (const [o, a] of Object.entries(s.values))
4020
+ yn(r, o)[n[i]] = a;
4021
+ }), r;
4022
+ }
4023
+ function yn(t, e) {
4024
+ let n = t.columns.get(e);
4025
+ return n === void 0 && (n = new Array(t.length).fill(be), t.columns.set(e, n)), n;
4026
+ }
4027
+ function Rt(t) {
4028
+ for (const [e, n] of t.columns)
4029
+ Array.isArray(n) && n.every((r) => typeof r == "number") && t.columns.set(e, Float64Array.from(n));
4030
+ }
4031
+ function K(t, e, n) {
4032
+ const r = t.columns.get(e)?.[n];
4033
+ return r === be ? void 0 : r;
4034
+ }
4035
+ function Mt(t, e) {
4036
+ const n = t.index.indexOf(e);
4037
+ if (!(n >= 0 && n < t.length))
4038
+ return;
4039
+ const r = {};
4040
+ for (const [s, i] of t.columns) {
4041
+ const o = i[n];
4042
+ o !== be && (r[s] = o);
4043
+ }
4044
+ return Object.freeze(r);
4045
+ }
4046
+ function Ct(t) {
4047
+ let e = 0;
4048
+ for (const n of t.columns.values())
4049
+ e += n instanceof Float64Array ? n.byteLength : 8 * n.length;
4050
+ return e;
4051
+ }
4052
+ function D(t, e) {
4053
+ const n = t.columns.get(e);
4054
+ return {
4055
+ length: t.length,
4056
+ get: (r) => bn(n?.[r])
4057
+ };
4058
+ }
4059
+ function wn(t, e) {
4060
+ const n = D(t, e);
4061
+ return gn(
4062
+ t.length,
4063
+ (r) => n.get(r),
4064
+ (r) => t.index.idOf(r)
4065
+ );
4066
+ }
4067
+ function bn(t) {
4068
+ return typeof t == "number" ? t : Number.NaN;
4069
+ }
4070
+ function Qe(t) {
4071
+ return typeof t == "string" || typeof t == "number";
4072
+ }
4073
+ function Ae(t) {
4074
+ return t.type === "number" || t.type === "integer";
4075
+ }
4076
+ function A(t, e, n) {
4077
+ t[e] === void 0 && (t[e] = n);
4078
+ }
4079
+ function He(t, e, n, r) {
4080
+ const s = yn(t, e);
4081
+ (s[n] === be || s[n] === void 0) && (s[n] = r);
4082
+ }
4083
+ function vn(t, e) {
4084
+ const n = /* @__PURE__ */ new Map();
4085
+ for (let r = 0; r < t.length; r++) {
4086
+ const s = K(t, e, r);
4087
+ Qe(s) && n.set(s, (n.get(s) ?? 0) + 1);
4088
+ }
4089
+ return n;
4090
+ }
4091
+ function Ds(t) {
4092
+ const e = [...t.entries()].map(([n, r]) => ({ group: n, size: r }));
4093
+ return e.sort((n, r) => r.size - n.size || un(n.group, r.group)), Object.freeze(e.map((n) => Object.freeze(n)));
4094
+ }
4095
+ function On(t, e) {
4096
+ const n = t.find((r) => r.name === e)?.normalization;
4097
+ return hn(n) ? n : "none";
4098
+ }
4099
+ function Nn(t, e, n) {
4100
+ const r = wn(t, e), s = r.length;
4101
+ let i = 0, o = Number.NaN;
4102
+ for (let a = 0; a < s; a++) {
4103
+ const u = r[a], c = bn(K(t, e, u));
4104
+ c !== o && (i = a + 1, o = c), He(t, "rank", u, i), n && He(t, "percentile", u, (s - i + 1) / s);
4105
+ }
4106
+ }
4107
+ function _t(t, e, n) {
4108
+ const { statistics: r } = pn(D(t, "value"));
4109
+ Nn(t, "value", !0), r.measured > 0 && (A(e, "min", r.min), A(e, "max", r.max), A(e, "median", r.median), A(e, "mean", r.mean)), A(e, "measured", r.measured), A(e, "tiedAtMin", r.tiedAtMin), A(e, "normalization", On(n, "value"));
4110
+ }
4111
+ function Ft(t, e, n, r, s) {
4112
+ const i = vn(t, n);
4113
+ for (let o = 0; o < t.length; o++) {
4114
+ const a = K(t, n, o);
4115
+ Qe(a) && He(t, r, o, i.get(a));
4116
+ }
4117
+ A(e, s, i.size), A(e, "sizes", Ds(i));
4118
+ }
4119
+ function js(t, e) {
4120
+ Nn(t, "score", !1);
4121
+ const n = [...vn(t, "category").entries()].map(([r, s]) => ({
4122
+ category: String(r),
4123
+ count: s
4124
+ }));
4125
+ n.sort((r, s) => s.count - r.count || un(r.category, s.category)), A(e, "categories", Object.freeze(n.map((r) => Object.freeze(r))));
4126
+ }
4127
+ function ee(t, e) {
4128
+ let n = 0;
4129
+ for (let r = 0; r < t.length; r++)
4130
+ K(t, e, r) === !0 && n++;
4131
+ return n;
4132
+ }
4133
+ function Tt(t, e) {
4134
+ let n = 0;
4135
+ for (let r = 0; r < t.length; r++)
4136
+ K(t, e, r) !== void 0 && n++;
4137
+ return n;
4138
+ }
4139
+ function Us(t, e, n, r, s) {
4140
+ switch (t) {
4141
+ case "node-metric":
4142
+ _t(e, r, s);
4143
+ break;
4144
+ case "edge-metric":
4145
+ _t(n, r, s);
4146
+ break;
4147
+ case "community":
4148
+ Ft(e, r, "group", "groupSize", "groupCount");
4149
+ break;
4150
+ case "layered-grouping":
4151
+ Ft(e, r, "level", "levelSize", "levelCount");
4152
+ break;
4153
+ case "category-table":
4154
+ js(e, r);
4155
+ break;
4156
+ case "path":
4157
+ A(r, "length", ee(e, "onPath")), A(r, "hops", ee(n, "onPath"));
4158
+ break;
4159
+ case "node-set":
4160
+ A(r, "count", ee(e, "in"));
4161
+ break;
4162
+ case "edge-set":
4163
+ A(r, "count", ee(n, "in"));
4164
+ break;
4165
+ }
4166
+ }
4167
+ function Hs(t) {
4168
+ switch (t) {
4169
+ case "node-metric":
4170
+ case "edge-metric":
4171
+ return "value";
4172
+ case "category-table":
4173
+ return "score";
4174
+ case "layered-grouping":
4175
+ return "level";
4176
+ default:
4177
+ return null;
4178
+ }
4179
+ }
4180
+ function Bs(t, e, n) {
4181
+ if (!Array.isArray(t))
4182
+ return;
4183
+ const r = [];
4184
+ for (const s of t) {
4185
+ if (typeof s != "object" || s === null)
4186
+ continue;
4187
+ const i = s, o = i.group ?? i.category, a = i.size ?? i.count;
4188
+ if (Qe(o) && typeof a == "number" && r.push(Object.freeze(n ? { group: o, size: a, name: gs(r.length + 1) } : { group: o, size: a })), r.length === e)
4189
+ break;
4190
+ }
4191
+ return Object.freeze(r);
4192
+ }
4193
+ class et {
4194
+ #e;
4195
+ #t;
4196
+ #r;
4197
+ #n;
4198
+ #s;
4199
+ #c;
4200
+ #u = /* @__PURE__ */ new Map();
4201
+ /** Each ranked field's order, as positions: four bytes per ranked element. */
4202
+ #i = /* @__PURE__ */ new Map();
4203
+ #o = /* @__PURE__ */ new Map();
4204
+ #l;
4205
+ /**
4206
+ * Build a result around storage that has already been filled and frozen.
4207
+ * @param init - What the run published.
4208
+ * @param nodes - The published nodes.
4209
+ * @param edges - The published edges.
4210
+ * @param graph - The graph half, frozen.
4211
+ */
4212
+ constructor(e, n, r, s) {
4213
+ this.runId = e.runId, this.shape = e.shape, this.fields = Object.freeze([...e.fields]), this.measured = Object.freeze({ nodes: e.measured.nodes, edges: e.measured.edges }), this.graph = s, this.#e = n, this.#t = r, this.#r = e.caveats, this.#n = e.durationMs, this.#s = e.labelOf ?? (() => {
4214
+ }), this.#c = e.reading ?? Zr;
4215
+ }
4216
+ /**
4217
+ * One node's fields.
4218
+ * @param id - The node id.
4219
+ * @returns The fields, or undefined when the run produced nothing for that node.
4220
+ */
4221
+ node(e) {
4222
+ return Mt(this.#e, e);
4223
+ }
4224
+ /**
4225
+ * One edge's fields.
4226
+ * @param id - The edge id.
4227
+ * @returns The fields, or undefined when the run produced nothing for that edge.
4228
+ */
4229
+ edge(e) {
4230
+ return Mt(this.#t, e);
4231
+ }
4232
+ /**
4233
+ * One numeric field as a column.
4234
+ *
4235
+ * The view reads straight through to the result's own storage and its four figures were
4236
+ * computed on the first call, so a histogram, a colour ramp's domain and a summary all walk
4237
+ * one column rather than three copies of it.
4238
+ * @param field - The field name.
4239
+ * @returns A view over the values, without an object per element.
4240
+ * @throws A GraphtyError coded E_UNKNOWN_ATTRIBUTE when the run published no such field, or
4241
+ * E_BAD_COMMAND when the field is not a number published per element.
4242
+ */
4243
+ column(e) {
4244
+ return this.#f(e).view;
4245
+ }
4246
+ /**
4247
+ * The highest-ranked elements on one field.
4248
+ *
4249
+ * Elements with equal values share a rank and come back in printed-id order, so the top of a
4250
+ * ranking does not reshuffle between two runs that measured the same thing.
4251
+ * @param field - The field to rank on.
4252
+ * @param limit - How many entries to return; the whole ranking when absent.
4253
+ * @returns The entries, best first.
4254
+ * @throws A GraphtyError coded E_OPTION_RANGE when the limit is not a whole number of
4255
+ * entries, E_UNKNOWN_ATTRIBUTE when the run published no such field, or E_BAD_COMMAND when
4256
+ * the field is not a number published per element.
4257
+ */
4258
+ ranking(e, n) {
4259
+ n !== void 0 && this.#d(n, "limit");
4260
+ const r = this.#a(e), s = this.#p(e, r), i = D(r, e);
4261
+ return Ue(
4262
+ s,
4263
+ n ?? s.length,
4264
+ (o) => i.get(o),
4265
+ (o) => r.index.idOf(o)
4266
+ );
4267
+ }
4268
+ /**
4269
+ * The top `n` elements on one field, cut only between tie groups: a group of equal values is
4270
+ * taken whole, and only when all of it fits inside `n`. Kept per field and `n`, because a
4271
+ * top selector asks once per element it paints.
4272
+ * @param field - The field to rank on.
4273
+ * @param n - The most elements the top may hold.
4274
+ * @returns The elements taken, and the tie group left out when there was one.
4275
+ * @throws A GraphtyError coded E_OPTION_RANGE when n is not a whole number of entries,
4276
+ * E_UNKNOWN_ATTRIBUTE when the run published no such field, or E_BAD_COMMAND when the
4277
+ * field is not a number published per element.
4278
+ */
4279
+ top(e, n) {
4280
+ const r = `${String(n)}:${e}`, s = this.#o.get(r);
4281
+ if (s !== void 0)
4282
+ return s;
4283
+ const i = this.#d(n, "n"), o = this.#a(e), a = this.#p(e, o), u = D(o, e);
4284
+ let c = Math.min(i, a.length);
4285
+ if (c < a.length) {
4286
+ const d = u.get(a[c]);
4287
+ for (; c < a.length && u.get(a[c]) === d; )
4288
+ c++;
4289
+ }
4290
+ const l = $s(
4291
+ Ue(
4292
+ a,
4293
+ c,
4294
+ (d) => u.get(d),
4295
+ (d) => o.index.idOf(d)
4296
+ ),
4297
+ i
4298
+ );
4299
+ return this.#o.set(r, l), l;
4300
+ }
4301
+ /**
4302
+ * Refuse a count of entries that is not a whole number.
4303
+ * @param limit - The count.
4304
+ * @param option - What the caller called it, for the refusal.
4305
+ * @returns The count.
4306
+ * @throws A GraphtyError coded E_OPTION_RANGE when it is not a whole number of entries.
4307
+ */
4308
+ #d(e, n) {
4309
+ if (!Number.isInteger(e) || e < 0)
4310
+ throw new m({
4311
+ code: "E_OPTION_RANGE",
4312
+ source: "run",
4313
+ message: `A ranking limit is a whole number of entries, not ${String(e)}.`,
4314
+ details: { option: n, value: e, min: 0 },
4315
+ target: { kind: "run", id: this.runId }
4316
+ });
4317
+ return e;
4318
+ }
4319
+ /**
4320
+ * The distribution of one numeric field.
4321
+ *
4322
+ * Whether the field counts things is read off its own descriptor rather than passed in, so a
4323
+ * count metric gets whole-number band edges without the caller knowing that it should.
4324
+ * @param field - The field to bin.
4325
+ * @param options - How to cut the bins.
4326
+ * @returns The distribution, carrying the scale that was applied as well as the bars.
4327
+ * @throws A GraphtyError coded E_OPTION_RANGE when the bin count is outside the permitted
4328
+ * range, E_UNKNOWN_ATTRIBUTE when the run published no such field, or E_BAD_COMMAND when
4329
+ * the field is not a number published per element.
4330
+ */
4331
+ histogram(e, n) {
4332
+ const r = this.#h(e), s = r.kind === "edge" ? this.#t : this.#e;
4333
+ return Ps(D(s, e), {
4334
+ ...n,
4335
+ integerValued: r.type === "integer"
4336
+ });
4337
+ }
4338
+ /**
4339
+ * The bounded form of this result.
4340
+ *
4341
+ * Everything on it is either a single figure or a list the element cut to a fixed length, so
4342
+ * the object is the same size for a graph of a hundred nodes and a graph of a million.
4343
+ * @returns The summary.
4344
+ */
4345
+ summary() {
4346
+ return this.#l ??= this.#m(), this.#l;
4347
+ }
4348
+ /**
4349
+ * What this result means, in one sentence of plain language.
4350
+ * @param options - The locale and how technical to be.
4351
+ * @returns The sentence.
4352
+ */
4353
+ reading(e) {
4354
+ return this.#c(this, e ?? {});
4355
+ }
4356
+ /**
4357
+ * The descriptor of one numeric per-element field, without complaining when there is none.
4358
+ *
4359
+ * A summary asks this rather than {@link Result.#descriptorFor} because a summary must not
4360
+ * throw: a run whose field list does not declare the field its shape calls primary is a
4361
+ * defect in that run, and the summary's job is to say what it can about the result rather
4362
+ * than to refuse to describe it at all.
4363
+ * @param field - The field name.
4364
+ * @returns Its descriptor, or null when the run published no numeric field under that name.
4365
+ */
4366
+ #g(e) {
4367
+ const n = this.fields.find((r) => r.name === e && r.kind !== "graph");
4368
+ return n !== void 0 && Ae(n) ? n : null;
4369
+ }
4370
+ /**
4371
+ * The descriptor of one numeric field the run published per element.
4372
+ * @param field - The field name.
4373
+ * @returns Its descriptor.
4374
+ * @throws A GraphtyError naming what went wrong, with the readable fields in its details.
4375
+ */
4376
+ #h(e) {
4377
+ const n = this.fields.filter((i) => i.name === e), r = n.find((i) => i.kind !== "graph"), s = this.fields.filter((i) => i.kind !== "graph" && Ae(i)).map((i) => i.name);
4378
+ if (r === void 0)
4379
+ throw n.length > 0 ? new m({
4380
+ code: "E_BAD_COMMAND",
4381
+ source: "run",
4382
+ message: `"${e}" is a graph-level field of run "${this.runId}"; read it from result.graph.`,
4383
+ details: { field: e, kind: "graph", available: s },
4384
+ target: { kind: "run", id: this.runId }
4385
+ }) : new m({
4386
+ code: "E_UNKNOWN_ATTRIBUTE",
4387
+ source: "run",
4388
+ message: `Run "${this.runId}" published no field named "${e}".`,
4389
+ details: { field: e, available: s, candidates: bs(e, s) },
4390
+ target: { kind: "run", id: this.runId }
4391
+ });
4392
+ if (!Ae(r))
4393
+ throw new m({
4394
+ code: "E_BAD_COMMAND",
4395
+ source: "run",
4396
+ message: `"${e}" is typed "${r.type}", which is not a column of numbers.`,
4397
+ details: { field: e, type: r.type, available: s },
4398
+ target: { kind: "run", id: this.runId }
4399
+ });
4400
+ return r;
4401
+ }
4402
+ /**
4403
+ * The half of the result a per-element field belongs to.
4404
+ * @param field - The field name.
4405
+ * @returns The nodes or the edges.
4406
+ * @throws A GraphtyError naming what went wrong.
4407
+ */
4408
+ #a(e) {
4409
+ return this.#h(e).kind === "edge" ? this.#t : this.#e;
4410
+ }
4411
+ /**
4412
+ * One field's column and statistics, computed on the first ask and kept.
4413
+ * @param field - The field name.
4414
+ * @returns The view and the statistics behind it.
4415
+ * @throws A GraphtyError naming what went wrong.
4416
+ */
4417
+ #f(e) {
4418
+ const n = this.#u.get(e);
4419
+ if (n !== void 0)
4420
+ return n;
4421
+ const r = pn(D(this.#a(e), e));
4422
+ return this.#u.set(e, r), r;
4423
+ }
4424
+ /**
4425
+ * One field's ranking order, computed on the first ask and kept.
4426
+ * @param field - The field to rank on.
4427
+ * @param table - The half it belongs to.
4428
+ * @returns The ranked positions, best first.
4429
+ */
4430
+ #p(e, n) {
4431
+ let r = this.#i.get(e);
4432
+ return r === void 0 && (r = wn(n, e), this.#i.set(e, r)), r;
4433
+ }
4434
+ /**
4435
+ * What this result retains, in bytes: its columns and every cache it has built. Its id
4436
+ * indexes are not counted; see {@link retentionOf}.
4437
+ * @returns Bytes.
4438
+ */
4439
+ get byteSize() {
4440
+ let e = Ct(this.#e) + Ct(this.#t);
4441
+ for (const n of this.#i.values())
4442
+ e += n.byteLength;
4443
+ for (const n of this.#o.values())
4444
+ e += 64 * n.entries.length;
4445
+ return e;
4446
+ }
4447
+ /**
4448
+ * The id indexes this result reads through, for whoever charges for them.
4449
+ * @returns One per half that holds elements.
4450
+ */
4451
+ indexes() {
4452
+ return [this.#e, this.#t].filter((e) => e.length > 0).map((e) => ({ index: e.index, token: e.token, bytes: Ls(e.index) }));
4453
+ }
4454
+ /**
4455
+ * Read the nodes through a snapshot's id index instead of this result's own, when the two hold
4456
+ * the same ids in the same order.
4457
+ * @param index - The snapshot's node id index.
4458
+ * @param token - The graph token of that snapshot.
4459
+ */
4460
+ shareNodeIndex(e, n) {
4461
+ const r = this.#e;
4462
+ if (!(r.index instanceof mn) || e.size !== r.length)
4463
+ return;
4464
+ const { ids: s } = r.index;
4465
+ for (let i = 0; i < s.length; i++)
4466
+ if (e.idOf(i) !== s[i])
4467
+ return;
4468
+ r.index = e, r.token = n;
4469
+ }
4470
+ /**
4471
+ * Build the bounded form of this result.
4472
+ * @returns The summary.
4473
+ */
4474
+ #m() {
4475
+ const e = Hs(this.shape), n = e === null || this.#g(e) === null ? null : e, r = n === null ? null : this.#f(n).statistics, s = r !== null && r.measured > 0 ? r : null, i = n === null ? [] : this.ranking(n, xs).map(
4476
+ (c) => Object.freeze({
4477
+ id: c.id,
4478
+ label: this.#s(c.id) ?? String(c.id),
4479
+ value: c.value,
4480
+ rank: c.rank,
4481
+ percentile: c.percentile
4482
+ })
4483
+ ), o = {
4484
+ count: this.#y(),
4485
+ measured: r === null ? this.#w() : r.measured,
4486
+ min: s === null ? null : s.min,
4487
+ max: s === null ? null : s.max,
4488
+ median: s === null ? null : s.median,
4489
+ mean: s === null ? null : s.mean,
4490
+ tiedAtMin: r === null ? 0 : r.tiedAtMin,
4491
+ normalization: this.#b(n),
4492
+ top: Object.freeze(i),
4493
+ caveats: this.#r,
4494
+ durationMs: this.#n
4495
+ }, a = this.graph.sizes ?? this.graph.categories, u = Bs(a, zs, this.shape === "community");
4496
+ return Object.freeze(u === void 0 ? o : { ...o, groups: u });
4497
+ }
4498
+ /**
4499
+ * How many elements this result was computed over.
4500
+ *
4501
+ * A shape publishes per-element fields for nodes, for edges or for neither, and the scope a
4502
+ * summary reports is the half or halves it actually measures. A shape that publishes nothing
4503
+ * per element reports none, rather than borrowing the graph's size to look busy.
4504
+ * @returns The count.
4505
+ */
4506
+ #y() {
4507
+ const e = De(this.shape), n = e.nodeFields.length > 0 ? this.measured.nodes : 0, r = e.edgeFields.length > 0 ? this.measured.edges : 0;
4508
+ return n + r;
4509
+ }
4510
+ /**
4511
+ * How many elements carry the shape's primary field, for a shape that measures no number.
4512
+ * @returns The count.
4513
+ */
4514
+ #w() {
4515
+ const e = De(this.shape), { primaryField: n } = e;
4516
+ if (n === null)
4517
+ return 0;
4518
+ const r = e.nodeFields.includes(n) ? Tt(this.#e, n) : 0, s = e.edgeFields.includes(n) ? Tt(this.#t, n) : 0;
4519
+ return r + s;
4520
+ }
4521
+ /**
4522
+ * How this result's values were scaled.
4523
+ * @param valueField - The field a summary describes, or null when the shape measures no
4524
+ * number.
4525
+ * @returns The normalisation the run published, the one its field declares, or "none".
4526
+ */
4527
+ #b(e) {
4528
+ const n = this.graph.normalization;
4529
+ return hn(n) ? n : e === null ? "none" : On(this.fields, e);
4530
+ }
4531
+ }
4532
+ function Gs(t) {
4533
+ const e = $t(t.nodes), n = $t(t.edges), r = { ...t.graph };
4534
+ return Us(t.shape, e, n, r, t.fields), Rt(e), Rt(n), new et(t, e, n, Object.freeze(r));
4535
+ }
4536
+ function so(t) {
4537
+ return t instanceof et ? { bytes: t.byteSize, indexes: t.indexes() } : { bytes: 0, indexes: [] };
4538
+ }
4539
+ function io(t, e, n) {
4540
+ t instanceof et && t.shareNodeIndex(e, n);
4541
+ }
4542
+ const Vs = "Computed on the whole graph; values kept for the scope only.";
4543
+ function An(t) {
4544
+ const { graph: e, resolution: n } = t;
4545
+ return n.nodeCount === e.nodeCount && n.edgeCount === e.edgeCount;
4546
+ }
4547
+ function Be(t, e, n) {
4548
+ return e !== g && e < n && C(t, e);
4549
+ }
4550
+ function ke(t, e) {
4551
+ return `${String(t)} ${e}${t === 1 ? "" : "s"}`;
4552
+ }
4553
+ function Ws(t, e) {
4554
+ if (!t)
4555
+ return Vs;
4556
+ const { nodeCount: n, edgeCount: r } = e.resolution;
4557
+ return e.reading === "induced" ? `Computed on the induced subgraph of ${ke(n, "node")}.` : `Computed on the subgraph of ${ke(n, "node")} and the ${ke(r, "edge")} in scope.`;
4558
+ }
4559
+ function Ys(t, e) {
4560
+ const n = Mr(t);
4561
+ if (n === null || An(n))
4562
+ return e;
4563
+ const { graph: r, resolution: s } = n, i = (a) => Be(s.nodes, r.ids.indexOf(a.id), r.nodeCount), o = (a) => Be(s.edges, mr(r, a.id), r.edgeCount);
4564
+ return {
4565
+ ...e,
4566
+ ...e.nodes === void 0 ? {} : { nodes: e.nodes.filter(i) },
4567
+ ...e.edges === void 0 ? {} : { edges: e.edges.filter(o) },
4568
+ caveats: {
4569
+ ...e.caveats,
4570
+ notes: [...e.caveats.notes, Ws(Ze(t), n)]
4571
+ }
4572
+ };
4573
+ }
4574
+ function oo(t, e, n) {
4575
+ if (n === null || An(n))
4576
+ return;
4577
+ const { graph: r, resolution: s } = n;
4578
+ for (const i of t) {
4579
+ if (i.type !== "node-id" && i.type !== "node-set")
4580
+ continue;
4581
+ const o = e[i.name], a = Array.isArray(o) ? o : [o];
4582
+ for (const u of a) {
4583
+ if (typeof u != "string" && typeof u != "number")
4584
+ continue;
4585
+ const c = r.ids.indexOf(u);
4586
+ if (c !== g && !Be(s.nodes, c, r.nodeCount))
4587
+ throw new m({
4588
+ code: "E_OPTION_RANGE",
4589
+ message: `"${i.name}" names node "${String(u)}", which is outside the run's scope`,
4590
+ source: "run",
4591
+ details: { option: i.name, value: u, reason: "outside-scope" }
4592
+ });
4593
+ }
4594
+ }
4595
+ }
4596
+ function qs(t) {
4597
+ const e = t.styles?.config.data.knownFields.nodeLabelPath ?? null;
4598
+ if (e === null)
4599
+ return;
4600
+ const n = t.getDataManager();
4601
+ return (r) => {
4602
+ const s = n.getNode(r)?.data[e];
4603
+ return typeof s == "string" || typeof s == "number" ? String(s) : void 0;
4604
+ };
4605
+ }
4606
+ function ao(t) {
4607
+ return { exact: !0, precision: "f64", notes: [], ...t };
4608
+ }
4609
+ const Js = 1024, Ks = 16;
4610
+ function Zs() {
4611
+ return {
4612
+ input: () => {
4613
+ throw new Error("A detached run context reads no graph: call computeRun, which binds the input.");
4614
+ },
4615
+ signal: new AbortController().signal,
4616
+ report: () => {
4617
+ },
4618
+ yieldNow: () => new Promise((t) => {
4619
+ setTimeout(t, 0);
4620
+ })
4621
+ };
4622
+ }
4623
+ async function co(t, e, n, r) {
4624
+ const s = n.length;
4625
+ t.report({ phase: e, completed: 0, total: s });
4626
+ let i = performance.now();
4627
+ for (let o = 0; o < s; o++)
4628
+ o > 0 && o % Js === 0 && (t.signal.throwIfAborted(), t.report({ phase: e, completed: o, total: s }), performance.now() - i >= Ks && (await t.yieldNow(), i = performance.now())), r(n[o], o);
4629
+ t.signal.throwIfAborted(), t.report({ phase: e, completed: s, total: s });
4630
+ }
4631
+ function Xs(t, e, n) {
4632
+ const r = n?.find((i) => i.name === t.name && i.kind === t.kind), s = {
4633
+ name: t.name,
4634
+ plainName: r?.plainName ?? t.name,
4635
+ technicalName: r?.technicalName ?? t.name,
4636
+ kind: t.kind,
4637
+ type: t.type,
4638
+ path: ne(e, t.name),
4639
+ ...r?.unit === void 0 ? {} : { unit: r.unit }
4640
+ };
4641
+ return t.normalization === void 0 ? s : { ...s, normalization: t.normalization };
4642
+ }
4643
+ class uo extends Pe {
4644
+ /** What the last run published, kept so a caller holding the algorithm can read the result. */
4645
+ #e;
4646
+ /**
4647
+ * Fill in what the caller did not pass, and refuse what this algorithm does not declare.
4648
+ *
4649
+ * ONE DECLARATION, NOT TWO. `descriptor.options` is the only list a declared algorithm
4650
+ * writes, and this is what makes that true at the point the values reach the running code:
4651
+ * the same descriptors the catalogue hands a picker are what the caller's values are checked
4652
+ * against. The older `static optionsSchema` remains the answer for a class that declares no
4653
+ * descriptor, which is every algorithm the element itself ships.
4654
+ *
4655
+ * It also fixes the failure vocabulary on the way in. The older schema throws an uncoded
4656
+ * `Error` for a bad value and SILENTLY DROPS a name it does not know, where the run path
4657
+ * refuses the same name with `E_UNKNOWN_OPTION` -- so the same mistake produced three
4658
+ * different outcomes depending on which door the caller came through.
4659
+ * @param options - What the caller asked for.
4660
+ * @returns Every declared option, with the caller's values where they were given and the
4661
+ * declared defaults everywhere else.
4662
+ * @throws A `GraphtyError` with `E_UNKNOWN_OPTION` for a name this algorithm does not
4663
+ * declare, or `E_OPTION_RANGE` for a value it would not accept.
4664
+ */
4665
+ resolveOptions(e) {
4666
+ const { descriptor: n } = this.constructor;
4667
+ return n === void 0 ? super.resolveOptions(e) : _n(n.options, e ?? {}, {
4668
+ kind: "algorithm",
4669
+ id: n.key
4670
+ });
4671
+ }
4672
+ /**
4673
+ * What the last run published.
4674
+ *
4675
+ * THE REPLACEMENT FOR `algorithmResults`. The 1.x entry point used to scatter its numbers onto
4676
+ * the render objects under names it chose for itself, and the only way back to them was to
4677
+ * walk the graph. It returns a result object now, and this is where the 1.x `run()` leaves it,
4678
+ * so the old call shape still has somewhere to read from.
4679
+ * @returns The result, or undefined when nothing has run or there was nothing to compute.
4680
+ */
4681
+ get result() {
4682
+ return this.#e;
4683
+ }
4684
+ /**
4685
+ * Run the algorithm and publish what it produced on the 1.x result paths.
4686
+ *
4687
+ * The 1.x entry point: it returns nothing, and it publishes under the algorithm's own type
4688
+ * rather than under a run id, because there is no run behind it. Whoever wants the result
4689
+ * calls {@link DeclaredAlgorithm.computeRun}, which is the same work with a run in front of
4690
+ * it.
4691
+ * @returns A promise that settles when the result has been published.
4692
+ */
4693
+ async run() {
4694
+ await this.computeRun(Zs(), this.type);
4695
+ }
4696
+ /**
4697
+ * Compute on behalf of a run, and hand the result back.
4698
+ *
4699
+ * The run machinery's entry point, which is {@link DeclaredAlgorithm.computeRun} under the
4700
+ * name every algorithm answers to.
4701
+ * @param context - A signal, a progress channel and a yield.
4702
+ * @param runId - The id the result is published under.
4703
+ * @param fields - The catalogue's descriptors for this algorithm's fields.
4704
+ * @returns The result, or undefined when there was nothing to compute.
4705
+ * @throws Whatever the context's signal throws once the run has been cancelled.
4706
+ */
4707
+ publishResult(e, n, r) {
4708
+ return this.computeRun(e, n, r);
4709
+ }
4710
+ /**
4711
+ * Compute this algorithm's result, publish it under a run id, and project the 1.x view of it.
4712
+ *
4713
+ * This is what the run executor calls. The catalogue's own field descriptors are passed in
4714
+ * because the catalogue states what a reader sees a field called and cannot be imported here
4715
+ * without a cycle -- it reads these classes to publish their options.
4716
+ * @param context - What the element gave the run: a signal, a progress channel and a yield.
4717
+ * The graph the run computes over is bound here, as the context's `input`.
4718
+ * @param runId - The id the result is published under, which is the `<runId>` in
4719
+ * `results.<runId>`.
4720
+ * @param declared - The catalogue's descriptors for this algorithm's fields, when the caller
4721
+ * holds them.
4722
+ * @returns The result, or undefined when there was nothing to compute.
4723
+ * @throws Whatever the context's signal throws once the run has been cancelled, which is a
4724
+ * `DOMException` named `AbortError`.
4725
+ */
4726
+ async computeRun(e, n, r) {
4727
+ const s = Date.now(), i = {
4728
+ signal: e.signal,
4729
+ report: (l) => {
4730
+ e.report(l);
4731
+ },
4732
+ yieldNow: () => e.yieldNow(),
4733
+ input: (l, d) => this.input(l, d)
4734
+ }, o = await this.compute(i);
4735
+ if (o === null)
4736
+ return;
4737
+ const a = this.input("declared"), u = qs(this.graph), c = Gs(
4738
+ Ys(this, {
4739
+ ...u === void 0 ? {} : { labelOf: u },
4740
+ runId: n,
4741
+ shape: o.shape,
4742
+ fields: o.fields.map((l) => Xs(l, n, r)),
4743
+ measured: { nodes: a.nodeCount, edges: a.edgeCount },
4744
+ graph: o.graph,
4745
+ nodes: o.nodes,
4746
+ edges: o.edges,
4747
+ caveats: o.caveats,
4748
+ durationMs: Date.now() - s
4749
+ })
4750
+ );
4751
+ return this.#e = c, c;
4752
+ }
4753
+ }
4754
+ function lo(t, e = "number") {
4755
+ return [
4756
+ { name: "value", kind: t, type: e },
4757
+ { name: "rank", kind: t, type: "integer" },
4758
+ { name: "percentile", kind: t, type: "number" },
4759
+ { name: "min", kind: "graph", type: "number" },
4760
+ { name: "max", kind: "graph", type: "number" },
4761
+ { name: "median", kind: "graph", type: "number" },
4762
+ { name: "mean", kind: "graph", type: "number" },
4763
+ { name: "measured", kind: "graph", type: "integer" },
4764
+ { name: "normalization", kind: "graph", type: "string" },
4765
+ { name: "tiedAtMin", kind: "graph", type: "integer" }
4766
+ ];
4767
+ }
4768
+ const Pt = [
4769
+ { name: "group", kind: "node", type: "integer" },
4770
+ { name: "groupSize", kind: "node", type: "integer" },
4771
+ { name: "groupCount", kind: "graph", type: "integer" },
4772
+ { name: "sizes", kind: "graph", type: "table" }
4773
+ ];
4774
+ function ho(t) {
4775
+ return t ? [...Pt, { name: "modularity", kind: "graph", type: "number" }] : Pt;
4776
+ }
4777
+ const fo = [
4778
+ { name: "level", kind: "node", type: "integer" },
4779
+ { name: "levelSize", kind: "node", type: "integer" },
4780
+ { name: "levelCount", kind: "graph", type: "integer" },
4781
+ { name: "sizes", kind: "graph", type: "table" }
4782
+ ], po = [
4783
+ { name: "onPath", kind: "node", type: "boolean" },
4784
+ { name: "order", kind: "node", type: "integer" },
4785
+ { name: "onPath", kind: "edge", type: "boolean" },
4786
+ { name: "length", kind: "graph", type: "integer" },
4787
+ { name: "cost", kind: "graph", type: "number" },
4788
+ { name: "hops", kind: "graph", type: "integer" }
4789
+ ];
4790
+ function go(t, e) {
4791
+ return [
4792
+ { name: "in", kind: t, type: "boolean" },
4793
+ { name: "count", kind: "graph", type: "integer" },
4794
+ { ...e, kind: "graph" }
4795
+ ];
4796
+ }
4797
+ const Qs = `${Le}.${ps}`;
4798
+ function v(t) {
4799
+ return { ...t, path: `${Qs}.${t.name}` };
4800
+ }
4801
+ function kn(t, e) {
4802
+ return [
4803
+ v({
4804
+ name: "value",
4805
+ plainName: e.plainName,
4806
+ technicalName: e.technicalName,
4807
+ kind: t,
4808
+ type: e.type ?? "number",
4809
+ ...e.unit === void 0 ? {} : { unit: e.unit }
4810
+ }),
4811
+ v({ name: "rank", plainName: "Rank", technicalName: "rank", kind: t, type: "integer" }),
4812
+ v({ name: "percentile", plainName: "Percentile", technicalName: "percentile", kind: t, type: "number" }),
4813
+ v({ name: "min", plainName: "Lowest", technicalName: "min", kind: "graph", type: "number" }),
4814
+ v({ name: "max", plainName: "Highest", technicalName: "max", kind: "graph", type: "number" }),
4815
+ v({ name: "median", plainName: "Middle", technicalName: "median", kind: "graph", type: "number" }),
4816
+ v({ name: "mean", plainName: "Average", technicalName: "mean", kind: "graph", type: "number" }),
4817
+ v({
4818
+ name: "measured",
4819
+ plainName: "Measured",
4820
+ technicalName: "measured",
4821
+ kind: "graph",
4822
+ type: "integer"
4823
+ }),
4824
+ v({
4825
+ name: "normalization",
4826
+ plainName: "Normalization",
4827
+ technicalName: "normalization",
4828
+ kind: "graph",
4829
+ type: "string"
4830
+ }),
4831
+ v({
4832
+ name: "tiedAtMin",
4833
+ plainName: "Tied at the lowest value",
4834
+ technicalName: "tiedAtMin",
4835
+ kind: "graph",
4836
+ type: "integer"
4837
+ })
4838
+ ];
4839
+ }
4840
+ function mo(t) {
4841
+ return kn("node", t);
4842
+ }
4843
+ function yo(t) {
4844
+ return kn("edge", t);
4845
+ }
4846
+ function wo(t) {
4847
+ const { plainName: e } = t, n = [
4848
+ v({ name: "group", plainName: e, technicalName: t.technicalName, kind: "node", type: "integer" }),
4849
+ v({
4850
+ name: "groupSize",
4851
+ plainName: `${e} size`,
4852
+ technicalName: "groupSize",
4853
+ kind: "node",
4854
+ type: "integer"
4855
+ }),
4856
+ v({
4857
+ name: "groupCount",
4858
+ plainName: `${e} count`,
4859
+ technicalName: "groupCount",
4860
+ kind: "graph",
4861
+ type: "integer"
4862
+ }),
4863
+ v({
4864
+ name: "sizes",
4865
+ plainName: `${e} sizes`,
4866
+ technicalName: "sizes",
4867
+ kind: "graph",
4868
+ type: "table"
4869
+ })
4870
+ ];
4871
+ return t.modularity === !0 ? [
4872
+ ...n,
4873
+ v({
4874
+ name: "modularity",
4875
+ plainName: "Community strength",
4876
+ technicalName: "modularity",
4877
+ kind: "graph",
4878
+ type: "number"
4879
+ })
4880
+ ] : n;
4881
+ }
4882
+ export {
4883
+ ci as $,
4884
+ Pe as A,
4885
+ Le as B,
4886
+ Xe as C,
4887
+ gi as D,
4888
+ Zr as E,
4889
+ pi as F,
4890
+ hs as G,
4891
+ ne as H,
4892
+ qt as I,
4893
+ ar as J,
4894
+ rr as K,
4895
+ fo as L,
4896
+ Gt as M,
4897
+ pr as N,
4898
+ k as O,
4899
+ po as P,
4900
+ gr as Q,
4901
+ Zi as R,
4902
+ Un as S,
4903
+ H as T,
4904
+ Ei as U,
4905
+ di as V,
4906
+ jn as W,
4907
+ ct as X,
4908
+ Ks as Y,
4909
+ xn as Z,
4910
+ hi as _,
4911
+ uo as a,
4912
+ Ai as a0,
4913
+ Di as a1,
4914
+ ji as a2,
4915
+ qs as a3,
4916
+ Gs as a4,
4917
+ Ys as a5,
4918
+ S as a6,
4919
+ Lt as a7,
4920
+ Gi as a8,
4921
+ oo as a9,
4922
+ wr as aA,
4923
+ Or as aB,
4924
+ Fi as aC,
4925
+ nn as aD,
4926
+ Li as aE,
4927
+ zi as aF,
4928
+ $s as aG,
4929
+ ro as aH,
4930
+ fn as aI,
4931
+ no as aJ,
4932
+ Pi as aK,
4933
+ Ki as aL,
4934
+ Vi as aM,
4935
+ De as aN,
4936
+ mr as aO,
4937
+ un as aP,
4938
+ bs as aQ,
4939
+ Ji as aR,
4940
+ qi as aS,
4941
+ Yi as aT,
4942
+ Wi as aU,
4943
+ gs as aV,
4944
+ Xi as aW,
4945
+ to as aX,
4946
+ io as aY,
4947
+ eo as aZ,
4948
+ Hi as aa,
4949
+ Ti as ab,
4950
+ zn as ac,
4951
+ Ui as ad,
4952
+ yi as ae,
4953
+ mi as af,
4954
+ bi as ag,
4955
+ wi as ah,
4956
+ Ie as ai,
4957
+ Mi as aj,
4958
+ Ke as ak,
4959
+ en as al,
4960
+ Me as am,
4961
+ Ci as an,
4962
+ _i as ao,
4963
+ $i as ap,
4964
+ Ri as aq,
4965
+ xe as ar,
4966
+ P as as,
4967
+ b as at,
4968
+ so as au,
4969
+ zt as av,
4970
+ Ce as aw,
4971
+ X as ax,
4972
+ yr as ay,
4973
+ xi as az,
4974
+ Se as b,
4975
+ li as c,
4976
+ Qi as d,
4977
+ Ii as e,
4978
+ ki as f,
4979
+ ui as g,
4980
+ ho as h,
4981
+ wo as i,
4982
+ ao as j,
4983
+ Bi as k,
4984
+ yo as l,
4985
+ co as m,
4986
+ v as n,
4987
+ lo as o,
4988
+ mo as p,
4989
+ vi as q,
4990
+ Oi as r,
4991
+ Si as s,
4992
+ Ni as t,
4993
+ ai as u,
4994
+ Lr as v,
4995
+ go as w,
4996
+ xr as x,
4997
+ Vn as y,
4998
+ fi as z
4999
+ };