@pilates/core 1.0.1 → 2.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 (77) hide show
  1. package/dist/algorithm/cache.d.ts +7 -19
  2. package/dist/algorithm/cache.d.ts.map +1 -1
  3. package/dist/algorithm/cache.js +31 -27
  4. package/dist/algorithm/cache.js.map +1 -1
  5. package/dist/algorithm/index.d.ts +31 -0
  6. package/dist/algorithm/index.d.ts.map +1 -1
  7. package/dist/algorithm/index.js +105 -13
  8. package/dist/algorithm/index.js.map +1 -1
  9. package/dist/algorithm/round.d.ts +13 -0
  10. package/dist/algorithm/round.d.ts.map +1 -1
  11. package/dist/algorithm/round.js +33 -16
  12. package/dist/algorithm/round.js.map +1 -1
  13. package/dist/algorithm/spineless/classify.d.ts +47 -0
  14. package/dist/algorithm/spineless/classify.d.ts.map +1 -0
  15. package/dist/algorithm/spineless/classify.js +109 -0
  16. package/dist/algorithm/spineless/classify.js.map +1 -0
  17. package/dist/algorithm/spineless/field-id-pool.d.ts +28 -0
  18. package/dist/algorithm/spineless/field-id-pool.d.ts.map +1 -0
  19. package/dist/algorithm/spineless/field-id-pool.js +35 -0
  20. package/dist/algorithm/spineless/field-id-pool.js.map +1 -0
  21. package/dist/algorithm/spineless/flex-grammar.d.ts +394 -0
  22. package/dist/algorithm/spineless/flex-grammar.d.ts.map +1 -0
  23. package/dist/algorithm/spineless/flex-grammar.js +2509 -0
  24. package/dist/algorithm/spineless/flex-grammar.js.map +1 -0
  25. package/dist/algorithm/spineless/grammar.d.ts +156 -0
  26. package/dist/algorithm/spineless/grammar.d.ts.map +1 -0
  27. package/dist/algorithm/spineless/grammar.js +145 -0
  28. package/dist/algorithm/spineless/grammar.js.map +1 -0
  29. package/dist/algorithm/spineless/layout.d.ts +167 -0
  30. package/dist/algorithm/spineless/layout.d.ts.map +1 -0
  31. package/dist/algorithm/spineless/layout.js +893 -0
  32. package/dist/algorithm/spineless/layout.js.map +1 -0
  33. package/dist/algorithm/spineless/order-maintenance.bench.d.ts +25 -0
  34. package/dist/algorithm/spineless/order-maintenance.bench.d.ts.map +1 -0
  35. package/dist/algorithm/spineless/order-maintenance.bench.js +78 -0
  36. package/dist/algorithm/spineless/order-maintenance.bench.js.map +1 -0
  37. package/dist/algorithm/spineless/order-maintenance.d.ts +201 -0
  38. package/dist/algorithm/spineless/order-maintenance.d.ts.map +1 -0
  39. package/dist/algorithm/spineless/order-maintenance.js +300 -0
  40. package/dist/algorithm/spineless/order-maintenance.js.map +1 -0
  41. package/dist/algorithm/spineless/priority-queue.bench.d.ts +17 -0
  42. package/dist/algorithm/spineless/priority-queue.bench.d.ts.map +1 -0
  43. package/dist/algorithm/spineless/priority-queue.bench.js +57 -0
  44. package/dist/algorithm/spineless/priority-queue.bench.js.map +1 -0
  45. package/dist/algorithm/spineless/priority-queue.d.ts +73 -0
  46. package/dist/algorithm/spineless/priority-queue.d.ts.map +1 -0
  47. package/dist/algorithm/spineless/priority-queue.js +149 -0
  48. package/dist/algorithm/spineless/priority-queue.js.map +1 -0
  49. package/dist/algorithm/spineless/runtime.d.ts +292 -0
  50. package/dist/algorithm/spineless/runtime.d.ts.map +1 -0
  51. package/dist/algorithm/spineless/runtime.js +609 -0
  52. package/dist/algorithm/spineless/runtime.js.map +1 -0
  53. package/dist/algorithm/spineless/style-dirty.d.ts +65 -0
  54. package/dist/algorithm/spineless/style-dirty.d.ts.map +1 -0
  55. package/dist/algorithm/spineless/style-dirty.js +75 -0
  56. package/dist/algorithm/spineless/style-dirty.js.map +1 -0
  57. package/dist/dirty-flags.d.ts +30 -0
  58. package/dist/dirty-flags.d.ts.map +1 -0
  59. package/dist/dirty-flags.js +35 -0
  60. package/dist/dirty-flags.js.map +1 -0
  61. package/dist/index.d.ts +4 -1
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +9 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/inspect.d.ts +27 -0
  66. package/dist/inspect.d.ts.map +1 -0
  67. package/dist/inspect.js +61 -0
  68. package/dist/inspect.js.map +1 -0
  69. package/dist/layout-pool.d.ts +49 -0
  70. package/dist/layout-pool.d.ts.map +1 -0
  71. package/dist/layout-pool.js +75 -0
  72. package/dist/layout-pool.js.map +1 -0
  73. package/dist/node.d.ts +20 -3
  74. package/dist/node.d.ts.map +1 -1
  75. package/dist/node.js +63 -42
  76. package/dist/node.js.map +1 -1
  77. package/package.json +1 -1
