@atlaspack/graph 3.3.2-dev.3682 → 3.4.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.
package/lib/BitSet.js DELETED
@@ -1,80 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.BitSet = void 0;
7
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32#implementing_count_leading_ones_and_beyond
8
- function ctz32(n) {
9
- if (n === 0) {
10
- return 32;
11
- }
12
- return 31 - Math.clz32(n & -n);
13
- }
14
- class BitSet {
15
- constructor(maxBits) {
16
- this.bits = new Uint32Array(Math.ceil(maxBits / 32));
17
- }
18
- clone() {
19
- let res = new BitSet(this.capacity);
20
- res.bits.set(this.bits);
21
- return res;
22
- }
23
- static union(a, b) {
24
- let res = a.clone();
25
- res.union(b);
26
- return res;
27
- }
28
- get capacity() {
29
- return this.bits.length * 32;
30
- }
31
- add(bit) {
32
- this.bits[bit >>> 5] |= 1 << (bit & 31);
33
- }
34
- delete(bit) {
35
- this.bits[bit >>> 5] &= ~(1 << (bit & 31));
36
- }
37
- has(bit) {
38
- return Boolean(this.bits[bit >>> 5] & 1 << (bit & 31));
39
- }
40
- empty() {
41
- for (let k = 0; k < this.bits.length; k++) {
42
- if (this.bits[k] !== 0) {
43
- return false;
44
- }
45
- }
46
- return true;
47
- }
48
- clear() {
49
- this.bits.fill(0);
50
- }
51
- intersect(other) {
52
- for (let i = 0; i < this.bits.length; i++) {
53
- this.bits[i] &= other.bits[i];
54
- }
55
- }
56
- union(other) {
57
- for (let i = 0; i < this.bits.length; i++) {
58
- this.bits[i] |= other.bits[i];
59
- }
60
- }
61
- remove(other) {
62
- for (let i = 0; i < this.bits.length; i++) {
63
- this.bits[i] &= ~other.bits[i];
64
- }
65
- }
66
- forEach(fn) {
67
- // https://lemire.me/blog/2018/02/21/iterating-over-set-bits-quickly/
68
- let bits = this.bits;
69
- for (let k = 0; k < bits.length; k++) {
70
- let v = bits[k];
71
- while (v !== 0) {
72
- let t = (v & -v) >>> 0;
73
- // $FlowFixMe
74
- fn((k << 5) + ctz32(v));
75
- v ^= t;
76
- }
77
- }
78
- }
79
- }
80
- exports.BitSet = BitSet;
@@ -1,83 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _Graph = _interopRequireDefault(require("./Graph"));
8
- function _nullthrows() {
9
- const data = _interopRequireDefault(require("nullthrows"));
10
- _nullthrows = function () {
11
- return data;
12
- };
13
- return data;
14
- }
15
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
- class ContentGraph extends _Graph.default {
17
- constructor(opts) {
18
- if (opts) {
19
- let {
20
- _contentKeyToNodeId,
21
- _nodeIdToContentKey,
22
- ...rest
23
- } = opts;
24
- super(rest);
25
- this._contentKeyToNodeId = _contentKeyToNodeId;
26
- this._nodeIdToContentKey = _nodeIdToContentKey;
27
- } else {
28
- super();
29
- this._contentKeyToNodeId = new Map();
30
- this._nodeIdToContentKey = new Map();
31
- }
32
- }
33
-
34
- // $FlowFixMe[prop-missing]
35
- static deserialize(opts) {
36
- return new ContentGraph(opts);
37
- }
38
-
39
- // $FlowFixMe[prop-missing]
40
- serialize() {
41
- // $FlowFixMe[prop-missing]
42
- return {
43
- ...super.serialize(),
44
- _contentKeyToNodeId: this._contentKeyToNodeId,
45
- _nodeIdToContentKey: this._nodeIdToContentKey
46
- };
47
- }
48
- addNodeByContentKey(contentKey, node) {
49
- if (this.hasContentKey(contentKey)) {
50
- throw new Error('Graph already has content key ' + contentKey);
51
- }
52
- let nodeId = super.addNode(node);
53
- this._contentKeyToNodeId.set(contentKey, nodeId);
54
- this._nodeIdToContentKey.set(nodeId, contentKey);
55
- return nodeId;
56
- }
57
- addNodeByContentKeyIfNeeded(contentKey, node) {
58
- return this.hasContentKey(contentKey) ? this.getNodeIdByContentKey(contentKey) : this.addNodeByContentKey(contentKey, node);
59
- }
60
- getNodeByContentKey(contentKey) {
61
- let nodeId = this._contentKeyToNodeId.get(contentKey);
62
- if (nodeId != null) {
63
- return super.getNode(nodeId);
64
- }
65
- }
66
- getContentKeyByNodeId(nodeId) {
67
- return (0, _nullthrows().default)(this._nodeIdToContentKey.get(nodeId), `Expected node id ${nodeId} to exist`);
68
- }
69
- getNodeIdByContentKey(contentKey) {
70
- return (0, _nullthrows().default)(this._contentKeyToNodeId.get(contentKey), `Expected content key ${contentKey} to exist`);
71
- }
72
- hasContentKey(contentKey) {
73
- return this._contentKeyToNodeId.has(contentKey);
74
- }
75
- removeNode(nodeId, removeOrphans = true) {
76
- this._assertHasNodeId(nodeId);
77
- let contentKey = (0, _nullthrows().default)(this._nodeIdToContentKey.get(nodeId));
78
- this._contentKeyToNodeId.delete(contentKey);
79
- this._nodeIdToContentKey.delete(nodeId);
80
- super.removeNode(nodeId, removeOrphans);
81
- }
82
- }
83
- exports.default = ContentGraph;
package/lib/Graph.js DELETED
@@ -1,536 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = exports.NULL_EDGE_TYPE = exports.ALL_EDGE_TYPES = void 0;
7
- exports.mapVisitor = mapVisitor;
8
- var _types = require("./types");
9
- var _AdjacencyList = _interopRequireDefault(require("./AdjacencyList"));
10
- var _BitSet = require("./BitSet");
11
- function _nullthrows() {
12
- const data = _interopRequireDefault(require("nullthrows"));
13
- _nullthrows = function () {
14
- return data;
15
- };
16
- return data;
17
- }
18
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
- const NULL_EDGE_TYPE = exports.NULL_EDGE_TYPE = 1;
20
- const ALL_EDGE_TYPES = exports.ALL_EDGE_TYPES = -1;
21
-
22
- /**
23
- * Internal type used for queue iterative DFS implementation.
24
- */
25
-
26
- /**
27
- * Options for DFS traversal.
28
- */
29
-
30
- class Graph {
31
- constructor(opts) {
32
- this.nodes = (opts === null || opts === void 0 ? void 0 : opts.nodes) || [];
33
- this.setRootNodeId(opts === null || opts === void 0 ? void 0 : opts.rootNodeId);
34
- let adjacencyList = opts === null || opts === void 0 ? void 0 : opts.adjacencyList;
35
- let initialCapacity = opts === null || opts === void 0 ? void 0 : opts.initialCapacity;
36
- this.adjacencyList = adjacencyList ? _AdjacencyList.default.deserialize(adjacencyList) : new _AdjacencyList.default(typeof initialCapacity === 'number' ? {
37
- initialCapacity
38
- } : undefined);
39
- }
40
- setRootNodeId(id) {
41
- this.rootNodeId = id;
42
- }
43
- static deserialize(opts) {
44
- return new this({
45
- nodes: opts.nodes,
46
- adjacencyList: opts.adjacencyList,
47
- rootNodeId: opts.rootNodeId
48
- });
49
- }
50
- serialize() {
51
- return {
52
- nodes: this.nodes,
53
- adjacencyList: this.adjacencyList.serialize(),
54
- rootNodeId: this.rootNodeId
55
- };
56
- }
57
-
58
- // Returns an iterator of all edges in the graph. This can be large, so iterating
59
- // the complete list can be costly in large graphs. Used when merging graphs.
60
- getAllEdges() {
61
- return this.adjacencyList.getAllEdges();
62
- }
63
- addNode(node) {
64
- let id = this.adjacencyList.addNode();
65
- this.nodes.push(node);
66
- return id;
67
- }
68
- hasNode(id) {
69
- return this.nodes[id] != null;
70
- }
71
- getNode(id) {
72
- return this.nodes[id];
73
- }
74
- addEdge(from, to, type = NULL_EDGE_TYPE) {
75
- if (Number(type) === 0) {
76
- throw new Error(`Edge type "${type}" not allowed`);
77
- }
78
- if (this.getNode(from) == null) {
79
- throw new Error(`"from" node '${(0, _types.fromNodeId)(from)}' not found`);
80
- }
81
- if (this.getNode(to) == null) {
82
- throw new Error(`"to" node '${(0, _types.fromNodeId)(to)}' not found`);
83
- }
84
- return this.adjacencyList.addEdge(from, to, type);
85
- }
86
- hasEdge(from, to, type = NULL_EDGE_TYPE) {
87
- return this.adjacencyList.hasEdge(from, to, type);
88
- }
89
- forEachNodeIdConnectedTo(to, fn, type = NULL_EDGE_TYPE) {
90
- this._assertHasNodeId(to);
91
- this.adjacencyList.forEachNodeIdConnectedTo(to, fn, type);
92
- }
93
- forEachNodeIdConnectedFrom(from, fn, type = NULL_EDGE_TYPE) {
94
- this._assertHasNodeId(from);
95
- this.adjacencyList.forEachNodeIdConnectedFromReverse(from, id => {
96
- fn(id);
97
- return false;
98
- }, type);
99
- }
100
- getNodeIdsConnectedTo(nodeId, type = NULL_EDGE_TYPE) {
101
- this._assertHasNodeId(nodeId);
102
- return this.adjacencyList.getNodeIdsConnectedTo(nodeId, type);
103
- }
104
- getNodeIdsConnectedFrom(nodeId, type = NULL_EDGE_TYPE) {
105
- this._assertHasNodeId(nodeId);
106
- return this.adjacencyList.getNodeIdsConnectedFrom(nodeId, type);
107
- }
108
-
109
- // Removes node and any edges coming from or to that node
110
- removeNode(nodeId, removeOrphans = true) {
111
- if (!this.hasNode(nodeId)) {
112
- return;
113
- }
114
- for (let {
115
- type,
116
- from
117
- } of this.adjacencyList.getInboundEdgesByType(nodeId)) {
118
- this._removeEdge(from, nodeId, type,
119
- // Do not allow orphans to be removed as this node could be one
120
- // and is already being removed.
121
- false);
122
- }
123
- for (let {
124
- type,
125
- to
126
- } of this.adjacencyList.getOutboundEdgesByType(nodeId)) {
127
- this._removeEdge(nodeId, to, type, removeOrphans);
128
- }
129
- this.nodes[nodeId] = null;
130
- }
131
- removeEdges(nodeId, type = NULL_EDGE_TYPE) {
132
- if (!this.hasNode(nodeId)) {
133
- return;
134
- }
135
- for (let to of this.getNodeIdsConnectedFrom(nodeId, type)) {
136
- this._removeEdge(nodeId, to, type);
137
- }
138
- }
139
- removeEdge(from, to, type = NULL_EDGE_TYPE, removeOrphans = true) {
140
- if (!this.adjacencyList.hasEdge(from, to, type)) {
141
- throw new Error(`Edge from ${(0, _types.fromNodeId)(from)} to ${(0, _types.fromNodeId)(to)} not found!`);
142
- }
143
- this._removeEdge(from, to, type, removeOrphans);
144
- }
145
-
146
- // Removes edge and node the edge is to if the node is orphaned
147
- _removeEdge(from, to, type = NULL_EDGE_TYPE, removeOrphans = true) {
148
- if (!this.adjacencyList.hasEdge(from, to, type)) {
149
- return;
150
- }
151
- this.adjacencyList.removeEdge(from, to, type);
152
- if (removeOrphans && this.isOrphanedNode(to)) {
153
- this.removeNode(to);
154
- }
155
- }
156
- isOrphanedNode(nodeId) {
157
- if (!this.hasNode(nodeId)) {
158
- return false;
159
- }
160
- if (this.rootNodeId == null) {
161
- // If the graph does not have a root, and there are inbound edges,
162
- // this node should not be considered orphaned.
163
- return !this.adjacencyList.hasInboundEdges(nodeId);
164
- }
165
-
166
- // Otherwise, attempt to traverse backwards to the root. If there is a path,
167
- // then this is not an orphaned node.
168
- let hasPathToRoot = false;
169
- // go back to traverseAncestors
170
- this.traverseAncestors(nodeId, (ancestorId, _, actions) => {
171
- if (ancestorId === this.rootNodeId) {
172
- hasPathToRoot = true;
173
- actions.stop();
174
- }
175
- }, ALL_EDGE_TYPES);
176
- if (hasPathToRoot) {
177
- return false;
178
- }
179
- return true;
180
- }
181
- updateNode(nodeId, node) {
182
- this._assertHasNodeId(nodeId);
183
- this.nodes[nodeId] = node;
184
- }
185
-
186
- // Update a node's downstream nodes making sure to prune any orphaned branches
187
- replaceNodeIdsConnectedTo(fromNodeId, toNodeIds, replaceFilter, type = NULL_EDGE_TYPE, removeOrphans = true) {
188
- this._assertHasNodeId(fromNodeId);
189
- let outboundEdges = this.getNodeIdsConnectedFrom(fromNodeId, type);
190
- let childrenToRemove = new Set(replaceFilter ? outboundEdges.filter(toNodeId => replaceFilter(toNodeId)) : outboundEdges);
191
- for (let toNodeId of toNodeIds) {
192
- childrenToRemove.delete(toNodeId);
193
- if (!this.hasEdge(fromNodeId, toNodeId, type)) {
194
- this.addEdge(fromNodeId, toNodeId, type);
195
- }
196
- }
197
- for (let child of childrenToRemove) {
198
- this._removeEdge(fromNodeId, child, type, removeOrphans);
199
- }
200
- }
201
- traverse(visit, startNodeId, type = NULL_EDGE_TYPE) {
202
- let enter = typeof visit === 'function' ? visit : visit.enter;
203
- if (type === ALL_EDGE_TYPES && enter && (typeof visit === 'function' || !visit.exit)) {
204
- return this.dfsFast(enter, startNodeId);
205
- } else {
206
- return this.dfs({
207
- visit,
208
- startNodeId,
209
- getChildren: nodeId => this.getNodeIdsConnectedFrom(nodeId, type)
210
- });
211
- }
212
- }
213
- filteredTraverse(filter, visit, startNodeId, type) {
214
- return this.traverse(mapVisitor(filter, visit), startNodeId, type);
215
- }
216
- traverseAncestors(startNodeId, visit, type = NULL_EDGE_TYPE) {
217
- return this.dfs({
218
- visit,
219
- startNodeId,
220
- getChildren: nodeId => this.getNodeIdsConnectedTo(nodeId, type)
221
- });
222
- }
223
- dfsFast(visit, startNodeId) {
224
- let traversalStartNode = (0, _nullthrows().default)(startNodeId ?? this.rootNodeId, 'A start node is required to traverse');
225
- this._assertHasNodeId(traversalStartNode);
226
- let visited;
227
- if (!this._visited || this._visited.capacity < this.nodes.length) {
228
- this._visited = new _BitSet.BitSet(this.nodes.length);
229
- visited = this._visited;
230
- } else {
231
- visited = this._visited;
232
- visited.clear();
233
- }
234
- // Take shared instance to avoid re-entrancy issues.
235
- this._visited = null;
236
- let stopped = false;
237
- let skipped = false;
238
- let actions = {
239
- skipChildren() {
240
- skipped = true;
241
- },
242
- stop() {
243
- stopped = true;
244
- }
245
- };
246
- let queue = [{
247
- nodeId: traversalStartNode,
248
- context: null
249
- }];
250
- while (queue.length !== 0) {
251
- let {
252
- nodeId,
253
- context
254
- } = queue.pop();
255
- if (!this.hasNode(nodeId) || visited.has(nodeId)) continue;
256
- visited.add(nodeId);
257
- skipped = false;
258
- let newContext = visit(nodeId, context, actions);
259
- if (typeof newContext !== 'undefined') {
260
- // $FlowFixMe[reassign-const]
261
- context = newContext;
262
- }
263
- if (skipped) {
264
- continue;
265
- }
266
- if (stopped) {
267
- this._visited = visited;
268
- return context;
269
- }
270
- this.adjacencyList.forEachNodeIdConnectedFromReverse(nodeId, child => {
271
- if (!visited.has(child)) {
272
- queue.push({
273
- nodeId: child,
274
- context
275
- });
276
- }
277
- return false;
278
- });
279
- }
280
- this._visited = visited;
281
- return null;
282
- }
283
-
284
- // A post-order implementation of dfsFast
285
- postOrderDfsFast(visit, startNodeId) {
286
- let traversalStartNode = (0, _nullthrows().default)(startNodeId ?? this.rootNodeId, 'A start node is required to traverse');
287
- this._assertHasNodeId(traversalStartNode);
288
- let visited;
289
- if (!this._visited || this._visited.capacity < this.nodes.length) {
290
- this._visited = new _BitSet.BitSet(this.nodes.length);
291
- visited = this._visited;
292
- } else {
293
- visited = this._visited;
294
- visited.clear();
295
- }
296
- this._visited = null;
297
- let stopped = false;
298
- let actions = {
299
- stop() {
300
- stopped = true;
301
- },
302
- skipChildren() {
303
- throw new Error('Calling skipChildren inside a post-order traversal is not allowed');
304
- }
305
- };
306
- let queue = [traversalStartNode];
307
- while (queue.length !== 0) {
308
- let nodeId = queue[queue.length - 1];
309
- if (!visited.has(nodeId)) {
310
- visited.add(nodeId);
311
- this.adjacencyList.forEachNodeIdConnectedFromReverse(nodeId, child => {
312
- if (!visited.has(child)) {
313
- queue.push(child);
314
- }
315
- return false;
316
- });
317
- } else {
318
- queue.pop();
319
- visit(nodeId, null, actions);
320
- if (stopped) {
321
- this._visited = visited;
322
- return;
323
- }
324
- }
325
- }
326
- this._visited = visited;
327
- }
328
-
329
- /**
330
- * Iterative implementation of DFS that supports all use-cases.
331
- *
332
- * This replaces `dfs` and will replace `dfsFast`.
333
- */
334
- dfs({
335
- visit,
336
- startNodeId,
337
- getChildren
338
- }) {
339
- let traversalStartNode = (0, _nullthrows().default)(startNodeId ?? this.rootNodeId, 'A start node is required to traverse');
340
- this._assertHasNodeId(traversalStartNode);
341
- let visited;
342
- if (!this._visited || this._visited.capacity < this.nodes.length) {
343
- this._visited = new _BitSet.BitSet(this.nodes.length);
344
- visited = this._visited;
345
- } else {
346
- visited = this._visited;
347
- visited.clear();
348
- }
349
- // Take shared instance to avoid re-entrancy issues.
350
- this._visited = null;
351
- let stopped = false;
352
- let skipped = false;
353
- let actions = {
354
- skipChildren() {
355
- skipped = true;
356
- },
357
- stop() {
358
- stopped = true;
359
- }
360
- };
361
- const queue = [{
362
- nodeId: traversalStartNode,
363
- context: null
364
- }];
365
- const enter = typeof visit === 'function' ? visit : visit.enter;
366
- while (queue.length !== 0) {
367
- const command = queue.pop();
368
- if (command.exit != null) {
369
- let {
370
- nodeId,
371
- context,
372
- exit
373
- } = command;
374
- let newContext = exit(nodeId, command.context, actions);
375
- if (typeof newContext !== 'undefined') {
376
- // $FlowFixMe[reassign-const]
377
- context = newContext;
378
- }
379
- if (skipped) {
380
- continue;
381
- }
382
- if (stopped) {
383
- this._visited = visited;
384
- return context;
385
- }
386
- } else {
387
- let {
388
- nodeId,
389
- context
390
- } = command;
391
- if (!this.hasNode(nodeId) || visited.has(nodeId)) continue;
392
- visited.add(nodeId);
393
- skipped = false;
394
- if (enter) {
395
- let newContext = enter(nodeId, context, actions);
396
- if (typeof newContext !== 'undefined') {
397
- // $FlowFixMe[reassign-const]
398
- context = newContext;
399
- }
400
- }
401
- if (skipped) {
402
- continue;
403
- }
404
- if (stopped) {
405
- this._visited = visited;
406
- return context;
407
- }
408
- if (typeof visit !== 'function' && visit.exit) {
409
- queue.push({
410
- nodeId,
411
- exit: visit.exit,
412
- context
413
- });
414
- }
415
-
416
- // TODO turn into generator function
417
- const children = getChildren(nodeId);
418
- for (let i = children.length - 1; i > -1; i -= 1) {
419
- const child = children[i];
420
- if (visited.has(child)) {
421
- continue;
422
- }
423
- queue.push({
424
- nodeId: child,
425
- context
426
- });
427
- }
428
- }
429
- }
430
- this._visited = visited;
431
- }
432
- bfs(visit) {
433
- let rootNodeId = (0, _nullthrows().default)(this.rootNodeId, 'A root node is required to traverse');
434
- let queue = [rootNodeId];
435
- let visited = new Set([rootNodeId]);
436
- while (queue.length > 0) {
437
- let node = queue.shift();
438
- let stop = visit(rootNodeId);
439
- if (stop === true) {
440
- return node;
441
- }
442
- for (let child of this.getNodeIdsConnectedFrom(node)) {
443
- if (!visited.has(child)) {
444
- visited.add(child);
445
- queue.push(child);
446
- }
447
- }
448
- }
449
- return null;
450
- }
451
- topoSort(type) {
452
- let sorted = [];
453
- this.traverse({
454
- exit: nodeId => {
455
- sorted.push(nodeId);
456
- }
457
- }, null, type);
458
- return sorted.reverse();
459
- }
460
- findAncestor(nodeId, fn) {
461
- let res = null;
462
- this.traverseAncestors(nodeId, (nodeId, ctx, traversal) => {
463
- if (fn(nodeId)) {
464
- res = nodeId;
465
- traversal.stop();
466
- }
467
- });
468
- return res;
469
- }
470
- findAncestors(nodeId, fn) {
471
- let res = [];
472
- this.traverseAncestors(nodeId, (nodeId, ctx, traversal) => {
473
- if (fn(nodeId)) {
474
- res.push(nodeId);
475
- traversal.skipChildren();
476
- }
477
- });
478
- return res;
479
- }
480
- findDescendant(nodeId, fn) {
481
- let res = null;
482
- this.traverse((nodeId, ctx, traversal) => {
483
- if (fn(nodeId)) {
484
- res = nodeId;
485
- traversal.stop();
486
- }
487
- }, nodeId);
488
- return res;
489
- }
490
- findDescendants(nodeId, fn) {
491
- let res = [];
492
- this.traverse((nodeId, ctx, traversal) => {
493
- if (fn(nodeId)) {
494
- res.push(nodeId);
495
- traversal.skipChildren();
496
- }
497
- }, nodeId);
498
- return res;
499
- }
500
- _assertHasNodeId(nodeId) {
501
- if (!this.hasNode(nodeId)) {
502
- throw new Error('Does not have node ' + (0, _types.fromNodeId)(nodeId));
503
- }
504
- }
505
- }
506
- exports.default = Graph;
507
- function mapVisitor(filter, visit) {
508
- function makeEnter(visit) {
509
- return function (nodeId, context, actions) {
510
- let value = filter(nodeId, actions);
511
- if (value != null) {
512
- return visit(value, context, actions);
513
- }
514
- };
515
- }
516
- if (typeof visit === 'function') {
517
- return makeEnter(visit);
518
- }
519
- let mapped = {};
520
- if (visit.enter != null) {
521
- mapped.enter = makeEnter(visit.enter);
522
- }
523
- if (visit.exit != null) {
524
- mapped.exit = function (nodeId, context, actions) {
525
- let exit = visit.exit;
526
- if (!exit) {
527
- return;
528
- }
529
- let value = filter(nodeId, actions);
530
- if (value != null) {
531
- return exit(value, context, actions);
532
- }
533
- };
534
- }
535
- return mapped;
536
- }