parseman 0.24.0 → 0.25.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.d.ts CHANGED
@@ -44,6 +44,6 @@ export type { TriviaEntriesView } from './cst/trivia-entries.ts';
44
44
  export { triviaKindMask } from './cst/trivia-kinds.ts';
45
45
  export { OffsetIndex, buildOffsetIndex, collectLeafSlots, gapText, lineBreaksIn, blankLinesIn, lineStartWithin, indentWidth, indentMixed, commentsIn, gapIsSignificant, } from './cst/offset-model.ts';
46
46
  export type { Slot, Gap } from './cst/offset-model.ts';
47
- export { relativize, absolutize, absoluteSpanAt, shiftAbsolute, applyEdit, } from './cst/relative-spans.ts';
47
+ export { relativize, absolutize, absoluteSpanAt, shiftAbsolute, applyEdit, relativizeCST, absolutizeCST, absoluteSpanCST, } from './cst/relative-spans.ts';
48
48
  export type { AbsNode, RelNode } from './cst/relative-spans.ts';
49
49
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -6393,17 +6393,159 @@ function manyRecover(item, until) {
6393
6393
  return many(tolerantElement(item, until, until));
6394
6394
  }
6395
6395
 
6396
+ // src/cst/relative-spans.ts
6397
+ function relativize(node2, parentBase = 0) {
6398
+ return {
6399
+ start: node2.start - parentBase,
6400
+ end: node2.end - parentBase,
6401
+ children: node2.children.map((c) => relativize(c, node2.start))
6402
+ };
6403
+ }
6404
+ function absolutize(node2, parentBase = 0) {
6405
+ const start = parentBase + node2.start;
6406
+ return {
6407
+ start,
6408
+ end: parentBase + node2.end,
6409
+ children: node2.children.map((c) => absolutize(c, start))
6410
+ };
6411
+ }
6412
+ function absoluteSpanAt(root, path) {
6413
+ let base = 0;
6414
+ let node2 = root;
6415
+ for (const idx of path) {
6416
+ base += node2.start;
6417
+ const child = node2.children[idx];
6418
+ if (!child) throw new RangeError(`absoluteSpanAt: no child ${idx} on path ${path.join(".")}`);
6419
+ node2 = child;
6420
+ }
6421
+ return { start: base + node2.start, end: base + node2.end };
6422
+ }
6423
+ function relativizeCST(node2, parentBase = 0) {
6424
+ const span = { start: node2.span.start - parentBase, end: node2.span.end - parentBase };
6425
+ if (node2.children) {
6426
+ const base = node2.span.start;
6427
+ return { ...node2, span, children: node2.children.map((c) => relativizeCST(c, base)) };
6428
+ }
6429
+ return { ...node2, span };
6430
+ }
6431
+ function absolutizeCST(node2, parentBase = 0) {
6432
+ const start = parentBase + node2.span.start;
6433
+ const span = { start, end: parentBase + node2.span.end };
6434
+ if (node2.children) {
6435
+ return { ...node2, span, children: node2.children.map((c) => absolutizeCST(c, start)) };
6436
+ }
6437
+ return { ...node2, span };
6438
+ }
6439
+ function absoluteSpanCST(root, path) {
6440
+ let base = 0;
6441
+ let node2 = root;
6442
+ for (const idx of path) {
6443
+ base += node2.span.start;
6444
+ const child = node2.children?.[idx];
6445
+ if (!child) throw new RangeError(`absoluteSpanCST: no child ${idx} on path ${path.join(".")}`);
6446
+ node2 = child;
6447
+ }
6448
+ return { start: base + node2.span.start, end: base + node2.span.end };
6449
+ }
6450
+ function shiftAbsolute(node2, at, delta) {
6451
+ const s = node2.start >= at ? node2.start + delta : node2.start;
6452
+ const e = node2.end >= at ? node2.end + delta : node2.end;
6453
+ return {
6454
+ start: s,
6455
+ end: e,
6456
+ children: node2.children.map((c) => shiftAbsolute(c, at, delta))
6457
+ };
6458
+ }
6459
+ function applyEdit(root, at, delta, stats) {
6460
+ return editNode(root, at, delta, 0, 0, stats);
6461
+ }
6462
+ function editNode(node2, at, delta, parentBase, parentShift, stats) {
6463
+ const absStart = parentBase + node2.start;
6464
+ const absEnd = parentBase + node2.end;
6465
+ if (absEnd < at) return node2;
6466
+ const startShifts = absStart >= at;
6467
+ if (startShifts && parentShift === delta) return node2;
6468
+ if (stats) stats.allocated++;
6469
+ const newAbsStart = startShifts ? absStart + delta : absStart;
6470
+ const newAbsEnd = absEnd + delta;
6471
+ const newParentBase = parentBase + parentShift;
6472
+ const newStart = newAbsStart - newParentBase;
6473
+ const newEnd = newAbsEnd - newParentBase;
6474
+ const ownShift = newAbsStart - absStart;
6475
+ let changed = false;
6476
+ const newChildren = [];
6477
+ for (const c of node2.children) {
6478
+ const nc = editNode(c, at, delta, absStart, ownShift, stats);
6479
+ if (nc !== c) changed = true;
6480
+ newChildren.push(nc);
6481
+ }
6482
+ return {
6483
+ start: newStart,
6484
+ end: newEnd,
6485
+ children: changed ? newChildren : node2.children
6486
+ };
6487
+ }
6488
+
6396
6489
  // src/functional/doc.ts
