@procedures/collections 0.46.0 → 0.47.2

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 (233) hide show
  1. package/CHANGELOG.md +42 -8
  2. package/README.md +30 -0
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/index.d.ts +1 -58
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +3 -94
  7. package/dist/index.js.map +1 -1
  8. package/dist/storage/index.d.ts +2 -2
  9. package/dist/storage/index.d.ts.map +1 -1
  10. package/dist/storage/index.js +1 -1
  11. package/dist/storage/index.js.map +1 -1
  12. package/dist/storage/memory.d.ts +1 -1
  13. package/dist/storage/memory.d.ts.map +1 -1
  14. package/dist/storage/memory.js +1 -1
  15. package/dist/storage/memory.js.map +1 -1
  16. package/dist/testing/index.d.ts +1 -1
  17. package/dist/testing/index.d.ts.map +1 -1
  18. package/dist/testing/index.js +1 -1
  19. package/dist/testing/index.js.map +1 -1
  20. package/dist/testing/storage-contract.js +1 -1
  21. package/dist/testing/storage-contract.js.map +1 -1
  22. package/dist/undo/index.d.ts +1 -1
  23. package/dist/undo/index.js +1 -1
  24. package/dist/undo/undo-log.d.ts +1 -1
  25. package/dist/undo/undo-log.js +1 -1
  26. package/package.json +6 -6
  27. package/src/index.ts +338 -213
  28. package/src/storage/index.ts +2 -2
  29. package/src/storage/memory.ts +1 -1
  30. package/src/testing/index.ts +1 -1
  31. package/src/testing/storage-contract.ts +1 -1
  32. package/src/undo/index.ts +1 -1
  33. package/src/undo/undo-log.ts +1 -1
  34. package/dist/async/async-queue.d.ts +0 -170
  35. package/dist/async/async-queue.d.ts.map +0 -1
  36. package/dist/async/async-queue.js +0 -404
  37. package/dist/async/async-queue.js.map +0 -1
  38. package/dist/async/channels.d.ts +0 -211
  39. package/dist/async/channels.d.ts.map +0 -1
  40. package/dist/async/channels.js +0 -393
  41. package/dist/async/channels.js.map +0 -1
  42. package/dist/async/settled.d.ts +0 -23
  43. package/dist/async/settled.d.ts.map +0 -1
  44. package/dist/async/settled.js +0 -32
  45. package/dist/async/settled.js.map +0 -1
  46. package/dist/behaviors/bounded.d.ts +0 -79
  47. package/dist/behaviors/bounded.d.ts.map +0 -1
  48. package/dist/behaviors/bounded.js +0 -393
  49. package/dist/behaviors/bounded.js.map +0 -1
  50. package/dist/behaviors/composite.d.ts +0 -17
  51. package/dist/behaviors/composite.d.ts.map +0 -1
  52. package/dist/behaviors/composite.js +0 -93
  53. package/dist/behaviors/composite.js.map +0 -1
  54. package/dist/behaviors/evented.d.ts +0 -154
  55. package/dist/behaviors/evented.d.ts.map +0 -1
  56. package/dist/behaviors/evented.js +0 -299
  57. package/dist/behaviors/evented.js.map +0 -1
  58. package/dist/behaviors/lru.d.ts +0 -84
  59. package/dist/behaviors/lru.d.ts.map +0 -1
  60. package/dist/behaviors/lru.js +0 -376
  61. package/dist/behaviors/lru.js.map +0 -1
  62. package/dist/behaviors/readonly.d.ts +0 -73
  63. package/dist/behaviors/readonly.d.ts.map +0 -1
  64. package/dist/behaviors/readonly.js +0 -189
  65. package/dist/behaviors/readonly.js.map +0 -1
  66. package/dist/behaviors/safe.d.ts +0 -163
  67. package/dist/behaviors/safe.d.ts.map +0 -1
  68. package/dist/behaviors/safe.js +0 -176
  69. package/dist/behaviors/safe.js.map +0 -1
  70. package/dist/behaviors/synchronized.d.ts +0 -88
  71. package/dist/behaviors/synchronized.d.ts.map +0 -1
  72. package/dist/behaviors/synchronized.js +0 -285
  73. package/dist/behaviors/synchronized.js.map +0 -1
  74. package/dist/behaviors/ttl.d.ts +0 -118
  75. package/dist/behaviors/ttl.d.ts.map +0 -1
  76. package/dist/behaviors/ttl.js +0 -354
  77. package/dist/behaviors/ttl.js.map +0 -1
  78. package/dist/contracts/model.d.ts +0 -29
  79. package/dist/contracts/model.d.ts.map +0 -1
  80. package/dist/contracts/model.js +0 -26
  81. package/dist/contracts/model.js.map +0 -1
  82. package/dist/core/effects.d.ts +0 -176
  83. package/dist/core/effects.d.ts.map +0 -1
  84. package/dist/core/effects.js +0 -180
  85. package/dist/core/effects.js.map +0 -1
  86. package/dist/core/events.d.ts +0 -192
  87. package/dist/core/events.d.ts.map +0 -1
  88. package/dist/core/events.js +0 -291
  89. package/dist/core/events.js.map +0 -1
  90. package/dist/core/middleware.d.ts +0 -231
  91. package/dist/core/middleware.d.ts.map +0 -1
  92. package/dist/core/middleware.js +0 -161
  93. package/dist/core/middleware.js.map +0 -1
  94. package/dist/core/policies.d.ts +0 -220
  95. package/dist/core/policies.d.ts.map +0 -1
  96. package/dist/core/policies.js +0 -48
  97. package/dist/core/policies.js.map +0 -1
  98. package/dist/core/traits.d.ts +0 -142
  99. package/dist/core/traits.d.ts.map +0 -1
  100. package/dist/core/traits.js +0 -8
  101. package/dist/core/traits.js.map +0 -1
  102. package/dist/fx/collectors.d.ts +0 -193
  103. package/dist/fx/collectors.d.ts.map +0 -1
  104. package/dist/fx/collectors.js +0 -375
  105. package/dist/fx/collectors.js.map +0 -1
  106. package/dist/fx/iter.d.ts +0 -166
  107. package/dist/fx/iter.d.ts.map +0 -1
  108. package/dist/fx/iter.js +0 -421
  109. package/dist/fx/iter.js.map +0 -1
  110. package/dist/impl/array-deque.d.ts +0 -112
  111. package/dist/impl/array-deque.d.ts.map +0 -1
  112. package/dist/impl/array-deque.js +0 -380
  113. package/dist/impl/array-deque.js.map +0 -1
  114. package/dist/impl/array-list.d.ts +0 -101
  115. package/dist/impl/array-list.d.ts.map +0 -1
  116. package/dist/impl/array-list.js +0 -387
  117. package/dist/impl/array-list.js.map +0 -1
  118. package/dist/impl/hash-map.d.ts +0 -149
  119. package/dist/impl/hash-map.d.ts.map +0 -1
  120. package/dist/impl/hash-map.js +0 -473
  121. package/dist/impl/hash-map.js.map +0 -1
  122. package/dist/impl/hash-set.d.ts +0 -125
  123. package/dist/impl/hash-set.d.ts.map +0 -1
  124. package/dist/impl/hash-set.js +0 -264
  125. package/dist/impl/hash-set.js.map +0 -1
  126. package/dist/impl/linked-hash-map.d.ts +0 -141
  127. package/dist/impl/linked-hash-map.d.ts.map +0 -1
  128. package/dist/impl/linked-hash-map.js +0 -442
  129. package/dist/impl/linked-hash-map.js.map +0 -1
  130. package/dist/impl/linked-list.d.ts +0 -109
  131. package/dist/impl/linked-list.d.ts.map +0 -1
  132. package/dist/impl/linked-list.js +0 -494
  133. package/dist/impl/linked-list.js.map +0 -1
  134. package/dist/impl/priority-queue.d.ts +0 -139
  135. package/dist/impl/priority-queue.d.ts.map +0 -1
  136. package/dist/impl/priority-queue.js +0 -343
  137. package/dist/impl/priority-queue.js.map +0 -1
  138. package/dist/impl/tree-map.d.ts +0 -153
  139. package/dist/impl/tree-map.d.ts.map +0 -1
  140. package/dist/impl/tree-map.js +0 -788
  141. package/dist/impl/tree-map.js.map +0 -1
  142. package/dist/impl/tree-set.d.ts +0 -112
  143. package/dist/impl/tree-set.d.ts.map +0 -1
  144. package/dist/impl/tree-set.js +0 -374
  145. package/dist/impl/tree-set.js.map +0 -1
  146. package/dist/interfaces/collection.d.ts +0 -119
  147. package/dist/interfaces/collection.d.ts.map +0 -1
  148. package/dist/interfaces/collection.js +0 -8
  149. package/dist/interfaces/collection.js.map +0 -1
  150. package/dist/interfaces/list.d.ts +0 -247
  151. package/dist/interfaces/list.d.ts.map +0 -1
  152. package/dist/interfaces/list.js +0 -8
  153. package/dist/interfaces/list.js.map +0 -1
  154. package/dist/interfaces/map.d.ts +0 -344
  155. package/dist/interfaces/map.d.ts.map +0 -1
  156. package/dist/interfaces/map.js +0 -8
  157. package/dist/interfaces/map.js.map +0 -1
  158. package/dist/interfaces/queue.d.ts +0 -304
  159. package/dist/interfaces/queue.d.ts.map +0 -1
  160. package/dist/interfaces/queue.js +0 -8
  161. package/dist/interfaces/queue.js.map +0 -1
  162. package/dist/interfaces/set.d.ts +0 -137
  163. package/dist/interfaces/set.d.ts.map +0 -1
  164. package/dist/interfaces/set.js +0 -8
  165. package/dist/interfaces/set.js.map +0 -1
  166. package/dist/order/index.d.ts +0 -7
  167. package/dist/order/index.d.ts.map +0 -1
  168. package/dist/order/index.js +0 -7
  169. package/dist/order/index.js.map +0 -1
  170. package/dist/order/rank.d.ts +0 -100
  171. package/dist/order/rank.d.ts.map +0 -1
  172. package/dist/order/rank.js +0 -286
  173. package/dist/order/rank.js.map +0 -1
  174. package/dist/storage/listeners.d.ts +0 -39
  175. package/dist/storage/listeners.d.ts.map +0 -1
  176. package/dist/storage/listeners.js +0 -65
  177. package/dist/storage/listeners.js.map +0 -1
  178. package/dist/testing/check.d.ts +0 -25
  179. package/dist/testing/check.d.ts.map +0 -1
  180. package/dist/testing/check.js +0 -85
  181. package/dist/testing/check.js.map +0 -1
  182. package/dist/utils/defaults.d.ts +0 -135
  183. package/dist/utils/defaults.d.ts.map +0 -1
  184. package/dist/utils/defaults.js +0 -322
  185. package/dist/utils/defaults.js.map +0 -1
  186. package/dist/utils/factories.d.ts +0 -144
  187. package/dist/utils/factories.d.ts.map +0 -1
  188. package/dist/utils/factories.js +0 -293
  189. package/dist/utils/factories.js.map +0 -1
  190. package/dist/utils/helpers.d.ts +0 -137
  191. package/dist/utils/helpers.d.ts.map +0 -1
  192. package/dist/utils/helpers.js +0 -221
  193. package/dist/utils/helpers.js.map +0 -1
  194. package/src/async/async-queue.ts +0 -481
  195. package/src/async/channels.ts +0 -450
  196. package/src/async/settled.ts +0 -41
  197. package/src/behaviors/bounded.ts +0 -485
  198. package/src/behaviors/composite.ts +0 -99
  199. package/src/behaviors/evented.ts +0 -464
  200. package/src/behaviors/lru.ts +0 -447
  201. package/src/behaviors/readonly.ts +0 -236
  202. package/src/behaviors/safe.ts +0 -372
  203. package/src/behaviors/synchronized.ts +0 -316
  204. package/src/behaviors/ttl.ts +0 -462
  205. package/src/contracts/model.ts +0 -44
  206. package/src/core/effects.ts +0 -323
  207. package/src/core/events.ts +0 -356
  208. package/src/core/middleware.ts +0 -415
  209. package/src/core/policies.ts +0 -316
  210. package/src/core/traits.ts +0 -164
  211. package/src/fx/collectors.ts +0 -500
  212. package/src/fx/iter.ts +0 -536
  213. package/src/impl/array-deque.ts +0 -463
  214. package/src/impl/array-list.ts +0 -490
  215. package/src/impl/hash-map.ts +0 -623
  216. package/src/impl/hash-set.ts +0 -342
  217. package/src/impl/linked-hash-map.ts +0 -572
  218. package/src/impl/linked-list.ts +0 -606
  219. package/src/impl/priority-queue.ts +0 -448
  220. package/src/impl/tree-map.ts +0 -912
  221. package/src/impl/tree-set.ts +0 -469
  222. package/src/interfaces/collection.ts +0 -141
  223. package/src/interfaces/list.ts +0 -281
  224. package/src/interfaces/map.ts +0 -405
  225. package/src/interfaces/queue.ts +0 -353
  226. package/src/interfaces/set.ts +0 -158
  227. package/src/order/index.ts +0 -6
  228. package/src/order/rank.ts +0 -271
  229. package/src/storage/listeners.ts +0 -72
  230. package/src/testing/check.ts +0 -81
  231. package/src/utils/defaults.ts +0 -345
  232. package/src/utils/factories.ts +0 -357
  233. package/src/utils/helpers.ts +0 -248
