@pilates/core 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/algorithm/index.d.ts +31 -0
  2. package/dist/algorithm/index.d.ts.map +1 -1
  3. package/dist/algorithm/index.js +85 -1
  4. package/dist/algorithm/index.js.map +1 -1
  5. package/dist/algorithm/round.d.ts +13 -0
  6. package/dist/algorithm/round.d.ts.map +1 -1
  7. package/dist/algorithm/round.js +17 -0
  8. package/dist/algorithm/round.js.map +1 -1
  9. package/dist/algorithm/spineless/flex-grammar.d.ts +394 -0
  10. package/dist/algorithm/spineless/flex-grammar.d.ts.map +1 -0
  11. package/dist/algorithm/spineless/flex-grammar.js +2373 -0
  12. package/dist/algorithm/spineless/flex-grammar.js.map +1 -0
  13. package/dist/algorithm/spineless/grammar.d.ts +150 -0
  14. package/dist/algorithm/spineless/grammar.d.ts.map +1 -0
  15. package/dist/algorithm/spineless/grammar.js +144 -0
  16. package/dist/algorithm/spineless/grammar.js.map +1 -0
  17. package/dist/algorithm/spineless/layout.d.ts +130 -0
  18. package/dist/algorithm/spineless/layout.d.ts.map +1 -0
  19. package/dist/algorithm/spineless/layout.js +755 -0
  20. package/dist/algorithm/spineless/layout.js.map +1 -0
  21. package/dist/algorithm/spineless/order-maintenance.bench.d.ts +25 -0
  22. package/dist/algorithm/spineless/order-maintenance.bench.d.ts.map +1 -0
  23. package/dist/algorithm/spineless/order-maintenance.bench.js +78 -0
  24. package/dist/algorithm/spineless/order-maintenance.bench.js.map +1 -0
  25. package/dist/algorithm/spineless/order-maintenance.d.ts +192 -0
  26. package/dist/algorithm/spineless/order-maintenance.d.ts.map +1 -0
  27. package/dist/algorithm/spineless/order-maintenance.js +294 -0
  28. package/dist/algorithm/spineless/order-maintenance.js.map +1 -0
  29. package/dist/algorithm/spineless/priority-queue.bench.d.ts +17 -0
  30. package/dist/algorithm/spineless/priority-queue.bench.d.ts.map +1 -0
  31. package/dist/algorithm/spineless/priority-queue.bench.js +57 -0
  32. package/dist/algorithm/spineless/priority-queue.bench.js.map +1 -0
  33. package/dist/algorithm/spineless/priority-queue.d.ts +73 -0
  34. package/dist/algorithm/spineless/priority-queue.d.ts.map +1 -0
  35. package/dist/algorithm/spineless/priority-queue.js +149 -0
  36. package/dist/algorithm/spineless/priority-queue.js.map +1 -0
  37. package/dist/algorithm/spineless/runtime.d.ts +239 -0
  38. package/dist/algorithm/spineless/runtime.d.ts.map +1 -0
  39. package/dist/algorithm/spineless/runtime.js +458 -0
  40. package/dist/algorithm/spineless/runtime.js.map +1 -0
  41. package/dist/algorithm/spineless/style-dirty.d.ts +65 -0
  42. package/dist/algorithm/spineless/style-dirty.d.ts.map +1 -0
  43. package/dist/algorithm/spineless/style-dirty.js +75 -0
  44. package/dist/algorithm/spineless/style-dirty.js.map +1 -0
  45. package/dist/index.d.ts +3 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +6 -1
  48. package/dist/index.js.map +1 -1
  49. package/dist/inspect.d.ts +27 -0
  50. package/dist/inspect.d.ts.map +1 -0
  51. package/dist/inspect.js +61 -0
  52. package/dist/inspect.js.map +1 -0
  53. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order-maintenance.js","sourceRoot":"","sources":["../../../src/algorithm/spineless/order-maintenance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Microbenchmark for the OM-keyed priority queue.