6490
+ function asRuleFn(entry) {
6491
+ return typeof entry === "function" ? entry : (input, pos, ctx) => entry.parse(input, pos, ctx);
6492
+ }
6493
+ function defOf(entry) {
6494
+ return typeof entry === "object" && entry !== null && "_def" in entry ? entry._def : void 0;
6495
+ }
6496
+ function producesRepetition(def, depth = 0) {
6497
+ if (!def || depth > 24) return false;
6498
+ const d = def;
6499
+ switch (d.tag) {
6500
+ case "sepBy":
6501
+ case "many":
6502
+ case "oneOrMore":
6503
+ return true;
6504
+ // Rule entries and `ref`s wrap their body in a `lazy` thunk — resolve it. The
6505
+ // `depth` cap bounds any self-referential cycle (a repetition, if present, is
6506
+ // found shallowly before recursion goes deep).
6507
+ case "lazy": {
6508
+ const thunk = d.thunk;
6509
+ let inner;
6510
+ try {
6511
+ inner = typeof thunk === "function" ? thunk() : void 0;
6512
+ } catch {
6513
+ return false;
6514
+ }
6515
+ return producesRepetition(inner?._def, depth + 1);
6516
+ }
6517
+ // Transparent wrappers — look through to the inner parser.
6518
+ case "node":
6519
+ case "transform":
6520
+ case "token":
6521
+ case "label":
6522
+ case "field":
6523
+ case "expect":
6524
+ case "withCtx":
6525
+ case "grammar":
6526
+ case "optional":
6527
+ return producesRepetition(defOf(d.parser), depth + 1);
6528
+ case "skip":
6529
+ return producesRepetition(defOf(d.main), depth + 1);
6530
+ // A bracketed/anchored list is a sequence whose element run is a repetition.
6531
+ case "sequence":
6532
+ return d.parsers.some((p) => producesRepetition(defOf(p), depth + 1));
6533
+ default:
6534
+ return false;
6535
+ }
6536
+ }
6397
6537
  var REENTRY_MAX_SPAN_FRACTION = 0.5;
6398
6538
  function isNode(x) {
6399
6539
  return typeof x === "object" && x !== null && x._tag === "node";
6400
6540
  }