package/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # @procedures/collections
2
2
 
3
+ ## 0.47.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 2684531: The pure collection and graph code moved to `@mark1russell7/collections`. Both packages re-export the same names, and the signatures stay the same.
8
+ - Updated dependencies [0650616]
9
+ - Updated dependencies [ae1e3fd]
10
+ - Updated dependencies [f1ece74]
11
+ - @procedures/client@0.47.2
12
+
13
+ ## 0.47.1
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [f845c6d]
18
+ - @procedures/client@0.47.1
19
+
20
+ ## 0.47.0
21
+
22
+ ### Patch Changes
23
+
24
+ - 397dd4b: Add `SummaryTree<Leaf, Summary>` and `summaryTree(spec, leaves)`: a persistent sequence of leaves with a monoid summary in each node. `concat`, `splitAt`, `split` (a monotone predicate over the prefix summary), `search`, `slice`, `splice`, `insert`, `remove`, `set` and `at` are O(log n). The tree is an AVL tree with the join algorithms.
25
+ - e1ce6f4: `SummaryTree` gets `locate(key, target)`, which finds the leaf and the offset of a position of an additive key and calls no `combine`. The new optional `spec.merge(left, right)` joins two neighbor leaves at each seam of `concat`, `append`, `prepend`, `splice`, `insert` and `remove`. `set` and a `splice` of 8 leaves or fewer copy only the paths to their leaves. A rope edit of 100k characters in leaves of 256 calls `combine` and `measure` 21 times at most, and 135 times before. Each node keeps the summary of its left subtree and its leaf, so a copy that changes only the right subtree calls `combine` once. The new type `SummaryLocation` is the result of `locate`.
26
+ - Updated dependencies [c9125a8]
27
+ - Updated dependencies [335728b]
28
+ - Updated dependencies [d987202]
29
+ - Updated dependencies [45a737f]
30
+ - Updated dependencies [d77e9e8]
31
+ - Updated dependencies [e913014]
32
+ - Updated dependencies [2f0c7b0]
33
+ - Updated dependencies [ad70c38]
34
+ - Updated dependencies [47819c6]
35
+ - @procedures/client@0.47.0
36
+
3
37
  ## 0.46.0