@@ -0,0 +1,609 @@
1
+ /**
2
+ * Spineless Traversal runtime — incremental driver for an attribute
3
+ * grammar (Kirisame, Wang, Panchekha — PLDI 2025).
4
+ *
5
+ * Combines the three foundational primitives:
6
+ * - `BenderOrderMaintenance` (OM) — assigns a stable, totally-
7
+ * ordered timestamp to every field at first computation. Topo
8
+ * order at init time => OM order forever, even after relabel.
9
+ * - `OmPriorityQueue<Field>` — keyed on the field's OM node.
10
+ * Popping the minimum returns the next field to recompute in
11
+ * topological order, without any explicit DAG walks.
12
+ * - `Grammar` — declarative `field -> rule(deps, compute)` map.
13
+ * The runtime queries it on every recompute.
14
+ *
15
+ * ## Phases
16
+ *
17
+ * **Init** (`init()`): one full pass over the grammar from the
18
+ * supplied root fields. DFS in topological order; for each field,
19
+ * allocate an OM node (`om.insertAfter(prev)`), record the
20
+ * reverse-deps edges so dependents can be scheduled later, then run
21
+ * the field's compute and cache the value. After init, every
22
+ * reachable field has a (timestamp, value, dependents-list) triple
23
+ * in the runtime's storage.
24
+ *
25
+ * **Recompute** (`markDirty(field)` + `recompute()`): callers mark
26
+ * the fields whose inputs changed. Each dirty field is enqueued
27
+ * (`pq.push(field, omNode)`). `recompute()` loops: pop the
28
+ * OM-minimum field, re-run its rule. If the new value differs from
29
+ * the cached one, persist it and push every dependent. Process
30
+ * stops when the queue is empty.
31
+ *
32
+ * **Termination** rests on the dependency graph being acyclic: each
33
+ * field's value is a function of finitely many others, so the
34
+ * worklist reaches the DAG's unique fixpoint in finitely many
35
+ * steps. When the OM order is a true topological order — as it is
36
+ * after `init` and pure-additive `graft` — every field recomputes
37
+ * exactly once (a dependent always pops after its deps), giving the
38
+ * O(affected) Spineless bound. After a `rebindRule` an existing
39
+ * field may gain a dependency on a later-OM field; recompute stays
40
+ * correct and terminating, but such a field may recompute a bounded
41
+ * number of extra times. OM order is thus a performance property,
42
+ * not a correctness one.
43
+ *
44
+ * **Value preservation under no-op recompute:** if a field's rule
45
+ * produces the same value as before, its dependents are NOT
46
+ * scheduled. This is the key "skip work" property of Spineless.
47
+ *
48
+ * **Graft** (`graft(additions, newRoots)`): incremental structural
49
+ * growth (phase 5c). New fields whose topological position is at the
50
+ * tail — they may read existing fields, but no existing field reads
51
+ * them and no existing rule changes — are spliced in without a
52
+ * rebuild: each gets an OM node appended after the current tail, its
53
+ * reverse-dependency edges recorded, and its value computed once.
54
+ * This is exactly the shape of appending a child to a parent in the
55
+ * "simple" regime.
56
+ *
57
+ * **Detach** (`detach(fields)`): the inverse of `graft` — drops a
58
+ * removed subtree's fields, freeing their OM nodes and pruning the
59
+ * reverse-dependency edges into surviving fields. Valid when the
60
+ * removed set is closed under "is read by" (nothing outside reads
61
+ * in), which holds for removing a last child in the simple regime.
62
+ * Surviving leaf-input fields the removed set was the sole reader of
63
+ * are dropped too — the caller passes only the subtree's own fields.
64
+ *
65
+ * **Rebind** (`rebindRule(field, newRule)`): replace an existing
66
+ * field's rule — used when a structural change rewrites a surviving
67
+ * field (e.g. appending into a flex-distributing parent grows every
68
+ * sibling's flex-distribution dependency set). The reverse-
69
+ * dependency edges are updated to the new dep set and the field is
70
+ * marked dirty. New deps may have a later OM than the field — see
71
+ * the termination note above.
72
+ *
73
+ * ## What this runtime does NOT cover
74
+ *
75
+ * - Regime-changing structural mutation. `graft` only adds pure
76
+ * topological-tail fields; appending into a flex-distributing /
77
+ * justified / wrapping parent also rewrites existing siblings'
78
+ * rules, and removal / direction flips re-key subtrees — later
79
+ * phase-5c slices.
80
+ * - Differential mode against the imperative algorithm. The
81
+ * correctness oracle for the runtime is the `TopoInterpreter`
82
+ * running over the same grammar — once both agree, the grammar's
83
+ * existing differential coverage carries through.
84
+ *
85
+ * @internal
86
+ */
87
+ import { fieldIdCount } from './field-id-pool.js';
88
+ import { BenderOrderMaintenance } from './order-maintenance.js';
89
+ import { OmPriorityQueue } from './priority-queue.js';
90
+ /**
91
+ * A `ReadFn` for zero-dependency rules — they declare no deps, so their
92
+ * `compute` must never call `read`. If one does, this throws (a grammar
93
+ * bug), mirroring the undeclared-dependency error in the normal path.
94
+ */
95
+ const NEVER_READ = (dep) => {
96
+ throw new Error(`[spineless-runtime] a zero-dependency rule called read("${dep.name}") — it did not declare it as a dependency`);
97
+ };
98
+ /**
99
+ * Cache of the declared-deps Set for each rule. Keyed by the rule object
100
+ * (FieldRule is immutable after creation); when a rule is replaced via
101
+ * `rebindRule`, the new rule object gets a fresh WeakMap miss — no manual
102
+ * invalidation needed.
103
+ */
104
+ const depSetCache = new WeakMap();
105
+ /**
106
+ * @internal
107
+ */
108
+ export class SpinelessRuntime {
109
+ rootFields;
110
+ om;
111
+ pq;
112
+ /**
113
+ * External Grammar map reference — kept so that callers holding the
114
+ * same map reference (e.g. layout.ts's `output.grammar`) see mutations
115
+ * made by `graft` / `rebindRule` / `detach`. All internal HOT-PATH
116
+ * reads use `rulesArr` (O(1) array index) instead.
117
+ */
118
+ grammar;
119
+ /**
120
+ * Field rules indexed by field.id — the fast-path mirror of `grammar`.
121
+ * Updated in lockstep with every `grammar.set` / `grammar.delete`.
122
+ * Plain array; auto-grows on out-of-range assignment (JS semantics).
123
+ */
124
+ rulesArr = [];
125
+ /**
126
+ * Fast path: numeric field values indexed by field.id.
127
+ * valuePresent[id] === 1 means the value is stored here as a number.
128
+ */
129
+ valuesArr;
130
+ /**
131
+ * Presence / storage-kind bitset, indexed by field.id:
132
+ * 0 = absent (not yet computed or detached)
133
+ * 1 = computed, value is a number stored in valuesArr[id]
134
+ * 2 = computed, value is a non-number object stored in valuesMap
135
+ */
136
+ valuePresent;
137
+ /**
138
+ * Fallback for non-number field values (e.g. Field<MainAxisDistribution>).
139
+ * Only populated when valuePresent[id] === 2.
140
+ */
141
+ valuesMap = new Map();
142
+ /**
143
+ * OM nodes indexed by field.id — replaces the former `omNodes: Map<Field, OMNode>`.
144
+ * Plain array; auto-grows on out-of-range assignment (JS semantics).
145
+ * undefined slot = field not integrated (or detached).
146
+ */
147
+ omNodesArr = [];
148
+ /**
149
+ * Authoritative list of all fields ever registered with this runtime
150
+ * (in integration order). Used for iteration in `markAllDirty` — slots
151
+ * whose `omNodesArr[field.id]` is `undefined` (detached) are skipped.
152
+ * Dead entries are never removed; the skip is O(1) per slot.
153
+ */
154
+ fieldRoster = [];
155
+ /**
156
+ * Reverse-dependency lists indexed by field.id — replaces the former
157
+ * `dependents: Map<Field, Field[]>`. `dependentsArr[id]` is the array
158
+ * of fields that read field-id. undefined = no dependents recorded yet
159
+ * (or field detached). Plain array; auto-grows on assignment.
160
+ */
161
+ dependentsArr = [];
162
+ /** The OM node at the topological tail — where `graft` appends. */
163
+ lastOm = null;
164
+ initDone = false;
165
+ /**
166
+ * Recompute counters — for observability (phase 9). Plain integer
167
+ * fields, bumped on the existing `integrate` / `recompute` loops,
168
+ * so they cost nothing measurable and need no enable flag.
169
+ */
170
+ stats = {
171
+ /** Fields integrated so far — the `init` pass plus every `graft`. */
172
+ initFields: 0,
173
+ /** Fields popped from the PQ by the most recent `recompute()`. */
174
+ recomputeVisited: 0,
175
+ /** Of those, Fields whose value actually changed. */
176
+ recomputeChanged: 0,
177
+ /** Cumulative Fields visited across every `recompute()` since init. */
178
+ totalVisited: 0,
179
+ };
180
+ constructor(grammar, rootFields, om = new BenderOrderMaintenance()) {
181
+ this.grammar = grammar;
182
+ this.rootFields = rootFields;
183
+ this.om = om;
184
+ this.pq = new OmPriorityQueue(om);
185
+ // Mirror the public Grammar map into rulesArr (indexed by field.id)
186
+ // so the hot path can do O(1) array reads instead of Map lookups.
187
+ for (const [f, rule] of grammar) {
188
+ this.rulesArr[f.id] = rule;
189
+ }
190
+ // Initialise value arrays to cover all IDs allocated so far.
191
+ // ensureFieldCapacity() grows them on demand as new fields arrive.
192
+ const initialCap = Math.max(fieldIdCount(), 1024);
193
+ this.valuesArr = new Float64Array(initialCap);
194
+ this.valuePresent = new Uint8Array(initialCap);
195
+ }
196
+ /**
197
+ * Grow `valuesArr` and `valuePresent` so that `id` is a valid index.
198
+ * Doubles capacity until sufficient, copying forward (LayoutPool pattern).
199
+ */
200
+ ensureFieldCapacity(id) {
201
+ if (id < this.valuesArr.length)
202
+ return;
203
+ let cap = this.valuesArr.length;
204
+ while (id >= cap)
205
+ cap *= 2;
206
+ const newArr = new Float64Array(cap);
207
+ const newPresent = new Uint8Array(cap);
208
+ newArr.set(this.valuesArr);
209
+ newPresent.set(this.valuePresent);
210
+ this.valuesArr = newArr;
211
+ this.valuePresent = newPresent;
212
+ }
213
+ /**
214
+ * Walk the grammar in topological order, allocate an OM node per
215
+ * field, cache initial values, and record reverse-dependents. Must
216
+ * be called once before any `evaluate` / `markDirty` / `recompute`.
217
+ */
218
+ init() {
219
+ this.integrate(this.rootFields);
220
+ this.initDone = true;
221
+ }
222
+ /**
223
+ * Integrate new fields into an already-`init`ed runtime without a
224
+ * rebuild (phase 5c). `additions` holds the rules for the new
225
+ * fields only — it throws if any field is already present, since
226
+ * redefining an existing field is a rule *change*, not a graft.
227
+ * `newRoots` are the new fields to start the topological DFS from
228
+ * (their existing-field dependencies are reached as boundaries).
229
+ *
230
+ * Correct **iff** the new fields are pure topological-tail
231
+ * additions: no existing field reads a new field, and no existing
232
+ * rule needed to change. The caller guarantees this — it holds by
233
+ * construction when appending a last child to a parent in the
234
+ * simple regime (no flex distribution, default `justify`, no
235
+ * wrap). The new fields are computed with correct inputs during
236
+ * the graft, so no `markDirty` / `recompute` is needed afterward.
237
+ */
238
+ graft(additions, newRoots) {
239
+ if (!this.initDone) {
240
+ throw new Error('[spineless-runtime] graft called before init()');
241
+ }
242
+ for (const [f, rule] of additions) {
243
+ if (this.omNodesArr[f.id] !== undefined) {
244
+ throw new Error(`[spineless-runtime] graft: field "${f.name}" already exists — graft integrates NEW fields only`);
245
+ }
246
+ this.rulesArr[f.id] = rule;
247
+ this.grammar.set(f, rule);
248
+ }
249
+ this.integrate(newRoots);
250
+ }
251
+ /**
252
+ * Remove fields from an already-`init`ed runtime without a rebuild
253
+ * (phase 5c) — the inverse of `graft`. `fields` is the exact set
254
+ * to drop (a removed subtree's fields). For each: its OM node is
255
+ * freed, its cached value and reverse-dependency list dropped, its
256
+ * rule deleted from the grammar, and it is pruned from the
257
+ * reverse-dependency list of every field it read.
258
+ *
259
+ * Throws if any removed field still has a dependent *outside* the
260
+ * removed set — detaching it would dangle that edge. The caller
261
+ * guarantees a clean cut: it holds by construction when removing a
262
+ * last child from a parent in the simple regime (nothing outside
263
+ * that subtree reads into it). No `recompute` is needed afterward —
264
+ * removing a topological-tail subtree changes no surviving field.
265
+ *
266
+ * After the cut, any surviving leaf-input field the removed set was
267
+ * the sole reader of is **orphaned** — nothing reads it and the
268
+ * grammar cannot re-read it without a fresh build. Such orphans are
269
+ * dropped too (a leaf has no dependencies, so this cannot cascade).
270
+ * That makes the caller's removed set just the subtree's own
271
+ * fields — orphan input fields, e.g. the previous last child's
272
+ * now-unread main-end margin, need not be enumerated.
273
+ *
274
+ * @returns The set of every field actually removed — both the
275
+ * explicit `fields` argument AND any orphan-cleaned surviving deps.
276
+ * Callers can use this to maintain a `Set<Field>` index in O(|dropped|)
277
+ * rather than scanning all tracked fields.
278
+ */
279
+ detach(fields) {
280
+ if (!this.initDone) {
281
+ throw new Error('[spineless-runtime] detach called before init()');
282
+ }
283
+ const removing = new Set(fields);
284
+ // Precondition: the removed set must be closed under "is read by"
285
+ // — no surviving field may depend on a removed one.
286
+ for (const f of removing) {
287
+ const revs = this.dependentsArr[f.id];
288
+ if (revs === undefined)
289
+ continue;
290
+ for (const d of revs) {
291
+ if (!removing.has(d)) {
292
+ throw new Error(`[spineless-runtime] detach: field "${f.name}" still has dependent "${d.name}" outside the removed set`);
293
+ }
294
+ }
295
+ }
296
+ // Surviving fields the removed set read — candidates for orphan
297
+ // cleanup once their reverse-dependency lists are pruned.
298
+ const survivingDeps = new Set();
299
+ const dropped = new Set();
300
+ const removedOmNodes = new Set();
301
+ const drop = (f) => {
302
+ dropped.add(f);
303
+ const omNode = this.omNodesArr[f.id];
304
+ if (omNode !== undefined) {
305
+ this.om.delete(omNode);
306
+ removedOmNodes.add(omNode);
307
+ }
308
+ this.omNodesArr[f.id] = undefined;
309
+ if (f.id < this.valuePresent.length && this.valuePresent[f.id] === 2) {
310
+ this.valuesMap.delete(f);
311
+ }
312
+ this.valuePresent[f.id] = 0;
313
+ this.dependentsArr[f.id] = undefined;
314
+ this.rulesArr[f.id] = undefined;
315
+ this.grammar.delete(f);
316
+ };
317
+ for (const f of removing) {
318
+ // Prune `f` from the reverse-dependency list of each field it
319
+ // read (a surviving dep must forget this removed dependent).
320
+ const rule = this.rulesArr[f.id];
321
+ if (rule !== undefined) {
322
+ for (const dep of rule.deps) {
323
+ const revs = this.dependentsArr[dep.id];
324
+ if (revs !== undefined) {
325
+ const i = revs.indexOf(f);
326
+ if (i !== -1)
327
+ revs.splice(i, 1);
328
+ }
329
+ if (!removing.has(dep))
330
+ survivingDeps.add(dep);
331
+ }
332
+ }
333
+ drop(f);
334
+ }
335
+ // Orphan cleanup: a surviving dep with no dependents left, whose
336
+ // own rule is a leaf (no dependencies), is now dead weight.
337
+ for (const dep of survivingDeps) {
338
+ const revs = this.dependentsArr[dep.id];
339
+ if (revs !== undefined && revs.length > 0)
340
+ continue;
341
+ const rule = this.rulesArr[dep.id];
342
+ if (rule === undefined || rule.deps.length > 0)
343
+ continue;
344
+ drop(dep);
345
+ }
346
+ // The OM tail may have been among the removed fields. If so, walk
347
+ // back through predecessors (skipping just-removed nodes) to find
348
+ // the new tail — O(removed) instead of O(total live nodes).
349
+ if (this.lastOm !== null && removedOmNodes.has(this.lastOm)) {
350
+ let candidate = this.lastOm;
351
+ while (candidate !== null && removedOmNodes.has(candidate)) {
352
+ candidate = this.om.predecessor(candidate);
353
+ }
354
+ this.lastOm = candidate;
355
+ }
356
+ return dropped;
357
+ }
358
+ /**
359
+ * Replace the rule of an already-integrated field (phase 5c) — for
360
+ * a structural change that rewrites a *surviving* field rather than
361
+ * adding or removing one. Appending a child into a flex-distributing
362
+ * parent, for instance, grows every existing sibling's
363
+ * flex-distribution dependency set.
364
+ *
365
+ * The reverse-dependency edges are repaired to match the new dep
366
+ * set (the field is dropped from the lists of deps it no longer
367
+ * reads and added to the lists of deps it now reads), the new rule
368
+ * is installed, and the field is marked dirty so the next
369
+ * `recompute()` re-runs it. Every new dependency must already be
370
+ * integrated. The field keeps its OM node; if a new dependency has
371
+ * a later OM, recompute stays correct (see the termination note on
372
+ * the class) at the cost of a bounded number of extra recomputes.
373
+ */
374
+ rebindRule(field, newRule) {
375
+ if (!this.initDone) {
376
+ throw new Error('[spineless-runtime] rebindRule called before init()');
377
+ }
378
+ if (this.omNodesArr[field.id] === undefined) {
379
+ throw new Error(`[spineless-runtime] rebindRule: field "${field.name}" is not in this runtime`);
380
+ }
381
+ const oldRule = this.rulesArr[field.id];
382
+ const oldDeps = new Set(oldRule?.deps ?? []);
383
+ const newDeps = new Set(newRule.deps);
384
+ // Deps no longer read: drop `field` from their dependents list.
385
+ for (const d of oldDeps) {
386
+ if (newDeps.has(d))
387
+ continue;
388
+ const revs = this.dependentsArr[d.id];
389
+ if (revs !== undefined) {
390
+ const i = revs.indexOf(field);
391
+ if (i !== -1)
392
+ revs.splice(i, 1);
393
+ }
394
+ }
395
+ // Newly read deps: register the reverse edge.
396
+ for (const d of newDeps) {
397
+ if (oldDeps.has(d))
398
+ continue;
399
+ if (this.omNodesArr[d.id] === undefined) {
400
+ throw new Error(`[spineless-runtime] rebindRule: new dependency "${d.name}" of "${field.name}" is not integrated`);
401
+ }
402
+ let revs = this.dependentsArr[d.id];
403
+ if (revs === undefined) {
404
+ revs = [];
405
+ this.dependentsArr[d.id] = revs;
406
+ }
407
+ revs.push(field);
408
+ }
409
+ this.rulesArr[field.id] = newRule;
410
+ this.grammar.set(field, newRule);
411
+ this.markDirty(field);
412
+ }
413
+ /**
414
+ * Topological DFS shared by `init` and `graft`. For every
415
+ * not-yet-integrated field reachable from `roots`: recurse into
416
+ * deps, record reverse-dependency edges, allocate an OM node after
417
+ * the current tail, run the rule, and cache the value. Fields that
418
+ * already have an OM node are boundaries — visited, edge recorded,
419
+ * not re-walked.
420
+ */
421
+ integrate(roots) {
422
+ const visiting = new Set();
423
+ const visit = (f) => {
424
+ // A field has an OM node exactly once it is integrated, so
425
+ // the omNodesArr slot doubles as the "already done" marker — which
426
+ // makes existing fields natural boundaries during a graft.
427
+ if (this.omNodesArr[f.id] !== undefined)
428
+ return;
429
+ if (visiting.has(f)) {
430
+ throw new Error(`[spineless-runtime] cycle detected: field "${f.name}" depends on itself transitively`);
431
+ }
432
+ visiting.add(f);
433
+ const rule = this.rulesArr[f.id];
434
+ if (rule === undefined) {
435
+ throw new Error(`[spineless-runtime] no rule for field "${f.name}". Register it in the grammar or remove the dep edge.`);
436
+ }
437
+ for (const dep of rule.deps) {
438
+ visit(dep);
439
+ let revs = this.dependentsArr[dep.id];
440
+ if (revs === undefined) {
441
+ revs = [];
442
+ this.dependentsArr[dep.id] = revs;
443
+ }
444
+ revs.push(f);
445
+ }
446
+ // Allocate the OM node at the topological tail. The OM is empty
447
+ // before the very first field, then chains insertAfter.
448
+ const omNode = this.lastOm === null ? this.om.init() : this.om.insertAfter(this.lastOm);
449
+ this.lastOm = omNode;
450
+ this.omNodesArr[f.id] = omNode;
451
+ this.fieldRoster.push(f);
452
+ this.stats.initFields++;
453
+ // Compute and cache.
454
+ this.ensureFieldCapacity(f.id);
455
+ const initVal = this.runCompute(f, rule);
456
+ if (typeof initVal === 'number') {
457
+ this.valuesArr[f.id] = initVal;
458
+ this.valuePresent[f.id] = 1;
459
+ }
460
+ else {
461
+ this.valuesMap.set(f, initVal);
462
+ this.valuePresent[f.id] = 2;
463
+ }
464
+ visiting.delete(f);
465
+ };
466
+ for (const root of roots)
467
+ visit(root);
468
+ }
469
+ /**
470
+ * Read the current cached value of a field. Throws if the field
471
+ * wasn't reachable from any root during `init` (so no cache entry
472
+ * exists).
473
+ */
474
+ evaluate(field) {
475
+ const id = field.id;
476
+ const kind = id < this.valuePresent.length ? this.valuePresent[id] : 0;
477
+ if (kind === 0) {
478
+ throw new Error(`[spineless-runtime] field "${field.name}" was not computed in init() — it isn't reachable from any root`);
479
+ }
480
+ if (kind === 1)
481
+ return this.valuesArr[id];
482
+ return this.valuesMap.get(field);
483
+ }
484
+ /**
485
+ * Whether `field` is currently tracked by the runtime — integrated
486
+ * and not since detached. A caller holding a possibly-stale field
487
+ * reference (e.g. an input field orphaned by a `detach`) can check
488
+ * this before `markDirty`.
489
+ */
490
+ isTracked(field) {
491
+ return this.omNodesArr[field.id] !== undefined;
492
+ }
493
+ /**
494
+ * Mark every field tracked by this runtime as dirty. Useful as an
495
+ * escape hatch when callers don't have fine-grained style-mutation
496
+ * wiring yet: mutate styles, call `markAllDirty()`, then
497
+ * `recompute()`. Each field re-runs its rule once, but the "skip
498
+ * dependents when value unchanged" property still applies — so
499
+ * cost is one compute per field plus propagation only along
500
+ * actually-changed values, rather than a full re-init.
501
+ */
502
+ markAllDirty() {
503
+ if (!this.initDone) {
504
+ throw new Error('[spineless-runtime] markAllDirty called before init()');
505
+ }
506
+ for (const field of this.fieldRoster) {
507
+ const omNode = this.omNodesArr[field.id];
508
+ if (omNode === undefined)
509
+ continue; // detached — skip
510
+ this.pq.push(field, omNode);
511
+ }
512
+ }
513
+ /**
514
+ * Mark a field as dirty. Its rule will be re-run on the next
515
+ * `recompute()`. If the new value differs from the cached one,
516
+ * dependents are scheduled in turn.
517
+ *
518
+ * Duplicate calls are a no-op (the priority queue dedupes via its
519
+ * internal membership set).
520
+ */
521
+ markDirty(field) {
522
+ if (!this.initDone) {
523
+ throw new Error('[spineless-runtime] markDirty called before init()');
524
+ }
525
+ const om = this.omNodesArr[field.id];
526
+ if (om === undefined) {
527
+ throw new Error(`[spineless-runtime] field "${field.name}" is not in this runtime — call markDirty only on fields reachable from a root at init`);
528
+ }
529
+ this.pq.push(field, om);
530
+ }
531
+ /**
532
+ * Process all dirty fields. Pops in OM (= topological) order; runs
533
+ * each field's rule. If the result differs from the cached value,
534
+ * persists it and pushes every dependent so it gets re-run later in
535
+ * this same pass.
536
+ *
537
+ * Returns every field whose value actually changed — the caller
538
+ * uses it to scope an incremental write-back to the moved nodes.
539
+ */
540
+ recompute() {
541
+ if (!this.initDone) {
542
+ throw new Error('[spineless-runtime] recompute called before init()');
543
+ }
544
+ const changed = [];
545
+ this.stats.recomputeVisited = 0;
546
+ this.stats.recomputeChanged = 0;
547
+ while (!this.pq.isEmpty()) {
548
+ const f = this.pq.popMin();
549
+ this.stats.recomputeVisited++;
550
+ this.stats.totalVisited++;
551
+ const rule = this.rulesArr[f.id];
552
+ const id = f.id;
553
+ const kind = this.valuePresent[id];
554
+ const prev = kind === 1 ? this.valuesArr[id] : this.valuesMap.get(f);
555
+ const next = this.runCompute(f, rule);
556
+ if (!Object.is(prev, next)) {
557
+ if (typeof next === 'number') {
558
+ this.valuesArr[id] = next;
559
+ this.valuePresent[id] = 1;
560
+ if (kind === 2)
561
+ this.valuesMap.delete(f);
562
+ }
563
+ else {
564
+ this.valuesMap.set(f, next);
565
+ this.valuePresent[id] = 2;
566
+ }
567
+ this.stats.recomputeChanged++;
568
+ changed.push(f);
569
+ const deps = this.dependentsArr[f.id];
570
+ if (deps !== undefined) {
571
+ for (const d of deps) {
572
+ const om = this.omNodesArr[d.id];
573
+ this.pq.push(d, om);
574
+ }
575
+ }
576
+ }
577
+ }
578
+ return changed;
579
+ }
580
+ runCompute(field, rule) {
581
+ // Zero-dep fields (leaf inputs, constants) can't read anything —
582
+ // skip the per-compute Set allocation + validating closure.
583
+ if (rule.deps.length === 0) {
584
+ return rule.compute(NEVER_READ);
585
+ }
586
+ // Look up the cached declared-deps Set for this rule object.
587
+ // Build and store on first call; reuse on every subsequent call.
588
+ // `rebindRule` installs a NEW rule object → WeakMap miss → fresh Set.
589
+ // No manual invalidation needed.
590
+ const ruleAsUnknown = rule;
591
+ let declaredDeps = depSetCache.get(ruleAsUnknown);
592
+ if (declaredDeps === undefined) {
593
+ declaredDeps = new Set(rule.deps);
594
+ depSetCache.set(ruleAsUnknown, declaredDeps);
595
+ }
596
+ const read = (dep) => {
597
+ if (!declaredDeps.has(dep)) {
598
+ throw new Error(`[spineless-runtime] rule for "${field.name}" reads "${dep.name}" but did not declare it as a dependency`);
599
+ }
600
+ const depId = dep.id;
601
+ const depKind = this.valuePresent[depId];
602
+ if (depKind === 1)
603
+ return this.valuesArr[depId];
604
+ return this.valuesMap.get(dep);
605
+ };
606
+ return rule.compute(read);
607
+ }
608
+ }
609
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/algorithm/spineless/runtime.ts"],"names":[],"mappings":"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"}