@bablr/btree 0.4.1 → 0.4.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.
- package/README.md +13 -12
- package/lib/enhanceable.js +157 -116
- package/lib/index.js +3 -2
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
# @bablr/btree
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This library offers a set of functional utilities for working with immutable btrees such as those used in agAST.
|
|
4
4
|
|
|
5
5
|
```js
|
|
6
|
-
|
|
7
|
-
3,
|
|
8
|
-
[['a'], ['b', 'c']],
|
|
9
|
-
]);
|
|
6
|
+
import * as btree from '@bablr/btree';
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
let tree = btree.fromValues([]);
|
|
9
|
+
tree = btree.push('a');
|
|
10
|
+
tree = btree.push('b');
|
|
11
|
+
tree = btree.push('c');
|
|
12
|
+
let tree3 = tree;
|
|
13
|
+
tree = btree.concat(tree, tree);
|
|
14
|
+
tree = btree.concat(tree3, tree);
|
|
15
|
+
|
|
16
|
+
btree.getSize(tree); // 9
|
|
17
|
+
btree.getAt(-2, tree); // 'b'
|
|
18
|
+
[...btree.traverse(tree)]; // ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
|
|
18
19
|
```
|
package/lib/enhanceable.js
CHANGED
|
@@ -1,17 +1,31 @@
|
|
|
1
|
-
import emptyStack from '@iter-tools/imm-stack';
|
|
2
|
-
|
|
3
1
|
const { isArray } = Array;
|
|
4
2
|
const { freeze } = Object;
|
|
5
3
|
const { isFinite } = Number;
|
|
6
4
|
|
|
7
5
|
export const defaultNodeSize = 8;
|
|
8
6
|
|
|
9
|
-
export const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
export const deepFreeze = (object) => {
|
|
8
|
+
let stack = [object];
|
|
9
|
+
while (stack.length) {
|
|
10
|
+
let item = stack[stack.length - 1];
|
|
11
|
+
stack.pop();
|
|
12
|
+
|
|
13
|
+
for (const value of Object.values(item)) {
|
|
14
|
+
if (value && typeof value === 'object') {
|
|
15
|
+
if (
|
|
16
|
+
!(Array.isArray(value) || [Object.prototype, null].includes(Object.getPrototypeOf(value)))
|
|
17
|
+
)
|
|
18
|
+
throw new Error();
|
|
19
|
+
stack.push(value);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
Object.freeze(item);
|
|
24
|
+
}
|
|
25
|
+
return object;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const buildModule = (NODE_SIZE = defaultNodeSize, buildStats) => {
|
|
15
29
|
const sumNodes = (nodes) => {
|
|
16
30
|
return nodes.map(getSize).reduce((a, b) => a + b, 0);
|
|
17
31
|
};
|
|
@@ -29,7 +43,8 @@ export const buildModule = (
|
|
|
29
43
|
};
|
|
30
44
|
|
|
31
45
|
const treeFrom = (...values) => {
|
|
32
|
-
|
|
46
|
+
validateValues(values);
|
|
47
|
+
if (!buildStats && values.length <= NODE_SIZE) {
|
|
33
48
|
return freeze(values);
|
|
34
49
|
} else {
|
|
35
50
|
let tree = [];
|
|
@@ -40,19 +55,14 @@ export const buildModule = (
|
|
|
40
55
|
}
|
|
41
56
|
};
|
|
42
57
|
|
|
43
|
-
const buildStats = (values) => {
|
|
44
|
-
let sums = values.reduce(statsReducer, getSumsInitial());
|
|
45
|
-
sums = finalizeSums(sums);
|
|
46
|
-
return sums;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
58
|
const treeFromValues = (values) => {
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
validateValues(values);
|
|
60
|
+
|
|
61
|
+
if (!buildStats && values.length <= NODE_SIZE) {
|
|
52
62
|
return isArray(values[0]) ? freeze([sumNodes(values), freeze(values)]) : freeze(values);
|
|
53
63
|
} else {
|
|
54
64
|
if (values.length <= NODE_SIZE) {
|
|
55
|
-
if (
|
|
65
|
+
if (buildStats) {
|
|
56
66
|
return freeze([sumNodes(values), freeze(values), buildStats(values)]);
|
|
57
67
|
} else {
|
|
58
68
|
return freeze([sumNodes(values), freeze(values)]);
|
|
@@ -91,11 +101,11 @@ export const buildModule = (
|
|
|
91
101
|
|
|
92
102
|
let midIndex;
|
|
93
103
|
|
|
94
|
-
if (isLeaf) {
|
|
95
|
-
|
|
96
|
-
} else {
|
|
97
|
-
|
|
98
|
-
}
|
|
104
|
+
// if (isLeaf) {
|
|
105
|
+
midIndex = Math.floor(values.length / 2 + 0.01);
|
|
106
|
+
// } else {
|
|
107
|
+
// midIndex = findBalancePoint(values);
|
|
108
|
+
// }
|
|
99
109
|
|
|
100
110
|
let leftValues = values.slice(0, midIndex);
|
|
101
111
|
let rightValues = values.slice(midIndex);
|
|
@@ -125,60 +135,46 @@ export const buildModule = (
|
|
|
125
135
|
let firstValues = getValues(first);
|
|
126
136
|
let secondValues = getValues(second);
|
|
127
137
|
|
|
138
|
+
if (!secondValues.length) return first;
|
|
139
|
+
if (!firstValues.length) return second;
|
|
140
|
+
|
|
128
141
|
if (firstHeight === secondHeight) {
|
|
129
|
-
if (firstValues.length + secondValues.length
|
|
142
|
+
if (firstValues.length + secondValues.length <= NODE_SIZE) {
|
|
130
143
|
return treeFromValues([...firstValues, ...secondValues]);
|
|
131
144
|
} else {
|
|
132
|
-
|
|
145
|
+
let { leftValues, rightValues } = splitValues([...firstValues, ...secondValues]);
|
|
146
|
+
return treeFromValues([treeFromValues(leftValues), treeFromValues(rightValues)]);
|
|
133
147
|
}
|
|
134
148
|
} else {
|
|
135
|
-
let
|
|
136
|
-
let path =
|
|
137
|
-
firstHeight > secondHeight
|
|
138
|
-
? findPath(Infinity, first, targetDepth)
|
|
139
|
-
: findPath(0, second, targetDepth);
|
|
140
|
-
|
|
141
|
-
let { node, index } = path.value;
|
|
142
|
-
|
|
149
|
+
let tree = firstHeight <= secondHeight ? second : first;
|
|
143
150
|
let pushout = firstHeight > secondHeight ? second : first;
|
|
144
151
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
node = setValues(node, values);
|
|
163
|
-
pushout = null;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
152
|
+
if (!nodeCollapses(pushout)) {
|
|
153
|
+
let targetIndex = firstHeight > secondHeight ? getSize(tree) : 0;
|
|
154
|
+
return addAt(targetIndex, tree, pushout);
|
|
155
|
+
} else {
|
|
156
|
+
let depth = Math.abs(firstHeight - secondHeight) - 1;
|
|
157
|
+
let targetIndex = firstHeight > secondHeight ? getSize(tree) - 1 : 0;
|
|
158
|
+
let targetPath = findPath(targetIndex, tree, depth);
|
|
159
|
+
let lastIndex = targetPath.length - 1;
|
|
160
|
+
let targetNode = getValues(targetPath[lastIndex].node)[targetPath[lastIndex].index];
|
|
161
|
+
let combinedValues =
|
|
162
|
+
firstHeight > secondHeight
|
|
163
|
+
? [...getValues(targetNode), ...getValues(pushout)]
|
|
164
|
+
: [...getValues(pushout), ...getValues(targetNode)];
|
|
165
|
+
if (getValues(pushout).length + getValues(targetNode).length <= NODE_SIZE) {
|
|
166
|
+
return replaceAt(targetIndex, tree, treeFromValues(combinedValues));
|
|
167
|
+
} else {
|
|
168
|
+
let { leftValues, rightValues } = splitValues(combinedValues);
|
|
166
169
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return
|
|
170
|
+
if (firstHeight > secondHeight) {
|
|
171
|
+
return replaceAt(targetIndex, addAt(targetIndex + 1, tree, rightValues), leftValues);
|
|
172
|
+
// return addAt(targetIndex + 1, replaceAt(targetIndex, tree, leftValues), rightValues);
|
|
170
173
|
} else {
|
|
171
|
-
|
|
174
|
+
// TODO change order of operations like above?
|
|
175
|
+
return addAt(targetIndex, replaceAt(targetIndex, tree, rightValues), leftValues);
|
|
172
176
|
}
|
|
173
177
|
}
|
|
174
|
-
|
|
175
|
-
const poppedNode = node;
|
|
176
|
-
path = path.pop();
|
|
177
|
-
({ node, index } = path.value);
|
|
178
|
-
|
|
179
|
-
node = setValuesAt(index, node, poppedNode);
|
|
180
|
-
values = getValues(node);
|
|
181
|
-
path = path.replace({ node, index });
|
|
182
178
|
}
|
|
183
179
|
}
|
|
184
180
|
};
|
|
@@ -188,9 +184,10 @@ export const buildModule = (
|
|
|
188
184
|
if (!isArray(tree)) throw new Error();
|
|
189
185
|
if (!value) throw new Error();
|
|
190
186
|
|
|
191
|
-
let path = findPath(idx, tree);
|
|
187
|
+
let path = findPath(idx, tree, getHeight(tree) - getHeight(value) - 1);
|
|
192
188
|
|
|
193
|
-
let
|
|
189
|
+
let pathIdx = path.length - 1;
|
|
190
|
+
let { node, index } = path[pathIdx];
|
|
194
191
|
|
|
195
192
|
let pushout = value;
|
|
196
193
|
|
|
@@ -203,7 +200,7 @@ export const buildModule = (
|
|
|
203
200
|
let finiteIndex = index === Infinity ? values.length : index;
|
|
204
201
|
|
|
205
202
|
if (!isFinite(finiteIndex)) throw new Error();
|
|
206
|
-
if (values.length +
|
|
203
|
+
if (values.length + (pushout ? 1 : 0) > NODE_SIZE) {
|
|
207
204
|
values.splice(finiteIndex, 0, pushout);
|
|
208
205
|
const { leftValues, rightValues } = splitValues(values);
|
|
209
206
|
|
|
@@ -216,7 +213,7 @@ export const buildModule = (
|
|
|
216
213
|
}
|
|
217
214
|
}
|
|
218
215
|
|
|
219
|
-
if (
|
|
216
|
+
if (pathIdx === 0) {
|
|
220
217
|
if (pushout) {
|
|
221
218
|
return treeFromValues([pushout, node]);
|
|
222
219
|
} else {
|
|
@@ -225,12 +222,11 @@ export const buildModule = (
|
|
|
225
222
|
}
|
|
226
223
|
|
|
227
224
|
const poppedNode = node;
|
|
228
|
-
|
|
229
|
-
({ node, index } = path
|
|
225
|
+
pathIdx--;
|
|
226
|
+
({ node, index } = path[pathIdx]);
|
|
230
227
|
|
|
231
228
|
node = setValuesAt(index, node, poppedNode);
|
|
232
229
|
values = getValues(node);
|
|
233
|
-
path = path.replace({ node, index });
|
|
234
230
|
}
|
|
235
231
|
};
|
|
236
232
|
|
|
@@ -240,7 +236,7 @@ export const buildModule = (
|
|
|
240
236
|
};
|
|
241
237
|
|
|
242
238
|
const collapses = (size) => {
|
|
243
|
-
return size
|
|
239
|
+
return size < NODE_SIZE / 2 - 0.01;
|
|
244
240
|
};
|
|
245
241
|
|
|
246
242
|
const nodeCollapses = (node) => {
|
|
@@ -248,13 +244,16 @@ export const buildModule = (
|
|
|
248
244
|
};
|
|
249
245
|
|
|
250
246
|
const nodeCanDonate = (node) => {
|
|
251
|
-
return collapses(getValues(node).length - 1);
|
|
247
|
+
return !collapses(getValues(node).length - 1);
|
|
252
248
|
};
|
|
253
249
|
|
|
254
250
|
const removeAt = (idx, tree) => {
|
|
251
|
+
if (idx > getSize(tree)) throw new Error('Index exceeds tree bounds');
|
|
252
|
+
|
|
255
253
|
let path = findPath(idx, tree);
|
|
256
254
|
|
|
257
|
-
let
|
|
255
|
+
let pathIdx = path.length - 1;
|
|
256
|
+
let { node, index } = path[pathIdx];
|
|
258
257
|
|
|
259
258
|
const initialValues = [...getValues(node)];
|
|
260
259
|
|
|
@@ -266,8 +265,8 @@ export const buildModule = (
|
|
|
266
265
|
let values = getValues(returnValue);
|
|
267
266
|
let adjustSibling = null;
|
|
268
267
|
|
|
269
|
-
if (
|
|
270
|
-
let { node: parentNode, index: parentIndex } = path
|
|
268
|
+
if (pathIdx >= 1 && nodeCollapses(returnValue)) {
|
|
269
|
+
let { node: parentNode, index: parentIndex } = path[pathIdx - 1];
|
|
271
270
|
const prevSibling = getValues(parentNode)[parentIndex - 1];
|
|
272
271
|
const nextSibling = getValues(parentNode)[parentIndex + 1];
|
|
273
272
|
let targetSibling = nodeCanDonate(prevSibling)
|
|
@@ -297,15 +296,12 @@ export const buildModule = (
|
|
|
297
296
|
}
|
|
298
297
|
}
|
|
299
298
|
|
|
300
|
-
if (
|
|
301
|
-
if (getSize(returnValue) <= NODE_SIZE) {
|
|
302
|
-
returnValue = setValues(returnValue, getValues(returnValue).flat());
|
|
303
|
-
}
|
|
299
|
+
if (pathIdx === 0) {
|
|
304
300
|
return returnValue;
|
|
305
301
|
}
|
|
306
302
|
|
|
307
|
-
|
|
308
|
-
({ node, index } = path
|
|
303
|
+
pathIdx--;
|
|
304
|
+
({ node, index } = path[pathIdx]);
|
|
309
305
|
|
|
310
306
|
values = getValues(node).slice();
|
|
311
307
|
|
|
@@ -328,6 +324,20 @@ export const buildModule = (
|
|
|
328
324
|
return removeAt(-1, tree);
|
|
329
325
|
};
|
|
330
326
|
|
|
327
|
+
const validateValues = (values) => {
|
|
328
|
+
if (values.length > NODE_SIZE) throw new Error();
|
|
329
|
+
if (!values.length) return;
|
|
330
|
+
|
|
331
|
+
let nodeIsLeaf = !isArray(values[0]);
|
|
332
|
+
for (let value of values) {
|
|
333
|
+
if (!nodeIsLeaf && nodeCollapses(value)) {
|
|
334
|
+
throw new Error('invalid btree: uncollapsed node');
|
|
335
|
+
} else if (!nodeIsLeaf && value == null) {
|
|
336
|
+
throw new Error('invalid btree: nil sibling');
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
331
341
|
const isValidNode = (node) => {
|
|
332
342
|
if (!isArray(node)) return false;
|
|
333
343
|
const values = getValues(node);
|
|
@@ -347,22 +357,27 @@ export const buildModule = (
|
|
|
347
357
|
|
|
348
358
|
const getSums = (node) => {
|
|
349
359
|
if (!isValidNode(node)) throw new Error();
|
|
350
|
-
|
|
360
|
+
let sums = Number.isFinite(node[0]) ? node[2] : null;
|
|
361
|
+
return sums || (buildStats ? buildStats(getValues(node)) : null);
|
|
351
362
|
};
|
|
352
363
|
|
|
353
364
|
const setValues = (node, values) => {
|
|
354
|
-
if (
|
|
365
|
+
if (isFinite(node[0]) || buildStats) {
|
|
366
|
+
return treeFromValues(values);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
validateValues(values);
|
|
355
370
|
|
|
356
|
-
return
|
|
371
|
+
return freeze(values);
|
|
357
372
|
};
|
|
358
373
|
|
|
359
374
|
function* traverse(tree) {
|
|
360
|
-
let states =
|
|
375
|
+
let states = [{ node: tree, i: 0 }];
|
|
361
376
|
|
|
362
377
|
assertValidNode(tree);
|
|
363
378
|
|
|
364
|
-
stack: while (states.
|
|
365
|
-
const s = states.
|
|
379
|
+
stack: while (states.length) {
|
|
380
|
+
const s = states[states.length - 1];
|
|
366
381
|
const { node } = s;
|
|
367
382
|
|
|
368
383
|
const values = getValues(node);
|
|
@@ -372,7 +387,7 @@ export const buildModule = (
|
|
|
372
387
|
if (isArray(value)) {
|
|
373
388
|
let node = value;
|
|
374
389
|
assertValidNode(node);
|
|
375
|
-
states
|
|
390
|
+
states.push({ node, i: 0 });
|
|
376
391
|
i = ++s.i;
|
|
377
392
|
continue stack;
|
|
378
393
|
} else {
|
|
@@ -381,7 +396,7 @@ export const buildModule = (
|
|
|
381
396
|
}
|
|
382
397
|
}
|
|
383
398
|
|
|
384
|
-
states
|
|
399
|
+
states.pop();
|
|
385
400
|
}
|
|
386
401
|
}
|
|
387
402
|
|
|
@@ -399,15 +414,33 @@ export const buildModule = (
|
|
|
399
414
|
|
|
400
415
|
const findPath = (idx, tree, depth = Infinity) => {
|
|
401
416
|
if (idx == null) throw new Error();
|
|
417
|
+
if (tree && !isArray(tree)) throw new Error();
|
|
402
418
|
|
|
403
|
-
let path =
|
|
419
|
+
let path = [];
|
|
420
|
+
let node = tree;
|
|
421
|
+
|
|
422
|
+
if (isArray(idx)) {
|
|
423
|
+
for (let seg of idx) {
|
|
424
|
+
let index = typeof seg !== 'object' ? seg : seg.index;
|
|
425
|
+
if (typeof index === 'string') throw new Error();
|
|
426
|
+
if (!isArray(node)) return null;
|
|
427
|
+
let index_ = index < 0 ? getSize(node) + index : index;
|
|
428
|
+
path.push({ index: index_, node });
|
|
429
|
+
node = getValues(node)[index_];
|
|
430
|
+
if (node && !isArray(node)) {
|
|
431
|
+
return freeze(path);
|
|
432
|
+
}
|
|
433
|
+
if (!node) return null;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return freeze(path);
|
|
437
|
+
}
|
|
404
438
|
|
|
405
439
|
let treeSum = getSize(tree);
|
|
406
440
|
let currentIdx = idx < 0 ? treeSum - 1 : 0;
|
|
407
441
|
let direction = idx < 0 ? -1 : 1;
|
|
408
442
|
let targetIdx = idx < 0 ? treeSum + idx : idx;
|
|
409
443
|
|
|
410
|
-
let node = tree;
|
|
411
444
|
stack: while (node) {
|
|
412
445
|
assertValidNode(node);
|
|
413
446
|
|
|
@@ -422,17 +455,16 @@ export const buildModule = (
|
|
|
422
455
|
i += increment
|
|
423
456
|
) {
|
|
424
457
|
let value = values[i];
|
|
425
|
-
if (isArray(value) && path.
|
|
458
|
+
if (isArray(value) && path.length < depth) {
|
|
426
459
|
candidateNode = value;
|
|
427
460
|
|
|
428
461
|
const sum = getSize(candidateNode);
|
|
429
|
-
|
|
430
|
-
const nextCount = currentIdx + sum * direction;
|
|
462
|
+
const nextIndex = currentIdx + sum * direction;
|
|
431
463
|
if (
|
|
432
|
-
(backwards ?
|
|
433
|
-
(backwards ?
|
|
464
|
+
(backwards ? nextIndex < targetIdx : nextIndex > targetIdx) ||
|
|
465
|
+
(backwards ? nextIndex < 0 : nextIndex >= treeSum)
|
|
434
466
|
) {
|
|
435
|
-
path
|
|
467
|
+
path.push({ index: i, node });
|
|
436
468
|
node = candidateNode;
|
|
437
469
|
continue stack;
|
|
438
470
|
} else {
|
|
@@ -440,35 +472,43 @@ export const buildModule = (
|
|
|
440
472
|
}
|
|
441
473
|
} else {
|
|
442
474
|
const sum = getSize(value);
|
|
443
|
-
const
|
|
475
|
+
const nextIndex = currentIdx + sum * direction;
|
|
444
476
|
if (!isFinite(targetIdx)) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
return path
|
|
477
|
+
path.push({ index: targetIdx, node });
|
|
478
|
+
|
|
479
|
+
return freeze(path);
|
|
480
|
+
} else if (backwards ? nextIndex < targetIdx : nextIndex > targetIdx) {
|
|
481
|
+
path.push({ index: i, node });
|
|
482
|
+
|
|
483
|
+
return freeze(path);
|
|
448
484
|
} else if (
|
|
449
485
|
backwards
|
|
450
|
-
?
|
|
451
|
-
:
|
|
486
|
+
? nextIndex < targetIdx || nextIndex < 0
|
|
487
|
+
: nextIndex > targetIdx || nextIndex >= treeSum
|
|
452
488
|
) {
|
|
453
489
|
break;
|
|
454
490
|
} else {
|
|
455
|
-
currentIdx += direction;
|
|
491
|
+
currentIdx += direction * sum;
|
|
456
492
|
}
|
|
457
493
|
}
|
|
458
494
|
}
|
|
459
|
-
|
|
495
|
+
|
|
496
|
+
path.push({ index: backwards ? -Infinity : Infinity, node });
|
|
497
|
+
|
|
498
|
+
return freeze(path);
|
|
460
499
|
}
|
|
461
500
|
|
|
462
501
|
return null;
|
|
463
502
|
};
|
|
464
503
|
|
|
465
504
|
const getAt = (idx, tree) => {
|
|
466
|
-
const
|
|
467
|
-
|
|
505
|
+
const path = findPath(idx, tree);
|
|
506
|
+
let seg = path && path[path.length - 1];
|
|
507
|
+
return seg && getValues(seg.node)[seg.index];
|
|
468
508
|
};
|
|
469
509
|
|
|
470
510
|
const replaceAt = (idx, tree, value) => {
|
|
471
|
-
let path = findPath(idx, tree);
|
|
511
|
+
let path = findPath(idx, tree, getHeight(tree) - getHeight(value) - 1);
|
|
472
512
|
|
|
473
513
|
if (getSize(tree) < idx) {
|
|
474
514
|
throw new Error('Cannot add past the end of a list');
|
|
@@ -476,16 +516,17 @@ export const buildModule = (
|
|
|
476
516
|
return addAt(idx, tree, value);
|
|
477
517
|
}
|
|
478
518
|
|
|
479
|
-
let
|
|
519
|
+
let pathIndex = path.length - 1;
|
|
520
|
+
let { node, index } = path[pathIndex];
|
|
480
521
|
|
|
481
522
|
let returnValue = setValuesAt(index, node, value);
|
|
482
523
|
|
|
483
524
|
for (;;) {
|
|
484
|
-
({ node, index } = path
|
|
525
|
+
({ node, index } = path[pathIndex]);
|
|
485
526
|
|
|
486
|
-
if (
|
|
487
|
-
|
|
488
|
-
({ node, index } = path
|
|
527
|
+
if (pathIndex > 0) {
|
|
528
|
+
pathIndex--;
|
|
529
|
+
({ node, index } = path[pathIndex]);
|
|
489
530
|
|
|
490
531
|
returnValue = setValuesAt(index, node, returnValue);
|
|
491
532
|
} else {
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { defaultNodeSize, buildModule } from './enhanceable.js';
|
|
1
|
+
import { defaultNodeSize, deepFreeze, buildModule } from './enhanceable.js';
|
|
2
2
|
|
|
3
|
-
export { defaultNodeSize };
|
|
3
|
+
export { defaultNodeSize, deepFreeze };
|
|
4
4
|
|
|
5
5
|
export const {
|
|
6
6
|
btreeFrom,
|
|
@@ -14,6 +14,7 @@ export const {
|
|
|
14
14
|
nodeCanDonate,
|
|
15
15
|
pop,
|
|
16
16
|
push,
|
|
17
|
+
concat,
|
|
17
18
|
addAt,
|
|
18
19
|
isValidNode,
|
|
19
20
|
assertValidNode,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/btree",
|
|
3
3
|
"description": "Functional utilities for working with btrees such as those used in agAST",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.2",
|
|
5
5
|
"author": "Conrad Buck<conartist6@gmail.com>",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -15,9 +15,7 @@
|
|
|
15
15
|
"scripts": {
|
|
16
16
|
"test": "mocha test/*.test.js"
|
|
17
17
|
},
|
|
18
|
-
"dependencies": {
|
|
19
|
-
"@iter-tools/imm-stack": "1.2.0"
|
|
20
|
-
},
|
|
18
|
+
"dependencies": {},
|
|
21
19
|
"devDependencies": {
|
|
22
20
|
"@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#c97bfa4b3663f8378e9b3e42bb5a41e685406cf9",
|
|
23
21
|
"enhanced-resolve": "^5.12.0",
|
|
@@ -29,7 +27,10 @@
|
|
|
29
27
|
"mocha": "10.7.3",
|
|
30
28
|
"prettier": "^2.6.2"
|
|
31
29
|
},
|
|
32
|
-
"repository":
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/bablr-lang/btree.git"
|
|
33
|
+
},
|
|
33
34
|
"homepage": "https://github.com/bablr-lang/btree",
|
|
34
35
|
"license": "MIT"
|
|
35
36
|
}
|