6401
- function findContaining(node2, pos, path = []) {
6541
+ function findContaining(node2, nodeAbsStart, pos, path = []) {
6402
6542
  for (let i = 0; i < node2.children.length; i++) {
6403
6543
  const child = node2.children[i];
6404
6544
  if (!isNode(child)) continue;
6405
- if (child.span.start <= pos && pos < child.span.end) {
6406
- const inner = findContaining(child, pos, [...path, i]);
6545
+ const childAbsStart = nodeAbsStart + child.span.start;
6546
+ const childAbsEnd = nodeAbsStart + child.span.end;
6547
+ if (childAbsStart <= pos && pos < childAbsEnd) {
6548
+ const inner = findContaining(child, childAbsStart, pos, [...path, i]);
6407
6549
  return inner ?? { node: child, path: [...path, i] };
6408
6550
  }
6409
6551
  }
@@ -6430,24 +6572,20 @@ function replaceAtPath(rebuild, root, path, newNode) {
6430
6572
  function defaultRebuild(node2, children) {
6431
6573
  return { ...node2, children };
6432
6574
  }
6433
- function shiftSpans(child, delta) {
6575
+ function shiftRelStart(child, delta) {
6434
6576
  const c = child;
6435
- const span = { start: c.span.start + delta, end: c.span.end + delta };
6436
- if (Array.isArray(c.children)) {
6437
- return { ...c, span, children: c.children.map((g) => shiftSpans(g, delta)) };
6438
- }
6439
- return { ...c, span };
6577
+ return { ...c, span: { start: c.span.start + delta, end: c.span.end + delta } };
6440
6578
  }
6441
- function graftAndShift(root, path, newNode, delta) {
6579
+ function graftRelative(root, path, newNode, delta) {
6442
6580
  if (path.length === 0) return newNode;
6443
6581
  const [idx, ...rest] = path;
6444
6582
  const oldChildren = root.children;
6445
6583
  const newChildren = oldChildren.map((child, i) => {
6446
6584
  if (i < idx) return child;
6447
6585
  if (i === idx) {
6448
- return rest.length === 0 ? newNode : graftAndShift(child, rest, newNode, delta);
6586
+ return rest.length === 0 ? newNode : graftRelative(child, rest, newNode, delta);
6449
6587
  }
6450
- return shiftSpans(child, delta);
6588
+ return shiftRelStart(child, delta);
6451
6589
  });
6452
6590
  return {
6453
6591
  ...root,
@@ -6455,6 +6593,96 @@ function graftAndShift(root, path, newNode, delta) {
6455
6593
  children: newChildren
6456
6594
  };
6457
6595
  }
6596
+ function parseMiddle(input, reStart, reEnd, cStart, ruleFn, separator, build) {
6597
+ const ctx = { trackLines: false, state: null, build };
6598
+ const out = [];
6599
+ let pos = reStart;
6600
+ let guard2 = 0;
6601
+ while (pos < reEnd) {
6602
+ if (++guard2 > reEnd - reStart + 2) return null;
6603
+ if (separator && out.length > 0 && out[out.length - 1]._tag === "node") {
6604
+ if (pos + separator.length > reEnd || !input.startsWith(separator, pos)) return null;
6605
+ out.push({ _tag: "leaf", value: separator, span: { start: pos - cStart, end: pos + separator.length - cStart } });
6606
+ pos += separator.length;
6607
+ continue;
6608
+ }
6609
+ let r;
6610
+ try {
6611
+ r = ruleFn(input, pos, ctx);
6612
+ } catch {
6613
+ return null;
6614
+ }
6615
+ if (!r.ok || r.span.end <= pos || r.span.end > reEnd) return null;
6616
+ out.push(relativizeCST(r.value, cStart));
6617
+ pos = r.span.end;
6618
+ }
6619
+ return pos === reEnd ? out : null;
6620
+ }
6621
+ function tryListSplice(root, path, C, cStart, newInput, from, to, delta, registry, build) {
6622
+ const kids = C.children;
6623
+ if (kids.length === 0) return null;
6624
+ let h = 0;
6625
+ while (h < kids.length && cStart + kids[h].span.end <= from) h++;
6626
+ while (h > 0 && kids[h - 1]._tag === "node") h--;
6627
+ let t = kids.length;
6628
+ while (t > h && cStart + kids[t - 1].span.start >= to) t--;
6629
+ while (t < kids.length && kids[t]._tag !== "node") t++;
6630
+ if (t >= kids.length) return null;
6631
+ for (let i = t; i < kids.length; i++) {
6632
+ if (kids[i]._tag === "node" && kids[i].state != null) return null;
6633
+ }
6634
+ let elemType;
6635
+ let elemCount = 0;
6636
+ for (const k of kids) {
6637
+ if (k._tag !== "node") continue;
6638
+ elemCount++;
6639
+ if (elemType === void 0) elemType = k.type;
6640
+ else if (k.type !== elemType) return null;
6641
+ }
6642
+ if (elemType === void 0 || elemCount < 2) return null;
6643
+ const ruleFn = registry[elemType];
6644
+ if (!ruleFn) return null;
6645
+ let separator = null;
6646
+ for (let i = 1; i < kids.length - 1; i++) {
6647
+ if (kids[i - 1]._tag === "node" && kids[i + 1]._tag === "node") {
6648
+ if (kids[i]._tag !== "leaf") return null;
6649
+ const sep = kids[i].value ?? null;
6650
+ if (separator === null) separator = sep;
6651
+ else if (sep !== separator) return null;
6652
+ }
6653
+ }
6654
+ if (separator === null) return null;
6655
+ const first = kids[0];
6656
+ const last = kids[kids.length - 1];
6657
+ if (first._tag === "leaf" && first.value !== separator && from < cStart + first.span.end) return null;
6658
+ if (last._tag === "leaf" && last.value !== separator && to > cStart + last.span.start) return null;
6659
+ const reStart = h > 0 ? cStart + kids[h - 1].span.end : cStart;
6660
+ const reEnd = cStart + kids[t].span.start + delta;
6661
+ if (reEnd < reStart) return null;
6662
+ const middle = parseMiddle(newInput, reStart, reEnd, cStart, ruleFn, separator, build);
6663
+ if (!middle) return null;
6664
+ if (middle.length > 0) {
6665
+ const last2 = middle[middle.length - 1];
6666
+ if (!(last2._tag === "leaf" && last2.value === separator)) return null;
6667
+ }
6668
+ if (reEnd < newInput.length) {
6669
+ for (const sentinel of [" ", "\uFFFF"]) {
6670
+ if (newInput[reEnd] === sentinel) continue;
6671
+ const probed = newInput.slice(0, reEnd) + sentinel.repeat(newInput.length - reEnd);
6672
+ const probe = parseMiddle(probed, reStart, reEnd, cStart, ruleFn, separator, build);
6673
+ if (!probe || probe.length !== middle.length) return null;
6674
+ for (let i = 0; i < middle.length; i++) if (!structurallyEqual(probe[i], middle[i])) return null;
6675
+ }
6676
+ }
6677
+ const head = kids.slice(0, h);
6678
+ const tail = kids.slice(t).map((k) => shiftRelStart(k, delta));
6679
+ const newC = {
6680
+ ...C,
6681
+ span: { start: C.span.start, end: C.span.end + delta },
6682
+ children: [...head, ...middle, ...tail]
6683
+ };
6684
+ return graftRelative(root, path, newC, delta);
6685
+ }
6458
6686
  function structurallyEqual(a, b) {
6459
6687
  if (a === b) return true;
6460
6688
  if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
@@ -6498,27 +6726,68 @@ function boundaryIsSafe(ruleFn, newInput, start, boundary, state, build, produce
6498
6726
  }
6499
6727
  var ParseDocImpl = class _ParseDocImpl {
6500
6728
  _registry;
6729
+ /** Registry entries normalized to callable parse functions (memoized once). */
6730
+ _fns;
6731
+ /** Rule names the grammar proves are genuine repetitions — the ONLY splice-safe types. */
6732
+ _reps;
6501
6733
  _rootRule;
6502
6734
  _opts;
6503
- tree;
6735
+ /**
6736
+ * The tree, held in whichever coordinate system it arrived in. A fresh parse
6737
+ * arrives ABSOLUTE (`_abs` set); an incremental graft arrives PARENT-RELATIVE
6738
+ * (`_rel` set). The public `tree` is always the RELATIVE form (so untouched
6739
+ * subtrees stay shared by identity across edits and reads are O(1)); it's
6740
+ * materialized from `_abs` once, on demand, and memoized. `undefined` = not yet
6741
+ * computed; `null` = failed parse. A fresh parse that's never edited nor
6742
+ * tree-read pays no conversion — important for the full-reparse fallback path.
6743
+ */
6744
+ _abs;
6745
+ _rel;
6504
6746
  errors;
6505
6747
  input;
6506
- constructor(registry, rootRule, opts, tree, errors, input) {
6748
+ constructor(registry, rootRule, opts, trees, errors, input) {
6507
6749
  this._registry = registry;
6750
+ this._fns = {};
6751
+ this._reps = /* @__PURE__ */ new Set();
6752
+ for (const [name, entry] of Object.entries(registry)) {
6753
+ this._fns[name] = asRuleFn(entry);
6754
+ if (producesRepetition(defOf(entry))) this._reps.add(name);
6755
+ }
6508
6756
  this._rootRule = rootRule;
6509
6757
  this._opts = opts;
6510
- this.tree = tree;
6758
+ this._abs = trees.abs;
6759
+ this._rel = trees.rel;
6511
6760
  this.errors = errors;
6512
6761
  this.input = input;
6513
6762
  }
6763
+ /**
6764
+ * The parse tree with PARENT-RELATIVE spans — a node's `span` is relative to
6765
+ * its parent's start (root base 0). This is the shareable representation:
6766
+ * untouched subtrees keep the same identity across `.edit()`s, and reading the
6767
+ * tree after a length-changing edit is O(1) (no offset rewrite). For absolute
6768
+ * positions use the O(depth) cursor `spanAt(path)`, or `absolutizeCST(tree)` to
6769
+ * materialize the whole absolute tree. (A fresh non-incremental `node().parse()`
6770
+ * result is unchanged — still absolute.)
6771
+ */
6772
+ get tree() {
6773
+ if (this._rel === void 0) {
6774
+ this._rel = this._abs ? relativizeCST(this._abs, 0) : null;
6775
+ }
6776
+ return this._rel;
6777
+ }
6778
+ spanAt(path) {
6779
+ const rel = this.tree;
6780
+ if (!rel) throw new Error("spanAt on a failed parse (tree is null)");
6781
+ return absoluteSpanCST(rel, path);
6782
+ }
6514
6783
  edit(from, to, replacement) {
6515
6784
  const newInput = this.input.slice(0, from) + replacement + this.input.slice(to);
6516
6785
  const reparse = () => parseDoc(this._registry, this._rootRule, newInput, this._opts);
6517
- if (!this.tree) return reparse();
6786
+ const root = this.tree;
6787
+ if (!root) return reparse();
6518
6788
  const delta = replacement.length - (to - from);
6519
- const found = findContaining(this.tree, from);
6520
- if (!found) return reparse();
6521
- const ancestors = ancestorsAt(this.tree, found.path);
6789
+ const found = findContaining(root, 0, from) ?? { node: root, path: [] };
6790
+ const ancestors = ancestorsAt(root, found.path);
6522
6791
  const candidates = [found];
6523
6792
  const pathCopy = [...found.path];
6524
6793
  for (let i = ancestors.length - 2; i >= 0; i--) {
@@ -6527,37 +6796,50 @@ var ParseDocImpl = class _ParseDocImpl {
6527
6796
  }
6528
6797
  const rebuild = this._opts.rebuild ?? defaultRebuild;
6529
6798
  for (const { node: node2, path } of candidates) {
6530
- if (node2.span.end - node2.span.start > this.input.length * REENTRY_MAX_SPAN_FRACTION) break;
6531
- const ruleFn = this._registry[node2.type];
6799
+ const { start: absStart, end: absEnd } = absoluteSpanCST(root, path);
6800
+ if (absEnd - absStart > this.input.length * REENTRY_MAX_SPAN_FRACTION) break;
6801
+ const ruleFn = this._fns[node2.type];
6532
6802
  if (!ruleFn) continue;
6533
- if (!(node2.span.start <= from && to <= node2.span.end)) continue;
6803
+ if (!(absStart <= from && to <= absEnd)) continue;
6534
6804
  const ctx = { trackLines: false, state: node2.state, build: this._opts.build };
6535
- const r = ruleFn(newInput, node2.span.start, ctx);
6805
+ const r = ruleFn(newInput, absStart, ctx);
6536
6806
  if (!r.ok) continue;
6537
- if (r.span.end !== node2.span.end + delta) continue;
6538
- if (!boundaryIsSafe(ruleFn, newInput, node2.span.start, node2.span.end + delta, node2.state, this._opts.build, r)) {
6807
+ if (r.span.end !== absEnd + delta) continue;
6808
+ if (!boundaryIsSafe(ruleFn, newInput, absStart, absEnd + delta, node2.state, this._opts.build, r)) {
6539
6809
  continue;
6540
6810
  }
6811
+ const parentBase = absStart - node2.span.start;
6812
+ const newRel = relativizeCST(r.value, parentBase);
6541
6813
  if (delta === 0) {
6542
- const newTree2 = replaceAtPath(rebuild, this.tree, path, r.value);
6543
- return new _ParseDocImpl(this._registry, this._rootRule, this._opts, newTree2, [], newInput);
6814
+ const newTree2 = replaceAtPath(rebuild, root, path, newRel);
6815
+ return new _ParseDocImpl(this._registry, this._rootRule, this._opts, { rel: newTree2 }, [], newInput);
6544
6816
  }
6545
6817
  if (this._opts.rebuild) return reparse();
6546
- const newTree = graftAndShift(this.tree, path, r.value, delta);
6547
- return new _ParseDocImpl(this._registry, this._rootRule, this._opts, newTree, [], newInput);
6818
+ const newTree = graftRelative(root, path, newRel, delta);
6819
+ return new _ParseDocImpl(this._registry, this._rootRule, this._opts, { rel: newTree }, [], newInput);
6820
+ }
6821
+ if (this._opts.structuralReuse && delta !== 0 && !this._opts.rebuild) {
6822
+ const spliceCandidates = [...candidates, { node: root, path: [] }];
6823
+ for (const { node: node2, path } of spliceCandidates) {
6824
+ if (!this._reps.has(node2.type)) continue;
6825
+ const { start: cStart, end: cEnd } = absoluteSpanCST(root, path);
6826
+ if (!(cStart <= from && to <= cEnd)) continue;
6827
+ const spliced = tryListSplice(root, path, node2, cStart, newInput, from, to, delta, this._fns, this._opts.build);
6828
+ if (spliced) return new _ParseDocImpl(this._registry, this._rootRule, this._opts, { rel: spliced }, [], newInput);
6829
+ }
6548
6830
  }
6549
6831
  return reparse();
6550
6832
  }
6551
6833
  };
6552
6834
  function parseDoc(registry, rootRule, input, opts = {}) {
6553
- const ruleFn = registry[rootRule];
6554
- if (!ruleFn) throw new Error(`No rule '${rootRule}' in registry`);
6835
+ const entry = registry[rootRule];
6836
+ if (!entry) throw new Error(`No rule '${rootRule}' in registry`);
6555
6837
  const ctx = { trackLines: false, state: opts.state, build: opts.build };
6556
- const r = ruleFn(input, 0, ctx);
6838
+ const r = asRuleFn(entry)(input, 0, ctx);
6557
6839
  if (r.ok) {
6558
- return new ParseDocImpl(registry, rootRule, opts, r.value, [], input);
6840
+ return new ParseDocImpl(registry, rootRule, opts, { abs: r.value }, [], input);
6559
6841
  }
6560
- return new ParseDocImpl(registry, rootRule, opts, null, [{ ok: false, expected: r.expected, span: r.span }], input);
6842
+ return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [{ ok: false, expected: r.expected, span: r.span }], input);
6561
6843
  }
6562
6844
 
6563
6845
  // src/functional/run.ts
@@ -6926,78 +7208,14 @@ function buildOffsetIndex(root, input = "") {
6926
7208
  return new OffsetIndex(collectLeafSlots(root), 0, input.length);
6927
7209
  }
6928
7210
 
6929
- // src/cst/relative-spans.ts
6930
- function relativize(node2, parentBase = 0) {
6931
- return {
6932
- start: node2.start - parentBase,
6933
- end: node2.end - parentBase,
6934
- children: node2.children.map((c) => relativize(c, node2.start))
6935
- };
6936
- }
6937
- function absolutize(node2, parentBase = 0) {
6938
- const start = parentBase + node2.start;
6939
- return {
6940
- start,
6941
- end: parentBase + node2.end,
6942
- children: node2.children.map((c) => absolutize(c, start))
6943
- };
6944
- }
6945
- function absoluteSpanAt(root, path) {
6946
- let base = 0;
6947
- let node2 = root;
6948
- for (const idx of path) {
6949
- base += node2.start;
6950
- const child = node2.children[idx];
6951
- if (!child) throw new RangeError(`absoluteSpanAt: no child ${idx} on path ${path.join(".")}`);
6952
- node2 = child;
6953
- }
6954
- return { start: base + node2.start, end: base + node2.end };
6955
- }
6956
- function shiftAbsolute(node2, at, delta) {
6957
- const s = node2.start >= at ? node2.start + delta : node2.start;
6958
- const e = node2.end >= at ? node2.end + delta : node2.end;
6959
- return {
6960
- start: s,
6961
- end: e,
6962
- children: node2.children.map((c) => shiftAbsolute(c, at, delta))
6963
- };
6964
- }
6965
- function applyEdit(root, at, delta, stats) {
6966
- return editNode(root, at, delta, 0, 0, stats);
6967
- }
6968
- function editNode(node2, at, delta, parentBase, parentShift, stats) {
6969
- const absStart = parentBase + node2.start;
6970
- const absEnd = parentBase + node2.end;
6971
- if (absEnd < at) return node2;
6972
- const startShifts = absStart >= at;
6973
- if (startShifts && parentShift === delta) return node2;
6974
- if (stats) stats.allocated++;
6975
- const newAbsStart = startShifts ? absStart + delta : absStart;
6976
- const newAbsEnd = absEnd + delta;
6977
- const newParentBase = parentBase + parentShift;
6978
- const newStart = newAbsStart - newParentBase;
6979
- const newEnd = newAbsEnd - newParentBase;
6980
- const ownShift = newAbsStart - absStart;
6981
- let changed = false;
6982
- const newChildren = [];
6983
- for (const c of node2.children) {
6984
- const nc = editNode(c, at, delta, absStart, ownShift, stats);
6985
- if (nc !== c) changed = true;
6986
- newChildren.push(nc);
6987
- }
6988
- return {
6989
- start: newStart,
6990
- end: newEnd,
6991
- children: changed ? newChildren : node2.children
6992
- };
6993
- }
6994
-
6995
7211
  // src/index.ts
6996
7212
  registerRegexAnalyzer(firstSetFromRegex);
6997
7213
  export {
6998
7214
  OffsetIndex,
6999
7215
  absoluteSpanAt,
7216
+ absoluteSpanCST,
7000
7217
  absolutize,
7218
+ absolutizeCST,
7001
7219
  annotateSpan,
7002
7220
  applyEdit,
7003
7221
  balanced,
@@ -7042,6 +7260,7 @@ export {
7042
7260
  ref,
7043
7261
  regex,
7044
7262
  relativize,
7263
+ relativizeCST,
7045
7264
  rules,
7046
7265
  run,
7047
7266
  scanTo,