@bablr/btree 0.4.1 → 0.4.3
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 +168 -116
- package/lib/index.js +5 -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
|
|
|
@@ -239,8 +235,12 @@ export const buildModule = (
|
|
|
239
235
|
return size ? addAt(size, tree, value) : treeFromValues([value]);
|
|
240
236
|
};
|
|
241
237
|
|
|
238
|
+
const unshift = (value, tree) => {
|
|
239
|
+
return addAt(0, tree, value);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
242
|
const collapses = (size) => {
|
|
243
|
-
return size
|
|
243
|
+
return size < NODE_SIZE / 2 - 0.01;
|
|
244
244
|
};
|
|
245
245
|
|
|
246
246
|
const nodeCollapses = (node) => {
|
|
@@ -248,13 +248,16 @@ export const buildModule = (
|
|
|
248
248
|
};
|
|
249
249
|
|
|
250
250
|
const nodeCanDonate = (node) => {
|
|
251
|
-
return collapses(getValues(node).length - 1);
|
|
251
|
+
return !collapses(getValues(node).length - 1);
|
|
252
252
|
};
|
|
253
253
|
|
|
254
254
|
const removeAt = (idx, tree) => {
|
|
255
|
+
if (idx > getSize(tree)) throw new Error('Index exceeds tree bounds');
|
|
256
|
+
|
|
255
257
|
let path = findPath(idx, tree);
|
|
256
258
|
|
|
257
|
-
let
|
|
259
|
+
let pathIdx = path.length - 1;
|
|
260
|
+
let { node, index } = path[pathIdx];
|
|
258
261
|
|
|
259
262
|
const initialValues = [...getValues(node)];
|
|
260
263
|
|
|
@@ -266,8 +269,8 @@ export const buildModule = (
|
|
|
266
269
|
let values = getValues(returnValue);
|
|
267
270
|
let adjustSibling = null;
|
|
268
271
|
|
|
269
|
-
if (
|
|
270
|
-
let { node: parentNode, index: parentIndex } = path
|
|
272
|
+
if (pathIdx >= 1 && nodeCollapses(returnValue)) {
|
|
273
|
+
let { node: parentNode, index: parentIndex } = path[pathIdx - 1];
|
|
271
274
|
const prevSibling = getValues(parentNode)[parentIndex - 1];
|
|
272
275
|
const nextSibling = getValues(parentNode)[parentIndex + 1];
|
|
273
276
|
let targetSibling = nodeCanDonate(prevSibling)
|
|
@@ -297,15 +300,12 @@ export const buildModule = (
|
|
|
297
300
|
}
|
|
298
301
|
}
|
|
299
302
|
|
|
300
|
-
if (
|
|
301
|
-
if (getSize(returnValue) <= NODE_SIZE) {
|
|
302
|
-
returnValue = setValues(returnValue, getValues(returnValue).flat());
|
|
303
|
-
}
|
|
303
|
+
if (pathIdx === 0) {
|
|
304
304
|
return returnValue;
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
-
|
|
308
|
-
({ node, index } = path
|
|
307
|
+
pathIdx--;
|
|
308
|
+
({ node, index } = path[pathIdx]);
|
|
309
309
|
|
|
310
310
|
values = getValues(node).slice();
|
|
311
311
|
|
|
@@ -328,6 +328,24 @@ export const buildModule = (
|
|
|
328
328
|
return removeAt(-1, tree);
|
|
329
329
|
};
|
|
330
330
|
|
|
331
|
+
const shift = (tree) => {
|
|
332
|
+
return removeAt(0, tree);
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const validateValues = (values) => {
|
|
336
|
+
if (values.length > NODE_SIZE) throw new Error();
|
|
337
|
+
if (!values.length) return;
|
|
338
|
+
|
|
339
|
+
let nodeIsLeaf = !isArray(values[0]);
|
|
340
|
+
for (let value of values) {
|
|
341
|
+
if (!nodeIsLeaf && nodeCollapses(value)) {
|
|
342
|
+
throw new Error('invalid btree: uncollapsed node');
|
|
343
|
+
} else if (!nodeIsLeaf && value == null) {
|
|
344
|
+
throw new Error('invalid btree: nil sibling');
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
331
349
|
const isValidNode = (node) => {
|
|
332
350
|
if (!isArray(node)) return false;
|
|
333
351
|
const values = getValues(node);
|
|
@@ -347,22 +365,27 @@ export const buildModule = (
|
|
|
347
365
|
|
|
348
366
|
const getSums = (node) => {
|
|
349
367
|
if (!isValidNode(node)) throw new Error();
|
|
350
|
-
|
|
368
|
+
let sums = Number.isFinite(node[0]) ? node[2] : null;
|
|
369
|
+
return sums || (buildStats ? buildStats(getValues(node)) : null);
|
|
351
370
|
};
|
|
352
371
|
|
|
353
372
|
const setValues = (node, values) => {
|
|
354
|
-
if (
|
|
373
|
+
if (isFinite(node[0]) || buildStats) {
|
|
374
|
+
return treeFromValues(values);
|
|
375
|
+
}
|
|
355
376
|
|
|
356
|
-
|
|
377
|
+
validateValues(values);
|
|
378
|
+
|
|
379
|
+
return freeze(values);
|
|
357
380
|
};
|
|
358
381
|
|
|
359
382
|
function* traverse(tree) {
|
|
360
|
-
let states =
|
|
383
|
+
let states = [{ node: tree, i: 0 }];
|
|
361
384
|
|
|
362
385
|
assertValidNode(tree);
|
|
363
386
|
|
|
364
|
-
stack: while (states.
|
|
365
|
-
const s = states.
|
|
387
|
+
stack: while (states.length) {
|
|
388
|
+
const s = states[states.length - 1];
|
|
366
389
|
const { node } = s;
|
|
367
390
|
|
|
368
391
|
const values = getValues(node);
|
|
@@ -372,7 +395,7 @@ export const buildModule = (
|
|
|
372
395
|
if (isArray(value)) {
|
|
373
396
|
let node = value;
|
|
374
397
|
assertValidNode(node);
|
|
375
|
-
states
|
|
398
|
+
states.push({ node, i: 0 });
|
|
376
399
|
i = ++s.i;
|
|
377
400
|
continue stack;
|
|
378
401
|
} else {
|
|
@@ -381,7 +404,7 @@ export const buildModule = (
|
|
|
381
404
|
}
|
|
382
405
|
}
|
|
383
406
|
|
|
384
|
-
states
|
|
407
|
+
states.pop();
|
|
385
408
|
}
|
|
386
409
|
}
|
|
387
410
|
|
|
@@ -399,15 +422,33 @@ export const buildModule = (
|
|
|
399
422
|
|
|
400
423
|
const findPath = (idx, tree, depth = Infinity) => {
|
|
401
424
|
if (idx == null) throw new Error();
|
|
425
|
+
if (tree && !isArray(tree)) throw new Error();
|
|
426
|
+
|
|
427
|
+
let path = [];
|
|
428
|
+
let node = tree;
|
|
402
429
|
|
|
403
|
-
|
|
430
|
+
if (isArray(idx)) {
|
|
431
|
+
for (let seg of idx) {
|
|
432
|
+
let index = typeof seg !== 'object' ? seg : seg.index;
|
|
433
|
+
if (typeof index === 'string') throw new Error();
|
|
434
|
+
if (!isArray(node)) return null;
|
|
435
|
+
let index_ = index < 0 ? getSize(node) + index : index;
|
|
436
|
+
path.push({ index: index_, node });
|
|
437
|
+
node = getValues(node)[index_];
|
|
438
|
+
if (node && !isArray(node)) {
|
|
439
|
+
return freeze(path);
|
|
440
|
+
}
|
|
441
|
+
if (!node) return null;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return freeze(path);
|
|
445
|
+
}
|
|
404
446
|
|
|
405
447
|
let treeSum = getSize(tree);
|
|
406
448
|
let currentIdx = idx < 0 ? treeSum - 1 : 0;
|
|
407
449
|
let direction = idx < 0 ? -1 : 1;
|
|
408
450
|
let targetIdx = idx < 0 ? treeSum + idx : idx;
|
|
409
451
|
|
|
410
|
-
let node = tree;
|
|
411
452
|
stack: while (node) {
|
|
412
453
|
assertValidNode(node);
|
|
413
454
|
|
|
@@ -422,17 +463,16 @@ export const buildModule = (
|
|
|
422
463
|
i += increment
|
|
423
464
|
) {
|
|
424
465
|
let value = values[i];
|
|
425
|
-
if (isArray(value) && path.
|
|
466
|
+
if (isArray(value) && path.length < depth) {
|
|
426
467
|
candidateNode = value;
|
|
427
468
|
|
|
428
469
|
const sum = getSize(candidateNode);
|
|
429
|
-
|
|
430
|
-
const nextCount = currentIdx + sum * direction;
|
|
470
|
+
const nextIndex = currentIdx + sum * direction;
|
|
431
471
|
if (
|
|
432
|
-
(backwards ?
|
|
433
|
-
(backwards ?
|
|
472
|
+
(backwards ? nextIndex < targetIdx : nextIndex > targetIdx) ||
|
|
473
|
+
(backwards ? nextIndex < 0 : nextIndex >= treeSum)
|
|
434
474
|
) {
|
|
435
|
-
path
|
|
475
|
+
path.push({ index: i, node });
|
|
436
476
|
node = candidateNode;
|
|
437
477
|
continue stack;
|
|
438
478
|
} else {
|
|
@@ -440,35 +480,43 @@ export const buildModule = (
|
|
|
440
480
|
}
|
|
441
481
|
} else {
|
|
442
482
|
const sum = getSize(value);
|
|
443
|
-
const
|
|
483
|
+
const nextIndex = currentIdx + sum * direction;
|
|
444
484
|
if (!isFinite(targetIdx)) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
return path
|
|
485
|
+
path.push({ index: targetIdx, node });
|
|
486
|
+
|
|
487
|
+
return freeze(path);
|
|
488
|
+
} else if (backwards ? nextIndex < targetIdx : nextIndex > targetIdx) {
|
|
489
|
+
path.push({ index: i, node });
|
|
490
|
+
|
|
491
|
+
return freeze(path);
|
|
448
492
|
} else if (
|
|
449
493
|
backwards
|
|
450
|
-
?
|
|
451
|
-
:
|
|
494
|
+
? nextIndex < targetIdx || nextIndex < 0
|
|
495
|
+
: nextIndex > targetIdx || nextIndex >= treeSum
|
|
452
496
|
) {
|
|
453
497
|
break;
|
|
454
498
|
} else {
|
|
455
|
-
currentIdx += direction;
|
|
499
|
+
currentIdx += direction * sum;
|
|
456
500
|
}
|
|
457
501
|
}
|
|
458
502
|
}
|
|
459
|
-
|
|
503
|
+
|
|
504
|
+
path.push({ index: backwards ? -Infinity : Infinity, node });
|
|
505
|
+
|
|
506
|
+
return freeze(path);
|
|
460
507
|
}
|
|
461
508
|
|
|
462
509
|
return null;
|
|
463
510
|
};
|
|
464
511
|
|
|
465
512
|
const getAt = (idx, tree) => {
|
|
466
|
-
const
|
|
467
|
-
|
|
513
|
+
const path = findPath(idx, tree);
|
|
514
|
+
let seg = path && path[path.length - 1];
|
|
515
|
+
return seg && getValues(seg.node)[seg.index];
|
|
468
516
|
};
|
|
469
517
|
|
|
470
518
|
const replaceAt = (idx, tree, value) => {
|
|
471
|
-
let path = findPath(idx, tree);
|
|
519
|
+
let path = findPath(idx, tree, getHeight(tree) - getHeight(value) - 1);
|
|
472
520
|
|
|
473
521
|
if (getSize(tree) < idx) {
|
|
474
522
|
throw new Error('Cannot add past the end of a list');
|
|
@@ -476,16 +524,17 @@ export const buildModule = (
|
|
|
476
524
|
return addAt(idx, tree, value);
|
|
477
525
|
}
|
|
478
526
|
|
|
479
|
-
let
|
|
527
|
+
let pathIndex = path.length - 1;
|
|
528
|
+
let { node, index } = path[pathIndex];
|
|
480
529
|
|
|
481
530
|
let returnValue = setValuesAt(index, node, value);
|
|
482
531
|
|
|
483
532
|
for (;;) {
|
|
484
|
-
({ node, index } = path
|
|
533
|
+
({ node, index } = path[pathIndex]);
|
|
485
534
|
|
|
486
|
-
if (
|
|
487
|
-
|
|
488
|
-
({ node, index } = path
|
|
535
|
+
if (pathIndex > 0) {
|
|
536
|
+
pathIndex--;
|
|
537
|
+
({ node, index } = path[pathIndex]);
|
|
489
538
|
|
|
490
539
|
returnValue = setValuesAt(index, node, returnValue);
|
|
491
540
|
} else {
|
|
@@ -505,10 +554,13 @@ export const buildModule = (
|
|
|
505
554
|
collapses,
|
|
506
555
|
nodeCollapses,
|
|
507
556
|
nodeCanDonate,
|
|
557
|
+
unshift,
|
|
508
558
|
pop,
|
|
509
559
|
removeAt,
|
|
510
560
|
push,
|
|
511
561
|
addAt,
|
|
562
|
+
shift,
|
|
563
|
+
unshift,
|
|
512
564
|
concat,
|
|
513
565
|
isValidNode,
|
|
514
566
|
assertValidNode,
|
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,7 +14,10 @@ export const {
|
|
|
14
14
|
nodeCanDonate,
|
|
15
15
|
pop,
|
|
16
16
|
push,
|
|
17
|
+
concat,
|
|
17
18
|
addAt,
|
|
19
|
+
shift,
|
|
20
|
+
unshift,
|
|
18
21
|
isValidNode,
|
|
19
22
|
assertValidNode,
|
|
20
23
|
getValues,
|
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.3",
|
|
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
|
}
|