@lezer/common 0.15.12 → 1.0.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/dist/index.cjs +207 -78
- package/dist/index.d.ts +1 -1
- package/dist/index.es.js +1816 -0
- package/dist/index.js +207 -79
- package/dist/mix.d.ts +3 -3
- package/dist/tree.d.ts +53 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// FIXME profile adding a per-Tree TreeNode cache, validating it by
|
|
2
2
|
// parent pointer
|
|
3
|
-
/// The default maximum length of a `TreeBuffer` node
|
|
3
|
+
/// The default maximum length of a `TreeBuffer` node.
|
|
4
4
|
const DefaultBufferLength = 1024;
|
|
5
5
|
let nextPropID = 0;
|
|
6
6
|
class Range {
|
|
@@ -63,7 +63,7 @@ NodeProp.contextHash = new NodeProp({ perNode: true });
|
|
|
63
63
|
NodeProp.lookAhead = new NodeProp({ perNode: true });
|
|
64
64
|
/// This per-node prop is used to replace a given node, or part of a
|
|
65
65
|
/// node, with another tree. This is useful to include trees from
|
|
66
|
-
/// different languages.
|
|
66
|
+
/// different languages in mixed-language parsers.
|
|
67
67
|
NodeProp.mounted = new NodeProp({ perNode: true });
|
|
68
68
|
/// A mounted tree, which can be [stored](#common.NodeProp^mounted) on
|
|
69
69
|
/// a tree node to indicate that parts of its content are
|
|
@@ -109,6 +109,7 @@ class NodeType {
|
|
|
109
109
|
this.id = id;
|
|
110
110
|
this.flags = flags;
|
|
111
111
|
}
|
|
112
|
+
/// Define a node type.
|
|
112
113
|
static define(spec) {
|
|
113
114
|
let props = spec.props && spec.props.length ? Object.create(null) : noProps;
|
|
114
115
|
let flags = (spec.top ? 1 /* Top */ : 0) | (spec.skipped ? 2 /* Skipped */ : 0) |
|
|
@@ -190,7 +191,7 @@ class NodeSet {
|
|
|
190
191
|
throw new RangeError("Node type ids should correspond to array positions when creating a node set");
|
|
191
192
|
}
|
|
192
193
|
/// Create a copy of this set with some node properties added. The
|
|
193
|
-
/// arguments to this method
|
|
194
|
+
/// arguments to this method can be created with
|
|
194
195
|
/// [`NodeProp.add`](#common.NodeProp.add).
|
|
195
196
|
extend(...props) {
|
|
196
197
|
let newTypes = [];
|
|
@@ -210,6 +211,28 @@ class NodeSet {
|
|
|
210
211
|
}
|
|
211
212
|
}
|
|
212
213
|
const CachedNode = new WeakMap(), CachedInnerNode = new WeakMap();
|
|
214
|
+
/// Options that control iteration. Can be combined with the `|`
|
|
215
|
+
/// operator to enable multiple ones.
|
|
216
|
+
var IterMode;
|
|
217
|
+
(function (IterMode) {
|
|
218
|
+
/// When enabled, iteration will only visit [`Tree`](#common.Tree)
|
|
219
|
+
/// objects, not nodes packed into
|
|
220
|
+
/// [`TreeBuffer`](#common.TreeBuffer)s.
|
|
221
|
+
IterMode[IterMode["ExcludeBuffers"] = 1] = "ExcludeBuffers";
|
|
222
|
+
/// Enable this to make iteration include anonymous nodes (such as
|
|
223
|
+
/// the nodes that wrap repeated grammar constructs into a balanced
|
|
224
|
+
/// tree).
|
|
225
|
+
IterMode[IterMode["IncludeAnonymous"] = 2] = "IncludeAnonymous";
|
|
226
|
+
/// By default, regular [mounted](#common.NodeProp^mounted) nodes
|
|
227
|
+
/// replace their base node in iteration. Enable this to ignore them
|
|
228
|
+
/// instead.
|
|
229
|
+
IterMode[IterMode["IgnoreMounts"] = 4] = "IgnoreMounts";
|
|
230
|
+
/// This option only applies in
|
|
231
|
+
/// [`enter`](#common.SyntaxNode.enter)-style methods. It tells the
|
|
232
|
+
/// library to not enter mounted overlays if one covers the given
|
|
233
|
+
/// position.
|
|
234
|
+
IterMode[IterMode["IgnoreOverlays"] = 8] = "IgnoreOverlays";
|
|
235
|
+
})(IterMode || (IterMode = {}));
|
|
213
236
|
/// A piece of syntax tree. There are two ways to approach these
|
|
214
237
|
/// trees: the way they are actually stored in memory, and the
|
|
215
238
|
/// convenient way.
|
|
@@ -268,25 +291,22 @@ class Tree {
|
|
|
268
291
|
(/\W/.test(this.type.name) && !this.type.isError ? JSON.stringify(this.type.name) : this.type.name) +
|
|
269
292
|
(children.length ? "(" + children + ")" : "");
|
|
270
293
|
}
|
|
271
|
-
/// Get a [tree cursor](#common.TreeCursor)
|
|
272
|
-
///
|
|
273
|
-
///
|
|
274
|
-
cursor(
|
|
275
|
-
|
|
294
|
+
/// Get a [tree cursor](#common.TreeCursor) positioned at the top of
|
|
295
|
+
/// the tree. Mode can be used to [control](#common.IterMode) which
|
|
296
|
+
/// nodes the cursor visits.
|
|
297
|
+
cursor(mode = 0) {
|
|
298
|
+
return new TreeCursor(this.topNode, mode);
|
|
299
|
+
}
|
|
300
|
+
/// Get a [tree cursor](#common.TreeCursor) pointing into this tree
|
|
301
|
+
/// at the given position and side (see
|
|
302
|
+
/// [`moveTo`](#common.TreeCursor.moveTo).
|
|
303
|
+
cursorAt(pos, side = 0, mode = 0) {
|
|
304
|
+
let scope = CachedNode.get(this) || this.topNode;
|
|
276
305
|
let cursor = new TreeCursor(scope);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
CachedNode.set(this, cursor._tree);
|
|
280
|
-
}
|
|
306
|
+
cursor.moveTo(pos, side);
|
|
307
|
+
CachedNode.set(this, cursor._tree);
|
|
281
308
|
return cursor;
|
|
282
309
|
}
|
|
283
|
-
/// Get a [tree cursor](#common.TreeCursor) that, unlike regular
|
|
284
|
-
/// cursors, doesn't skip through
|
|
285
|
-
/// [anonymous](#common.NodeType.isAnonymous) nodes and doesn't
|
|
286
|
-
/// automatically enter mounted nodes.
|
|
287
|
-
fullCursor() {
|
|
288
|
-
return new TreeCursor(this.topNode, 1 /* Full */);
|
|
289
|
-
}
|
|
290
310
|
/// Get a [syntax node](#common.SyntaxNode) object for the top of the
|
|
291
311
|
/// tree.
|
|
292
312
|
get topNode() {
|
|
@@ -319,23 +339,21 @@ class Tree {
|
|
|
319
339
|
/// not have its children iterated over (or `leave` called).
|
|
320
340
|
iterate(spec) {
|
|
321
341
|
let { enter, leave, from = 0, to = this.length } = spec;
|
|
322
|
-
for (let c = this.cursor(
|
|
323
|
-
let
|
|
324
|
-
if (c.from <= to && c.to >= from && (c.type.isAnonymous || enter(c
|
|
342
|
+
for (let c = this.cursor((spec.mode || 0) | IterMode.IncludeAnonymous);;) {
|
|
343
|
+
let entered = false;
|
|
344
|
+
if (c.from <= to && c.to >= from && (c.type.isAnonymous || enter(c) !== false)) {
|
|
325
345
|
if (c.firstChild())
|
|
326
346
|
continue;
|
|
327
|
-
|
|
328
|
-
mustLeave = true;
|
|
347
|
+
entered = true;
|
|
329
348
|
}
|
|
330
349
|
for (;;) {
|
|
331
|
-
if (
|
|
332
|
-
leave(c
|
|
333
|
-
mustLeave = c.type.isAnonymous;
|
|
350
|
+
if (entered && leave && !c.type.isAnonymous)
|
|
351
|
+
leave(c);
|
|
334
352
|
if (c.nextSibling())
|
|
335
353
|
break;
|
|
336
354
|
if (!c.parent())
|
|
337
355
|
return;
|
|
338
|
-
|
|
356
|
+
entered = true;
|
|
339
357
|
}
|
|
340
358
|
}
|
|
341
359
|
}
|
|
@@ -383,7 +401,7 @@ class FlatBufferCursor {
|
|
|
383
401
|
/// Tree buffers contain (type, start, end, endIndex) quads for each
|
|
384
402
|
/// node. In such a buffer, nodes are stored in prefix order (parents
|
|
385
403
|
/// before children, with the endIndex of the parent indicating which
|
|
386
|
-
/// children belong to it)
|
|
404
|
+
/// children belong to it).
|
|
387
405
|
class TreeBuffer {
|
|
388
406
|
/// Create a tree buffer.
|
|
389
407
|
constructor(
|
|
@@ -486,72 +504,73 @@ function resolveNode(node, pos, side, overlays) {
|
|
|
486
504
|
return node;
|
|
487
505
|
node = parent;
|
|
488
506
|
}
|
|
507
|
+
let mode = overlays ? 0 : IterMode.IgnoreOverlays;
|
|
489
508
|
// Must go up out of overlays when those do not overlap with pos
|
|
490
509
|
if (overlays)
|
|
491
510
|
for (let scan = node, parent = scan.parent; parent; scan = parent, parent = scan.parent) {
|
|
492
|
-
if (scan instanceof TreeNode && scan.index < 0 && ((_a = parent.enter(pos, side,
|
|
511
|
+
if (scan instanceof TreeNode && scan.index < 0 && ((_a = parent.enter(pos, side, mode)) === null || _a === void 0 ? void 0 : _a.from) != scan.from)
|
|
493
512
|
node = parent;
|
|
494
513
|
}
|
|
495
514
|
for (;;) {
|
|
496
|
-
let inner = node.enter(pos, side,
|
|
515
|
+
let inner = node.enter(pos, side, mode);
|
|
497
516
|
if (!inner)
|
|
498
517
|
return node;
|
|
499
518
|
node = inner;
|
|
500
519
|
}
|
|
501
520
|
}
|
|
502
521
|
class TreeNode {
|
|
503
|
-
constructor(
|
|
522
|
+
constructor(_tree, from,
|
|
504
523
|
// Index in parent node, set to -1 if the node is not a direct child of _parent.node (overlay)
|
|
505
524
|
index, _parent) {
|
|
506
|
-
this.
|
|
507
|
-
this.
|
|
525
|
+
this._tree = _tree;
|
|
526
|
+
this.from = from;
|
|
508
527
|
this.index = index;
|
|
509
528
|
this._parent = _parent;
|
|
510
529
|
}
|
|
511
|
-
get type() { return this.
|
|
512
|
-
get name() { return this.
|
|
513
|
-
get
|
|
514
|
-
get to() { return this._from + this.node.length; }
|
|
530
|
+
get type() { return this._tree.type; }
|
|
531
|
+
get name() { return this._tree.type.name; }
|
|
532
|
+
get to() { return this.from + this._tree.length; }
|
|
515
533
|
nextChild(i, dir, pos, side, mode = 0) {
|
|
516
534
|
for (let parent = this;;) {
|
|
517
|
-
for (let { children, positions } = parent.
|
|
518
|
-
let next = children[i], start = positions[i] + parent.
|
|
535
|
+
for (let { children, positions } = parent._tree, e = dir > 0 ? children.length : -1; i != e; i += dir) {
|
|
536
|
+
let next = children[i], start = positions[i] + parent.from;
|
|
519
537
|
if (!checkSide(side, pos, start, start + next.length))
|
|
520
538
|
continue;
|
|
521
539
|
if (next instanceof TreeBuffer) {
|
|
522
|
-
if (mode &
|
|
540
|
+
if (mode & IterMode.ExcludeBuffers)
|
|
523
541
|
continue;
|
|
524
542
|
let index = next.findChild(0, next.buffer.length, dir, pos - start, side);
|
|
525
543
|
if (index > -1)
|
|
526
544
|
return new BufferNode(new BufferContext(parent, next, i, start), null, index);
|
|
527
545
|
}
|
|
528
|
-
else if ((mode &
|
|
546
|
+
else if ((mode & IterMode.IncludeAnonymous) || (!next.type.isAnonymous || hasChild(next))) {
|
|
529
547
|
let mounted;
|
|
530
|
-
if (!(mode &
|
|
548
|
+
if (!(mode & IterMode.IgnoreMounts) &&
|
|
549
|
+
next.props && (mounted = next.prop(NodeProp.mounted)) && !mounted.overlay)
|
|
531
550
|
return new TreeNode(mounted.tree, start, i, parent);
|
|
532
551
|
let inner = new TreeNode(next, start, i, parent);
|
|
533
|
-
return (mode &
|
|
552
|
+
return (mode & IterMode.IncludeAnonymous) || !inner.type.isAnonymous ? inner
|
|
534
553
|
: inner.nextChild(dir < 0 ? next.children.length - 1 : 0, dir, pos, side);
|
|
535
554
|
}
|
|
536
555
|
}
|
|
537
|
-
if ((mode &
|
|
556
|
+
if ((mode & IterMode.IncludeAnonymous) || !parent.type.isAnonymous)
|
|
538
557
|
return null;
|
|
539
558
|
if (parent.index >= 0)
|
|
540
559
|
i = parent.index + dir;
|
|
541
560
|
else
|
|
542
|
-
i = dir < 0 ? -1 : parent._parent.
|
|
561
|
+
i = dir < 0 ? -1 : parent._parent._tree.children.length;
|
|
543
562
|
parent = parent._parent;
|
|
544
563
|
if (!parent)
|
|
545
564
|
return null;
|
|
546
565
|
}
|
|
547
566
|
}
|
|
548
567
|
get firstChild() { return this.nextChild(0, 1, 0, 4 /* DontCare */); }
|
|
549
|
-
get lastChild() { return this.nextChild(this.
|
|
568
|
+
get lastChild() { return this.nextChild(this._tree.children.length - 1, -1, 0, 4 /* DontCare */); }
|
|
550
569
|
childAfter(pos) { return this.nextChild(0, 1, pos, 2 /* After */); }
|
|
551
|
-
childBefore(pos) { return this.nextChild(this.
|
|
552
|
-
enter(pos, side,
|
|
570
|
+
childBefore(pos) { return this.nextChild(this._tree.children.length - 1, -1, pos, -2 /* Before */); }
|
|
571
|
+
enter(pos, side, mode = 0) {
|
|
553
572
|
let mounted;
|
|
554
|
-
if (
|
|
573
|
+
if (!(mode & IterMode.IgnoreOverlays) && (mounted = this._tree.prop(NodeProp.mounted)) && mounted.overlay) {
|
|
555
574
|
let rPos = pos - this.from;
|
|
556
575
|
for (let { from, to } of mounted.overlay) {
|
|
557
576
|
if ((side > 0 ? from <= rPos : from < rPos) &&
|
|
@@ -559,7 +578,7 @@ class TreeNode {
|
|
|
559
578
|
return new TreeNode(mounted.tree, mounted.overlay[0].from + this.from, -1, this);
|
|
560
579
|
}
|
|
561
580
|
}
|
|
562
|
-
return this.nextChild(0, 1, pos, side,
|
|
581
|
+
return this.nextChild(0, 1, pos, side, mode);
|
|
563
582
|
}
|
|
564
583
|
nextSignificantParent() {
|
|
565
584
|
let val = this;
|
|
@@ -576,9 +595,9 @@ class TreeNode {
|
|
|
576
595
|
get prevSibling() {
|
|
577
596
|
return this._parent && this.index >= 0 ? this._parent.nextChild(this.index - 1, -1, 0, 4 /* DontCare */) : null;
|
|
578
597
|
}
|
|
579
|
-
|
|
580
|
-
get tree() { return this.
|
|
581
|
-
toTree() { return this.
|
|
598
|
+
cursor(mode = 0) { return new TreeCursor(this, mode); }
|
|
599
|
+
get tree() { return this._tree; }
|
|
600
|
+
toTree() { return this._tree; }
|
|
582
601
|
resolve(pos, side = 0) {
|
|
583
602
|
return resolveNode(this, pos, side, false);
|
|
584
603
|
}
|
|
@@ -594,10 +613,12 @@ class TreeNode {
|
|
|
594
613
|
return getChildren(this, type, before, after);
|
|
595
614
|
}
|
|
596
615
|
/// @internal
|
|
597
|
-
toString() { return this.
|
|
616
|
+
toString() { return this._tree.toString(); }
|
|
617
|
+
get node() { return this; }
|
|
618
|
+
matchContext(context) { return matchNodeContext(this, context); }
|
|
598
619
|
}
|
|
599
620
|
function getChildren(node, type, before, after) {
|
|
600
|
-
let cur = node.cursor, result = [];
|
|
621
|
+
let cur = node.cursor(), result = [];
|
|
601
622
|
if (!cur.firstChild())
|
|
602
623
|
return result;
|
|
603
624
|
if (before != null)
|
|
@@ -613,6 +634,18 @@ function getChildren(node, type, before, after) {
|
|
|
613
634
|
return after == null ? result : [];
|
|
614
635
|
}
|
|
615
636
|
}
|
|
637
|
+
function matchNodeContext(node, context, i = context.length - 1) {
|
|
638
|
+
for (let p = node.parent; i >= 0; p = p.parent) {
|
|
639
|
+
if (!p)
|
|
640
|
+
return false;
|
|
641
|
+
if (!p.type.isAnonymous) {
|
|
642
|
+
if (context[i] && context[i] != p.name)
|
|
643
|
+
return false;
|
|
644
|
+
i--;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return true;
|
|
648
|
+
}
|
|
616
649
|
class BufferContext {
|
|
617
650
|
constructor(parent, buffer, index, start) {
|
|
618
651
|
this.parent = parent;
|
|
@@ -640,8 +673,8 @@ class BufferNode {
|
|
|
640
673
|
get lastChild() { return this.child(-1, 0, 4 /* DontCare */); }
|
|
641
674
|
childAfter(pos) { return this.child(1, pos, 2 /* After */); }
|
|
642
675
|
childBefore(pos) { return this.child(-1, pos, -2 /* Before */); }
|
|
643
|
-
enter(pos, side,
|
|
644
|
-
if (
|
|
676
|
+
enter(pos, side, mode = 0) {
|
|
677
|
+
if (mode & IterMode.ExcludeBuffers)
|
|
645
678
|
return null;
|
|
646
679
|
let { buffer } = this.context;
|
|
647
680
|
let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], side > 0 ? 1 : -1, pos - this.context.start, side);
|
|
@@ -667,7 +700,7 @@ class BufferNode {
|
|
|
667
700
|
return this.externalSibling(-1);
|
|
668
701
|
return new BufferNode(this.context, this._parent, buffer.findChild(parentStart, this.index, -1, 0, 4 /* DontCare */));
|
|
669
702
|
}
|
|
670
|
-
|
|
703
|
+
cursor(mode = 0) { return new TreeCursor(this, mode); }
|
|
671
704
|
get tree() { return null; }
|
|
672
705
|
toTree() {
|
|
673
706
|
let children = [], positions = [];
|
|
@@ -696,6 +729,8 @@ class BufferNode {
|
|
|
696
729
|
getChildren(type, before = null, after = null) {
|
|
697
730
|
return getChildren(this, type, before, after);
|
|
698
731
|
}
|
|
732
|
+
get node() { return this; }
|
|
733
|
+
matchContext(context) { return matchNodeContext(this, context); }
|
|
699
734
|
}
|
|
700
735
|
/// A tree cursor object focuses on a given node in a syntax tree, and
|
|
701
736
|
/// allows you to move to adjacent nodes.
|
|
@@ -705,8 +740,10 @@ class TreeCursor {
|
|
|
705
740
|
/// @internal
|
|
706
741
|
mode = 0) {
|
|
707
742
|
this.mode = mode;
|
|
743
|
+
/// @internal
|
|
708
744
|
this.buffer = null;
|
|
709
745
|
this.stack = [];
|
|
746
|
+
/// @internal
|
|
710
747
|
this.index = 0;
|
|
711
748
|
this.bufferNode = null;
|
|
712
749
|
if (node instanceof TreeNode) {
|
|
@@ -757,7 +794,7 @@ class TreeCursor {
|
|
|
757
794
|
/// @internal
|
|
758
795
|
enterChild(dir, pos, side) {
|
|
759
796
|
if (!this.buffer)
|
|
760
|
-
return this.yield(this._tree.nextChild(dir < 0 ? this._tree.
|
|
797
|
+
return this.yield(this._tree.nextChild(dir < 0 ? this._tree._tree.children.length - 1 : 0, dir, pos, side, this.mode));
|
|
761
798
|
let { buffer } = this.buffer;
|
|
762
799
|
let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.buffer.start, side);
|
|
763
800
|
if (index < 0)
|
|
@@ -779,18 +816,18 @@ class TreeCursor {
|
|
|
779
816
|
/// will also enter [overlaid](#common.MountedTree.overlay)
|
|
780
817
|
/// [mounted](#common.NodeProp^mounted) trees unless `overlays` is
|
|
781
818
|
/// set to false.
|
|
782
|
-
enter(pos, side,
|
|
819
|
+
enter(pos, side, mode = this.mode) {
|
|
783
820
|
if (!this.buffer)
|
|
784
|
-
return this.yield(this._tree.enter(pos, side,
|
|
785
|
-
return
|
|
821
|
+
return this.yield(this._tree.enter(pos, side, mode));
|
|
822
|
+
return mode & IterMode.ExcludeBuffers ? false : this.enterChild(1, pos, side);
|
|
786
823
|
}
|
|
787
824
|
/// Move to the node's parent node, if this isn't the top node.
|
|
788
825
|
parent() {
|
|
789
826
|
if (!this.buffer)
|
|
790
|
-
return this.yieldNode((this.mode &
|
|
827
|
+
return this.yieldNode((this.mode & IterMode.IncludeAnonymous) ? this._tree._parent : this._tree.parent);
|
|
791
828
|
if (this.stack.length)
|
|
792
829
|
return this.yieldBuf(this.stack.pop());
|
|
793
|
-
let parent = (this.mode &
|
|
830
|
+
let parent = (this.mode & IterMode.IncludeAnonymous) ? this.buffer.parent : this.buffer.parent.nextSignificantParent();
|
|
794
831
|
this.buffer = null;
|
|
795
832
|
return this.yieldNode(parent);
|
|
796
833
|
}
|
|
@@ -836,9 +873,12 @@ class TreeCursor {
|
|
|
836
873
|
}
|
|
837
874
|
for (; parent; { index, _parent: parent } = parent) {
|
|
838
875
|
if (index > -1)
|
|
839
|
-
for (let i = index + dir, e = dir < 0 ? -1 : parent.
|
|
840
|
-
let child = parent.
|
|
841
|
-
if ((this.mode &
|
|
876
|
+
for (let i = index + dir, e = dir < 0 ? -1 : parent._tree.children.length; i != e; i += dir) {
|
|
877
|
+
let child = parent._tree.children[i];
|
|
878
|
+
if ((this.mode & IterMode.IncludeAnonymous) ||
|
|
879
|
+
child instanceof TreeBuffer ||
|
|
880
|
+
!child.type.isAnonymous ||
|
|
881
|
+
hasChild(child))
|
|
842
882
|
return false;
|
|
843
883
|
}
|
|
844
884
|
}
|
|
@@ -906,7 +946,55 @@ class TreeCursor {
|
|
|
906
946
|
/// any. Will return null when the node is in a [tree
|
|
907
947
|
/// buffer](#common.TreeBuffer).
|
|
908
948
|
get tree() {
|
|
909
|
-
return this.buffer ? null : this._tree.
|
|
949
|
+
return this.buffer ? null : this._tree._tree;
|
|
950
|
+
}
|
|
951
|
+
/// Iterate over the current node and all its descendants, calling
|
|
952
|
+
/// `enter` when entering a node and `leave`, if given, when leaving
|
|
953
|
+
/// one. When `enter` returns `false`, any children of that node are
|
|
954
|
+
/// skipped, and `leave` isn't called for it.
|
|
955
|
+
iterate(enter, leave) {
|
|
956
|
+
for (let depth = 0;;) {
|
|
957
|
+
let mustLeave = false;
|
|
958
|
+
if (this.type.isAnonymous || enter(this) !== false) {
|
|
959
|
+
if (this.firstChild()) {
|
|
960
|
+
depth++;
|
|
961
|
+
continue;
|
|
962
|
+
}
|
|
963
|
+
if (!this.type.isAnonymous)
|
|
964
|
+
mustLeave = true;
|
|
965
|
+
}
|
|
966
|
+
for (;;) {
|
|
967
|
+
if (mustLeave && leave)
|
|
968
|
+
leave(this);
|
|
969
|
+
mustLeave = this.type.isAnonymous;
|
|
970
|
+
if (this.nextSibling())
|
|
971
|
+
break;
|
|
972
|
+
if (!depth)
|
|
973
|
+
return;
|
|
974
|
+
this.parent();
|
|
975
|
+
depth--;
|
|
976
|
+
mustLeave = true;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
/// Test whether the current node matches a given context—a sequence
|
|
981
|
+
/// of direct parent node names. Empty strings in the context array
|
|
982
|
+
/// are treated as wildcards.
|
|
983
|
+
matchContext(context) {
|
|
984
|
+
if (!this.buffer)
|
|
985
|
+
return matchNodeContext(this.node, context);
|
|
986
|
+
let { buffer } = this.buffer, { types } = buffer.set;
|
|
987
|
+
for (let i = context.length - 1, d = this.stack.length - 1; i >= 0; d--) {
|
|
988
|
+
if (d < 0)
|
|
989
|
+
return matchNodeContext(this.node, context, i);
|
|
990
|
+
let type = types[buffer.buffer[this.stack[d]]];
|
|
991
|
+
if (!type.isAnonymous) {
|
|
992
|
+
if (context[i] && context[i] != type.name)
|
|
993
|
+
return false;
|
|
994
|
+
i--;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
return true;
|
|
910
998
|
}
|
|
911
999
|
}
|
|
912
1000
|
function hasChild(tree) {
|
|
@@ -1166,6 +1254,48 @@ mkTree) {
|
|
|
1166
1254
|
divide(children, positions, from, to, 0);
|
|
1167
1255
|
return (mkTop || mkTree)(localChildren, localPositions, length);
|
|
1168
1256
|
}
|
|
1257
|
+
/// Provides a way to associate values with pieces of trees. As long
|
|
1258
|
+
/// as that part of the tree is reused, the associated values can be
|
|
1259
|
+
/// retrieved from an updated tree.
|
|
1260
|
+
class NodeWeakMap {
|
|
1261
|
+
constructor() {
|
|
1262
|
+
this.map = new WeakMap();
|
|
1263
|
+
}
|
|
1264
|
+
setBuffer(buffer, index, value) {
|
|
1265
|
+
let inner = this.map.get(buffer);
|
|
1266
|
+
if (!inner)
|
|
1267
|
+
this.map.set(buffer, inner = new Map);
|
|
1268
|
+
inner.set(index, value);
|
|
1269
|
+
}
|
|
1270
|
+
getBuffer(buffer, index) {
|
|
1271
|
+
let inner = this.map.get(buffer);
|
|
1272
|
+
return inner && inner.get(index);
|
|
1273
|
+
}
|
|
1274
|
+
/// Set the value for this syntax node.
|
|
1275
|
+
set(node, value) {
|
|
1276
|
+
if (node instanceof BufferNode)
|
|
1277
|
+
this.setBuffer(node.context.buffer, node.index, value);
|
|
1278
|
+
else if (node instanceof TreeNode)
|
|
1279
|
+
this.map.set(node.tree, value);
|
|
1280
|
+
}
|
|
1281
|
+
/// Retrieve value for this syntax node, if it exists in the map.
|
|
1282
|
+
get(node) {
|
|
1283
|
+
return node instanceof BufferNode ? this.getBuffer(node.context.buffer, node.index)
|
|
1284
|
+
: node instanceof TreeNode ? this.map.get(node.tree) : undefined;
|
|
1285
|
+
}
|
|
1286
|
+
/// Set the value for the node that a cursor currently points to.
|
|
1287
|
+
cursorSet(cursor, value) {
|
|
1288
|
+
if (cursor.buffer)
|
|
1289
|
+
this.setBuffer(cursor.buffer.buffer, cursor.index, value);
|
|
1290
|
+
else
|
|
1291
|
+
this.map.set(cursor.tree, value);
|
|
1292
|
+
}
|
|
1293
|
+
/// Retrieve the value for the node that a cursor currently points
|
|
1294
|
+
/// to.
|
|
1295
|
+
cursorGet(cursor) {
|
|
1296
|
+
return cursor.buffer ? this.getBuffer(cursor.buffer.buffer, cursor.index) : this.map.get(cursor.tree);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1169
1299
|
|
|
1170
1300
|
/// Tree fragments are used during [incremental
|
|
1171
1301
|
/// parsing](#common.Parser.startParse) to track parts of old trees
|
|
@@ -1175,7 +1305,10 @@ mkTree) {
|
|
|
1175
1305
|
/// [`applyChanges`](#common.TreeFragment^applyChanges) method to
|
|
1176
1306
|
/// update fragments for document changes.
|
|
1177
1307
|
class TreeFragment {
|
|
1178
|
-
/// Construct a tree fragment.
|
|
1308
|
+
/// Construct a tree fragment. You'll usually want to use
|
|
1309
|
+
/// [`addTree`](#common.TreeFragment^addTree) and
|
|
1310
|
+
/// [`applyChanges`](#common.TreeFragment^applyChanges) instead of
|
|
1311
|
+
/// calling this directly.
|
|
1179
1312
|
constructor(
|
|
1180
1313
|
/// The start of the unchanged range pointed to by this fragment.
|
|
1181
1314
|
/// This refers to an offset in the _updated_ document (as opposed
|
|
@@ -1290,11 +1423,6 @@ class StringInput {
|
|
|
1290
1423
|
/// function, runs the resulting [inner parses](#common.NestedParse),
|
|
1291
1424
|
/// and then [mounts](#common.NodeProp^mounted) their results onto the
|
|
1292
1425
|
/// tree.
|
|
1293
|
-
///
|
|
1294
|
-
/// The nesting function is passed a cursor to provide context for a
|
|
1295
|
-
/// node, but _should not_ move that cursor, only inspect its
|
|
1296
|
-
/// properties and optionally access its
|
|
1297
|
-
/// [node object](#common.TreeCursor.node).
|
|
1298
1426
|
function parseMixed(nest) {
|
|
1299
1427
|
return (parse, input, fragments, ranges) => new MixedParse(parse, nest, input, fragments, ranges);
|
|
1300
1428
|
}
|
|
@@ -1386,7 +1514,7 @@ class MixedParse {
|
|
|
1386
1514
|
let fragmentCursor = new FragmentCursor(this.fragments);
|
|
1387
1515
|
let overlay = null;
|
|
1388
1516
|
let covered = null;
|
|
1389
|
-
let cursor = new TreeCursor(new TreeNode(this.baseTree, this.ranges[0].from, 0, null),
|
|
1517
|
+
let cursor = new TreeCursor(new TreeNode(this.baseTree, this.ranges[0].from, 0, null), IterMode.IncludeAnonymous | IterMode.IgnoreMounts);
|
|
1390
1518
|
scan: for (let nest, isCovered; this.stoppedAt == null || cursor.from < this.stoppedAt;) {
|
|
1391
1519
|
let enter = true, range;
|
|
1392
1520
|
if (fragmentCursor.hasNode(cursor)) {
|
|
@@ -1514,13 +1642,13 @@ class StructureCursor {
|
|
|
1514
1642
|
constructor(root, offset) {
|
|
1515
1643
|
this.offset = offset;
|
|
1516
1644
|
this.done = false;
|
|
1517
|
-
this.cursor = root.
|
|
1645
|
+
this.cursor = root.cursor(IterMode.IncludeAnonymous | IterMode.IgnoreMounts);
|
|
1518
1646
|
}
|
|
1519
1647
|
// Move to the first node (in pre-order) that starts at or after `pos`.
|
|
1520
1648
|
moveTo(pos) {
|
|
1521
1649
|
let { cursor } = this, p = pos - this.offset;
|
|
1522
1650
|
while (!this.done && cursor.from < p) {
|
|
1523
|
-
if (cursor.to >= pos && cursor.enter(p, 1,
|
|
1651
|
+
if (cursor.to >= pos && cursor.enter(p, 1, IterMode.IgnoreOverlays | IterMode.ExcludeBuffers)) ;
|
|
1524
1652
|
else if (!cursor.next(false))
|
|
1525
1653
|
this.done = true;
|
|
1526
1654
|
}
|
|
@@ -1684,4 +1812,4 @@ function enterFragments(mounts, ranges) {
|
|
|
1684
1812
|
return result;
|
|
1685
1813
|
}
|
|
1686
1814
|
|
|
1687
|
-
export { DefaultBufferLength, MountedTree, NodeProp, NodeSet, NodeType, Parser, Tree, TreeBuffer, TreeCursor, TreeFragment, parseMixed };
|
|
1815
|
+
export { DefaultBufferLength, IterMode, MountedTree, NodeProp, NodeSet, NodeType, NodeWeakMap, Parser, Tree, TreeBuffer, TreeCursor, TreeFragment, parseMixed };
|
package/dist/mix.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SyntaxNodeRef } from "./tree";
|
|
2
2
|
import { Input, Parser, ParseWrapper } from "./parse";
|
|
3
3
|
export interface NestedParse {
|
|
4
4
|
parser: Parser;
|
|
5
5
|
overlay?: readonly {
|
|
6
6
|
from: number;
|
|
7
7
|
to: number;
|
|
8
|
-
}[] | ((node:
|
|
8
|
+
}[] | ((node: SyntaxNodeRef) => {
|
|
9
9
|
from: number;
|
|
10
10
|
to: number;
|
|
11
11
|
} | boolean);
|
|
12
12
|
}
|
|
13
|
-
export declare function parseMixed(nest: (node:
|
|
13
|
+
export declare function parseMixed(nest: (node: SyntaxNodeRef, input: Input) => NestedParse | null): ParseWrapper;
|