4
38
 
5
39
  ### Patch Changes
@@ -406,9 +440,9 @@
406
440
  Migration:
407
441
 
408
442
  - **Site.** No change. The site does not write collections.
409
- - **MiniMongo.** No change for a storage or a `HybridStorage` without `versionOf`. A `HybridStorage` with `versionOf` over `ApiStorage` needs a server storage with the same `versionOf` (for example `new InMemoryStorage({ versionOf })`), or the option `sendBaseVersions: false`.
410
- - **Graph.** Graph keeps last-write-wins first (D11): it gives no expected version, so nothing changes. `GraphDocsStorage` must refuse a write with an expected version until it tests one. Add the guard to its `set`, `delete` and `setBatch`, and run the contract suite: its first case tests the refusal. To adopt the version later, stamp a version field on the server, give the storage a `versionOf` that tests it in the write, and give the same `versionOf` to the `HybridStorage` of the client. Then add `createWithVersions` to the contract run.
411
- - **jarvis.** No change: jarvis gives no expected version. A storage of jarvis that implements `CollectionStorage` must refuse a write with an expected version, as for Graph.
443
+ - **An app with `HybridStorage`.** No change for a storage or a `HybridStorage` without `versionOf`. A `HybridStorage` with `versionOf` over `ApiStorage` needs a server storage with the same `versionOf` (for example `new InMemoryStorage({ versionOf })`), or the option `sendBaseVersions: false`.
444
+ - **An app with last-write-wins.** It gives no expected version, so nothing changes. Its own storage must refuse a write with an expected version until it tests one. Add the guard to its `set`, `delete` and `setBatch`, and run the contract suite: its first case tests the refusal. To adopt the version later, stamp a version field on the server, give the storage a `versionOf` that tests it in the write, and give the same `versionOf` to the `HybridStorage` of the client. Then add `createWithVersions` to the contract run.
445
+ - **An app without versions.** No change: it gives no expected version. A storage of the app that implements `CollectionStorage` must refuse a write with an expected version, as above.
412
446
  - **Other storages.** Each class that implements `CollectionStorage` reads the new options of `set`, `delete` and `setBatch`. It tests them in the write, or it rejects the write with `preconditionNotSupported()`. It never ignores them.