3
+ *
4
+ * Targets (Phase 5 viability):
5
+ * - `push`: < 2µs/op at N=10k (called once per dirty field per layout)
6
+ * - `popMin`: < 2µs/op at N=10k (called once per recompute step)
7
+ *
8
+ * Each layout pass under Spineless may process up to ~5k field-recomputes
9
+ * on a 1k-node TUI tree. Total PQ overhead must stay well under the
10
+ * 50-100µs target for incremental layout to beat imperative.
11
+ *
12
+ * Run with: `tsx packages/core/src/algorithm/spineless/priority-queue.bench.ts`
13
+ *
14
+ * @internal
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=priority-queue.bench.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"priority-queue.bench.d.ts","sourceRoot":"","sources":["../../../src/algorithm/spineless/priority-queue.bench.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Microbenchmark for the OM-keyed priority queue.
3
+ *
4
+ * Targets (Phase 5 viability):
5
+ * - `push`: < 2µs/op at N=10k (called once per dirty field per layout)
6
+ * - `popMin`: < 2µs/op at N=10k (called once per recompute step)
7
+ *
8
+ * Each layout pass under Spineless may process up to ~5k field-recomputes
9
+ * on a 1k-node TUI tree. Total PQ overhead must stay well under the
10
+ * 50-100µs target for incremental layout to beat imperative.
11
+ *
12
+ * Run with: `tsx packages/core/src/algorithm/spineless/priority-queue.bench.ts`
13
+ *
14
+ * @internal
15
+ */
16
+ import { BenderOrderMaintenance } from './order-maintenance.js';
17
+ import { OmPriorityQueue } from './priority-queue.js';
18
+ function median(xs) {
19
+ const sorted = [...xs].sort((a, b) => a - b);
20
+ return sorted[Math.floor(sorted.length / 2)];
21
+ }
22
+ function bench(label, sizes, opsPerTrial, trials) {
23
+ console.log(`\n## ${label}`);
24
+ for (const N of sizes) {
25
+ const trialMsPush = [];
26
+ const trialMsPop = [];
27
+ for (let t = 0; t < trials; t++) {
28
+ const om = new BenderOrderMaintenance();
29
+ const nodes = [om.init()];
30
+ for (let i = 1; i < N; i++)
31
+ nodes.push(om.insertAfter(nodes[i - 1]));
32
+ const pq = new OmPriorityQueue(om);
33
+ // Push phase
34
+ let s = performance.now();
35
+ for (let k = 0; k < opsPerTrial; k++) {
36
+ // Use a deterministic but spread-out order so the heap actually re-orders.
37
+ const i = (k * 2654435761) % N;
38
+ pq.push(k, nodes[i]);
39
+ }
40
+ let e = performance.now();
41
+ trialMsPush.push(e - s);
42
+ // Pop phase (extract everything)
43
+ s = performance.now();
44
+ while (!pq.isEmpty())
45
+ pq.popMin();
46
+ e = performance.now();
47
+ trialMsPop.push(e - s);
48
+ }
49
+ const usPush = (median(trialMsPush) * 1000) / opsPerTrial;
50
+ const usPop = (median(trialMsPop) * 1000) / opsPerTrial;
51
+ console.log(` N=${N.toString().padStart(6)} push=${usPush.toFixed(3).padStart(7)} µs popMin=${usPop.toFixed(3).padStart(7)} µs`);
52
+ }
53
+ }
54
+ console.log('OmPriorityQueue microbench (Bender OM, single-threaded JS)');
55
+ console.log('Targets: push < 2µs, popMin < 2µs at N=10k');
56
+ bench('push + popMin', [100, 1000, 10000], 10_000, 5);
57
+ //# sourceMappingURL=priority-queue.bench.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"priority-queue.bench.js","sourceRoot":"","sources":["../../../src/algorithm/spineless/priority-queue.bench.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Order-Maintenance-keyed priority queue.
3
+ *
4
+ * The hot data structure of the Spineless Traversal runtime (Kirisame,
5
+ * Wang, Panchekha — PLDI 2025). Each item is keyed by an {@link OMNode}
6
+ * representing its position in the layout-field traversal order; the
7
+ * queue extracts items in OM-order, so the runtime always processes
8
+ * the earliest-dirty field next.
9
+ *
10
+ * Implementation: binary min-heap over `{ value, omNode }` records.
11
+ * Ordering uses `om.compare(a.omNode, b.omNode)`. Standard O(log N)
12
+ * push/popMin, O(1) peek/size.
13
+ *
14
+ * Membership tracking: an internal `Set` allows O(1) `has(value)`
15
+ * queries so the Spineless runtime can avoid enqueueing the same
16
+ * field twice. Important: this assumes `value` instances are stable
17
+ * (used as Map keys via reference equality), which fits the Spineless
18
+ * "one OMNode per (Node, field-name) pair, allocated once" model.
19
+ *
20
+ * ## Correctness under OM relabel
21
+ *
22
+ * The OM data structure may relabel internal tags on insert
23
+ * (`BenderOrderMaintenance`'s windowed redistribute). The heap
24
+ * invariant is "parent ≤ all descendants by OM compare". A relabel
25
+ * preserves the RELATIVE order of all live OM nodes, so
26
+ * `sign(compare(a, b))` is unchanged — the heap invariant holds.
27
+ *
28
+ * @internal
29
+ */
30
+ import type { OMNode, OrderMaintenance } from './order-maintenance.js';
31
+ /**
32
+ * @internal
33
+ */
34
+ export declare class OmPriorityQueue<T> {
35
+ private readonly om;
36
+ private readonly heapValue;
37
+ private readonly heapOmNode;
38
+ private readonly members;
39
+ constructor(om: OrderMaintenance);
40
+ get size(): number;
41
+ isEmpty(): boolean;
42
+ has(value: T): boolean;
43
+ /**
44
+ * Push a value at the given OM position. Caller is responsible for
45
+ * checking `has(value)` first if dedup matters (some workflows
46
+ * intentionally re-enqueue after deletion).
47
+ *
48
+ * Returns `true` if added, `false` if `value` was already present
49
+ * (no-op — the queue is unchanged, original OM position retained).
50
+ */
51
+ push(value: T, omNode: OMNode): boolean;
52
+ /**
53
+ * Return (without removing) the value at OM-minimum. Returns
54
+ * `undefined` if the queue is empty.
55
+ */
56
+ peek(): T | undefined;
57
+ /**
58
+ * Remove and return the OM-minimum value. Returns `undefined` if
59
+ * the queue is empty.
60
+ */
61
+ popMin(): T | undefined;
62
+ /**
63
+ * Sift the element at index `start` up the heap until heap property
64
+ * is restored. O(log N).
65
+ */
66
+ private siftUp;
67
+ /**
68
+ * Sift the element at index `start` down the heap until heap property
69
+ * is restored. O(log N).
70
+ */
71
+ private siftDown;
72
+ }
73
+ //# sourceMappingURL=priority-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"priority-queue.d.ts","sourceRoot":"","sources":["../../../src/algorithm/spineless/priority-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAEvE;;GAEG;AACH,qBAAa,eAAe,CAAC,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAmB;IAMtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAE3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAEjC,EAAE,EAAE,gBAAgB;IAIhC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,IAAI,OAAO;IAIlB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO;IAItB;;;;;;;OAOG;IACH,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IASvC;;;OAGG;IACH,IAAI,IAAI,CAAC,GAAG,SAAS;IAIrB;;;OAGG;IACH,MAAM,IAAI,CAAC,GAAG,SAAS;IAgBvB;;;OAGG;IACH,OAAO,CAAC,MAAM;IAgBd;;;OAGG;IACH,OAAO,CAAC,QAAQ;CAsBjB"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Order-Maintenance-keyed priority queue.
3
+ *
4
+ * The hot data structure of the Spineless Traversal runtime (Kirisame,
5
+ * Wang, Panchekha — PLDI 2025). Each item is keyed by an {@link OMNode}
6
+ * representing its position in the layout-field traversal order; the
7
+ * queue extracts items in OM-order, so the runtime always processes
8
+ * the earliest-dirty field next.
9
+ *
10
+ * Implementation: binary min-heap over `{ value, omNode }` records.
11
+ * Ordering uses `om.compare(a.omNode, b.omNode)`. Standard O(log N)
12
+ * push/popMin, O(1) peek/size.
13
+ *
14
+ * Membership tracking: an internal `Set` allows O(1) `has(value)`
15
+ * queries so the Spineless runtime can avoid enqueueing the same
16
+ * field twice. Important: this assumes `value` instances are stable
17
+ * (used as Map keys via reference equality), which fits the Spineless
18
+ * "one OMNode per (Node, field-name) pair, allocated once" model.
19
+ *
20
+ * ## Correctness under OM relabel
21
+ *
22
+ * The OM data structure may relabel internal tags on insert
23
+ * (`BenderOrderMaintenance`'s windowed redistribute). The heap
24
+ * invariant is "parent ≤ all descendants by OM compare". A relabel
25
+ * preserves the RELATIVE order of all live OM nodes, so
26
+ * `sign(compare(a, b))` is unchanged — the heap invariant holds.
27
+ *
28
+ * @internal
29
+ */
30
+ /**
31
+ * @internal
32
+ */
33
+ export class OmPriorityQueue {
34
+ om;
35
+ // Parallel arrays for the heap. heapValue[i] is the user-supplied
36
+ // value; heapOmNode[i] is its OM position. Using parallel arrays
37
+ // rather than {value, omNode} pair objects avoids per-push
38
+ // allocation, which matters at Spineless-runtime scale (10k+
39
+ // pushes per layout pass at the largest TUI tree size).
40
+ heapValue = [];
41
+ heapOmNode = [];
42
+ // Membership set keyed by reference. Allows O(1) `has` checks.
43
+ members = new Set();
44
+ constructor(om) {
45
+ this.om = om;
46
+ }
47
+ get size() {
48
+ return this.heapValue.length;
49
+ }
50
+ isEmpty() {
51
+ return this.heapValue.length === 0;
52
+ }
53
+ has(value) {
54
+ return this.members.has(value);
55
+ }
56
+ /**
57
+ * Push a value at the given OM position. Caller is responsible for
58
+ * checking `has(value)` first if dedup matters (some workflows
59
+ * intentionally re-enqueue after deletion).
60
+ *
61
+ * Returns `true` if added, `false` if `value` was already present
62
+ * (no-op — the queue is unchanged, original OM position retained).
63
+ */
64
+ push(value, omNode) {
65
+ if (this.members.has(value))
66
+ return false;
67
+ this.heapValue.push(value);
68
+ this.heapOmNode.push(omNode);
69
+ this.members.add(value);
70
+ this.siftUp(this.heapValue.length - 1);
71
+ return true;
72
+ }
73
+ /**
74
+ * Return (without removing) the value at OM-minimum. Returns
75
+ * `undefined` if the queue is empty.
76
+ */
77
+ peek() {
78
+ return this.heapValue[0];
79
+ }
80
+ /**
81
+ * Remove and return the OM-minimum value. Returns `undefined` if
82
+ * the queue is empty.
83
+ */
84
+ popMin() {
85
+ const n = this.heapValue.length;
86
+ if (n === 0)
87
+ return undefined;
88
+ const top = this.heapValue[0];
89
+ const last = n - 1;
90
+ if (last > 0) {
91
+ this.heapValue[0] = this.heapValue[last];
92
+ this.heapOmNode[0] = this.heapOmNode[last];
93
+ }
94
+ this.heapValue.length = last;
95
+ this.heapOmNode.length = last;
96
+ this.members.delete(top);
97
+ if (last > 0)
98
+ this.siftDown(0);
99
+ return top;
100
+ }
101
+ /**
102
+ * Sift the element at index `start` up the heap until heap property
103
+ * is restored. O(log N).
104
+ */
105
+ siftUp(start) {
106
+ let i = start;
107
+ const value = this.heapValue[i];
108
+ const omNode = this.heapOmNode[i];
109
+ while (i > 0) {
110
+ const parent = (i - 1) >> 1;
111
+ const parentOm = this.heapOmNode[parent];
112
+ if (this.om.compare(omNode, parentOm) >= 0)
113
+ break;
114
+ this.heapValue[i] = this.heapValue[parent];
115
+ this.heapOmNode[i] = parentOm;
116
+ i = parent;
117
+ }
118
+ this.heapValue[i] = value;
119
+ this.heapOmNode[i] = omNode;
120
+ }
121
+ /**
122
+ * Sift the element at index `start` down the heap until heap property
123
+ * is restored. O(log N).
124
+ */
125
+ siftDown(start) {
126
+ let i = start;
127
+ const n = this.heapValue.length;
128
+ const value = this.heapValue[i];
129
+ const omNode = this.heapOmNode[i];
130
+ const halfN = n >> 1;
131
+ while (i < halfN) {
132
+ let bestChild = (i << 1) | 1; // 2i + 1, left child
133
+ const right = bestChild + 1;
134
+ if (right < n) {
135
+ if (this.om.compare(this.heapOmNode[right], this.heapOmNode[bestChild]) < 0) {
136
+ bestChild = right;
137
+ }
138
+ }
139
+ if (this.om.compare(this.heapOmNode[bestChild], omNode) >= 0)
140
+ break;
141
+ this.heapValue[i] = this.heapValue[bestChild];
142
+ this.heapOmNode[i] = this.heapOmNode[bestChild];
143
+ i = bestChild;
144
+ }
145
+ this.heapValue[i] = value;
146
+ this.heapOmNode[i] = omNode;
147
+ }
148
+ }
149
+ //# sourceMappingURL=priority-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"priority-queue.js","sourceRoot":"","sources":["../../../src/algorithm/spineless/priority-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,239 @@
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 type { Field, FieldRule, Grammar } from './grammar.js';
88
+ import { type OrderMaintenance } from './order-maintenance.js';
89
+ /**
90
+ * @internal
91
+ */
92
+ export declare class SpinelessRuntime {
93
+ private readonly grammar;
94
+ private readonly rootFields;
95
+ private readonly om;
96
+ private readonly pq;
97
+ /** field -> cached value */
98
+ private readonly values;
99
+ /** field -> its OM timestamp (allocated in topo order at init) */
100
+ private readonly omNodes;
101
+ /** field -> fields that read this field (reverse of `rule.deps`) */
102
+ private readonly dependents;
103
+ /** The OM node at the topological tail — where `graft` appends. */
104
+ private lastOm;
105
+ private initDone;
106
+ /**
107
+ * Recompute counters — for observability (phase 9). Plain integer
108
+ * fields, bumped on the existing `integrate` / `recompute` loops,
109
+ * so they cost nothing measurable and need no enable flag.
110
+ */
111
+ readonly stats: {
112
+ /** Fields integrated so far — the `init` pass plus every `graft`. */
113
+ initFields: number;
114
+ /** Fields popped from the PQ by the most recent `recompute()`. */
115
+ recomputeVisited: number;
116
+ /** Of those, Fields whose value actually changed. */
117
+ recomputeChanged: number;
118
+ /** Cumulative Fields visited across every `recompute()` since init. */
119
+ totalVisited: number;
120
+ };
121
+ constructor(grammar: Grammar, rootFields: ReadonlyArray<Field<unknown>>, om?: OrderMaintenance);
122
+ /**
123
+ * Walk the grammar in topological order, allocate an OM node per
124
+ * field, cache initial values, and record reverse-dependents. Must
125
+ * be called once before any `evaluate` / `markDirty` / `recompute`.
126
+ */
127
+ init(): void;
128
+ /**
129
+ * Integrate new fields into an already-`init`ed runtime without a
130
+ * rebuild (phase 5c). `additions` holds the rules for the new
131
+ * fields only — it throws if any field is already present, since
132
+ * redefining an existing field is a rule *change*, not a graft.
133
+ * `newRoots` are the new fields to start the topological DFS from
134
+ * (their existing-field dependencies are reached as boundaries).
135
+ *
136
+ * Correct **iff** the new fields are pure topological-tail
137
+ * additions: no existing field reads a new field, and no existing
138
+ * rule needed to change. The caller guarantees this — it holds by
139
+ * construction when appending a last child to a parent in the
140
+ * simple regime (no flex distribution, default `justify`, no
141
+ * wrap). The new fields are computed with correct inputs during
142
+ * the graft, so no `markDirty` / `recompute` is needed afterward.
143
+ */
144
+ graft(additions: Grammar, newRoots: ReadonlyArray<Field<unknown>>): void;
145
+ /**
146
+ * Remove fields from an already-`init`ed runtime without a rebuild
147
+ * (phase 5c) — the inverse of `graft`. `fields` is the exact set
148
+ * to drop (a removed subtree's fields). For each: its OM node is
149
+ * freed, its cached value and reverse-dependency list dropped, its
150
+ * rule deleted from the grammar, and it is pruned from the
151
+ * reverse-dependency list of every field it read.
152
+ *
153
+ * Throws if any removed field still has a dependent *outside* the
154
+ * removed set — detaching it would dangle that edge. The caller
155
+ * guarantees a clean cut: it holds by construction when removing a
156
+ * last child from a parent in the simple regime (nothing outside
157
+ * that subtree reads into it). No `recompute` is needed afterward —
158
+ * removing a topological-tail subtree changes no surviving field.
159
+ *
160
+ * After the cut, any surviving leaf-input field the removed set was
161
+ * the sole reader of is **orphaned** — nothing reads it and the
162
+ * grammar cannot re-read it without a fresh build. Such orphans are
163
+ * dropped too (a leaf has no dependencies, so this cannot cascade).
164
+ * That makes the caller's removed set just the subtree's own
165
+ * fields — orphan input fields, e.g. the previous last child's
166
+ * now-unread main-end margin, need not be enumerated.
167
+ */
168
+ detach(fields: Iterable<Field<unknown>>): void;
169
+ /**
170
+ * Replace the rule of an already-integrated field (phase 5c) — for
171
+ * a structural change that rewrites a *surviving* field rather than
172
+ * adding or removing one. Appending a child into a flex-distributing
173
+ * parent, for instance, grows every existing sibling's
174
+ * flex-distribution dependency set.
175
+ *
176
+ * The reverse-dependency edges are repaired to match the new dep
177
+ * set (the field is dropped from the lists of deps it no longer
178
+ * reads and added to the lists of deps it now reads), the new rule
179
+ * is installed, and the field is marked dirty so the next
180
+ * `recompute()` re-runs it. Every new dependency must already be
181
+ * integrated. The field keeps its OM node; if a new dependency has
182
+ * a later OM, recompute stays correct (see the termination note on
183
+ * the class) at the cost of a bounded number of extra recomputes.
184
+ */
185
+ rebindRule(field: Field<unknown>, newRule: FieldRule<unknown>): void;
186
+ /**
187
+ * Topological DFS shared by `init` and `graft`. For every
188
+ * not-yet-integrated field reachable from `roots`: recurse into
189
+ * deps, record reverse-dependency edges, allocate an OM node after
190
+ * the current tail, run the rule, and cache the value. Fields that
191
+ * already have an OM node are boundaries — visited, edge recorded,
192
+ * not re-walked.
193
+ */
194
+ private integrate;
195
+ /**
196
+ * Read the current cached value of a field. Throws if the field
197
+ * wasn't reachable from any root during `init` (so no cache entry
198
+ * exists).
199
+ */
200
+ evaluate<T>(field: Field<T>): T;
201
+ /**
202
+ * Whether `field` is currently tracked by the runtime — integrated
203
+ * and not since detached. A caller holding a possibly-stale field
204
+ * reference (e.g. an input field orphaned by a `detach`) can check
205
+ * this before `markDirty`.
206
+ */
207
+ isTracked(field: Field<unknown>): boolean;
208
+ /**
209
+ * Mark every field tracked by this runtime as dirty. Useful as an
210
+ * escape hatch when callers don't have fine-grained style-mutation
211
+ * wiring yet: mutate styles, call `markAllDirty()`, then
212
+ * `recompute()`. Each field re-runs its rule once, but the "skip
213
+ * dependents when value unchanged" property still applies — so
214
+ * cost is one compute per field plus propagation only along
215
+ * actually-changed values, rather than a full re-init.
216
+ */
217
+ markAllDirty(): void;
218
+ /**
219
+ * Mark a field as dirty. Its rule will be re-run on the next
220
+ * `recompute()`. If the new value differs from the cached one,
221
+ * dependents are scheduled in turn.
222
+ *
223
+ * Duplicate calls are a no-op (the priority queue dedupes via its
224
+ * internal membership set).
225
+ */
226
+ markDirty(field: Field<unknown>): void;
227
+ /**
228
+ * Process all dirty fields. Pops in OM (= topological) order; runs
229
+ * each field's rule. If the result differs from the cached value,
230
+ * persists it and pushes every dependent so it gets re-run later in
231
+ * this same pass.
232
+ *
233
+ * Returns every field whose value actually changed — the caller
234
+ * uses it to scope an incremental write-back to the moved nodes.
235
+ */
236
+ recompute(): Array<Field<unknown>>;
237
+ private runCompute;
238
+ }
239
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/algorithm/spineless/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAU,MAAM,cAAc,CAAC;AACtE,OAAO,EAAuC,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAGpG;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;IAC3D,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAmB;IACtC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAkC;IAErD,4BAA4B;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAClE,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;IAClE,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoD;IAE/E,mEAAmE;IACnE,OAAO,CAAC,MAAM,CAAuB;IAErC,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;OAIG;IACH,QAAQ,CAAC,KAAK;QACZ,qEAAqE;;QAErE,kEAAkE;;QAElE,qDAAqD;;QAErD,uEAAuE;;MAEvE;gBAGA,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EACzC,EAAE,GAAE,gBAA+C;IAQrD;;;;OAIG;IACH,IAAI,IAAI,IAAI;IAKZ;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI;IAexE;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI;IAsE9C;;;;;;;;;;;;;;;OAeG;IACH,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI;IA0CpE;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;IAgDjB;;;;OAIG;IACH,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;IAS/B;;;;;OAKG;IACH,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,OAAO;IAIzC;;;;;;;;OAQG;IACH,YAAY,IAAI,IAAI;IASpB;;;;;;;OAOG;IACH,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAatC;;;;;;;;OAQG;IACH,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IA8BlC,OAAO,CAAC,UAAU;CAYnB"}