413
447
 
414
448
  ### Patch Changes
@@ -442,8 +476,8 @@
442
476
 
443
477
  ### Patch Changes
444
478
 
445
- - 3a235b9: New: the patch operations `$remove` and `$insert` (Graph's split, wave 2, W5). `$remove` takes an element out of an array, and the next elements move down by one, as the operation `remove` of JSON Patch (RFC 6902). For a field of an object, it is the same as `$unset`. `$insert` adds an element to an array at an index, as the operation `add` of JSON Patch. Each index of one patch refers to the item before the patch. A patch that removes and inserts elements of the same array is refused, and so is an `$insert` past the end of an array. `$unset` keeps the rule of MongoDB: an element of an array becomes `null`. The storage contract has a case for the two operations, so each storage gets them through `applyPatch`.
446
- - 50d4818: New: `inversePatch` and `UndoLog` (Graph's split, wave 2, W10). `inversePatch(before, patch)` gives the patch that undoes a patch. The inverse of a removal of an element is an insertion, and the inverse of an insertion is a removal, so an undo does not keep the whole array. The function applies the inverse to check it, and gives `undefined` when no patch undoes the change exactly. `UndoLog` keeps the undo of each change in a collection storage, with a cap, and the fingerprint of the item after the change (`fingerprintOf`). `undo()` undoes the newest change and the other changes of its group. It reads each item first, and refuses the whole group with an `UndoConflictError` when another writer changed an item. Then each item gets one write.
479
+ - 3a235b9: New: the patch operations `$remove` and `$insert`. `$remove` takes an element out of an array, and the next elements move down by one, as the operation `remove` of JSON Patch (RFC 6902). For a field of an object, it is the same as `$unset`. `$insert` adds an element to an array at an index, as the operation `add` of JSON Patch. Each index of one patch refers to the item before the patch. A patch that removes and inserts elements of the same array is refused, and so is an `$insert` past the end of an array. `$unset` keeps the rule of MongoDB: an element of an array becomes `null`. The storage contract has a case for the two operations, so each storage gets them through `applyPatch`.
480
+ - 50d4818: New: `inversePatch` and `UndoLog`. `inversePatch(before, patch)` gives the patch that undoes a patch. The inverse of a removal of an element is an insertion, and the inverse of an insertion is a removal, so an undo does not keep the whole array. The function applies the inverse to check it, and gives `undefined` when no patch undoes the change exactly. `UndoLog` keeps the undo of each change in a collection storage, with a cap, and the fingerprint of the item after the change (`fingerprintOf`). `undo()` undoes the newest change and the other changes of its group. It reads each item first, and refuses the whole group with an `UndoConflictError` when another writer changed an item. Then each item gets one write.
447
481
  - Updated dependencies [3a235b9]
448
482
  - @procedures/client@0.13.2
449
483
 
@@ -464,7 +498,7 @@
464
498
 
465
499
  ### Patch Changes
466
500
 
467
- - b6782c0: New: the order of a list as data (Graph's split, wave 2, W1). `keyBetween(prev, next)` gives a string key between two neighbors, so a move writes one item and no other. The keys use fractional indexing with 62 digits: they do not run out, and the list needs no rebalance. `keysForDrop` gives all the writes of a move, also when two writers gave two items the same key. `keysBetween` gives several keys, `compareKeys` sorts them, `isValidKey` examines a key that a client writes, and `dropIndex(point, centers)` gives the index of a point among the items on the screen, in reading order.
501
+ - b6782c0: New: the order of a list as data. `keyBetween(prev, next)` gives a string key between two neighbors, so a move writes one item and no other. The keys use fractional indexing with 62 digits: they do not run out, and the list needs no rebalance. `keysForDrop` gives all the writes of a move, also when two writers gave two items the same key. `keysBetween` gives several keys, `compareKeys` sorts them, `isValidKey` examines a key that a client writes, and `dropIndex(point, centers)` gives the index of a point among the items on the screen, in reading order.
468
502
  - @procedures/client@0.12.2
469
503
 
470
504
  ## 0.12.1
@@ -516,7 +550,7 @@
516
550
 
517
551
  - 0dd1c86: The overlay: one logical document read through a stack of layers. `mergeCopies` merges the copies field by field (`UNSET` hides a field, `_deleted` hides the document) or takes the top copy whole. `copyAsPatch` gives a copy as the patch operations of `applyPatch`.
518
552
 
519
- `resolveStacks` and `stackOf` give the read stack, the write targets and the merge mode of each collection and document. The rules name the layers with variables, and the app resolves them. Each change is additive. The code comes from Graph (its split plan, part P2).
553
+ `resolveStacks` and `stackOf` give the read stack, the write targets and the merge mode of each collection and document. The rules name the layers with variables, and the app resolves them. Each change is additive.
520
554
  - Updated dependencies [8bb469c]
521
555
  - Updated dependencies [dc03903]
522
556
  - Updated dependencies [dca28c1]
@@ -566,7 +600,7 @@
566
600
 
567
601
  ### Minor Changes
568
602
 
569
- - 5837c2d: `asSettled(promises)` gives the result of each promise when it settles, in settle order, with the index of its promise. A rejection is a result, not an error. jarvis used the same `Promise.race` loop in two places.
603
+ - 5837c2d: `asSettled(promises)` gives the result of each promise when it settles, in settle order, with the index of its promise. A rejection is a result, not an error. An app used the same `Promise.race` loop in two places.
570
604
 
571
605
  ## 0.6.0
572
606
 
package/README.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  A comprehensive, transport-agnostic collections framework for TypeScript. Provides unified abstractions for data structures with pluggable storage backends, enabling seamless switching between local and remote storage.
6
6
 
7
+ The pure data structures and graphs are in the general package [`@mark1russell7/collections`](https://www.npmjs.com/package/@mark1russell7/collections), which has no runtime dependencies. This package re-exports them and adds storage, overlay and undo.
8
+
7
9
  ## Architecture Overview
8
10
 
9
11
  ```
@@ -408,6 +410,34 @@ const pq = new PriorityQueue<Task>((a, b) => a.priority - b.priority);
408
410
  const deque = new ArrayDeque<Message>(); // Double-ended queue
409
411
  ```
410
412
 
413
+ ### Sequences with a summary: `SummaryTree`
414
+
415
+ `SummaryTree<Leaf, Summary>` is a persistent sequence of leaves. Each node keeps the summary of its part of the sequence. A summary is a value of a monoid that you give as data: `empty` and an associative `combine`.
416
+
417
+ - `concat`, `splitAt`, `split`, `slice`, `splice`, `insert`, `remove`, `set` and `at` are O(log n).
418
+ - `split(predicate)` splits before the first leaf whose prefix summary satisfies a monotone predicate. `search(predicate)` finds that leaf and changes nothing.
419
+ - `locate(key, target)` finds the leaf that holds a position of an additive key, and the offset in that leaf. It calls no `combine`, so it costs nothing when `combine` is slow.
420
+ - `set` and a `splice` of 8 leaves or fewer copy only the paths to their leaves. Each level of each path calls `combine` 1 or 2 times. A leaf that becomes two leaves costs one descent.
421
+ - The optional `spec.merge(left, right)` joins two neighbor leaves into one at each seam that an edit makes. A rope uses it to keep its chunks large.
422
+ - Each edit returns a new tree. The old tree does not change, and the two trees share the nodes that did not change.
423
+ - The tree is an AVL tree, so its height is at most 1.45 log2(n + 2).
424
+
425
+ ```typescript
426
+ import { summaryTree } from "@procedures/collections";
427
+
428
+ const spec = {
429
+ monoid: { empty: 0, combine: (a: number, b: number) => a + b },
430
+ measure: (line: string) => line.length,
431
+ };
432
+ const lines = summaryTree(spec, ["first line", "second", "third"]);
433
+ lines.summary; // 21
434
+ const hit = lines.search((length) => length > 12); // { index: 1, leaf: "second", before: 10, through: 16 }
435
+ const edited = lines.splice(1, 1, ["2nd"]); // lines does not change
436
+ const at = lines.locate((length) => length, 12); // { index: 1, leaf: "second", offset: 2 }
437
+ ```
438
+
439
+ Use the same `spec` object for each tree that `concat` or `splice` joins. A tree of a different spec causes a `TypeError`.
440
+
411
441
  ## Behavior Decorators
412
442
 
413
443
  ### Bounded Collections