prosemirror-transform 1.10.4 → 1.11.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/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## 1.11.0 (2026-01-21)
2
+
3
+ ### New features
4
+
5
+ The new `Tranform.changedRange` method gives you a document range that includes all changes made by the transform/transaction.
6
+
7
+ ## 1.10.5 (2025-11-11)
8
+
9
+ ### Bug fixes
10
+
11
+ Fix a bug in `liftTarget` that caused it to fail to properly check content constraints when a lift would split a node.
12
+
1
13
  ## 1.10.4 (2025-04-22)
2
14
 
3
15
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -853,12 +853,14 @@ function canCut(node, start, end) {
853
853
  function liftTarget(range) {
854
854
  var parent = range.parent;
855
855
  var content = parent.content.cutByIndex(range.startIndex, range.endIndex);
856
- for (var depth = range.depth;; --depth) {
856
+ for (var depth = range.depth, contentBefore = 0, contentAfter = 0;; --depth) {
857
857
  var node = range.$from.node(depth);
858
- var index = range.$from.index(depth),
859
- endIndex = range.$to.indexAfter(depth);
858
+ var index = range.$from.index(depth) + contentBefore,
859
+ endIndex = range.$to.indexAfter(depth) - contentAfter;
860
860
  if (depth < range.depth && node.canReplace(index, endIndex, content)) return depth;
861
861
  if (depth == 0 || node.type.spec.isolating || !canCut(node, index, endIndex)) break;
862
+ if (index) contentBefore = 1;
863
+ if (endIndex < node.childCount) contentAfter = 1;
862
864
  }
863
865
  return null;
864
866
  }
@@ -1434,7 +1436,7 @@ function _replaceRange(tr, from, to, slice) {
1434
1436
  var $from = tr.doc.resolve(from),
1435
1437
  $to = tr.doc.resolve(to);
1436
1438
  if (fitsTrivially($from, $to, slice)) return tr.step(new ReplaceStep(from, to, slice));
1437
- var targetDepths = coveredDepths($from, tr.doc.resolve(to));
1439
+ var targetDepths = coveredDepths($from, $to);
1438
1440
  if (targetDepths[targetDepths.length - 1] == 0) targetDepths.pop();
1439
1441
  var preferredTarget = -($from.depth + 1);
1440
1442
  targetDepths.unshift(preferredTarget);
@@ -1689,6 +1691,27 @@ var Transform = function () {
1689
1691
  get: function get() {
1690
1692
  return this.steps.length > 0;
1691
1693
  }
1694
+ }, {
1695
+ key: "changedRange",
1696
+ value: function changedRange() {
1697
+ var from = 1e9,
1698
+ to = -1e9;
1699
+ for (var i = 0; i < this.mapping.maps.length; i++) {
1700
+ var map = this.mapping.maps[i];
1701
+ if (i) {
1702
+ from = map.map(from, 1);
1703
+ to = map.map(to, -1);
1704
+ }
1705
+ map.forEach(function (_f, _t, fromB, toB) {
1706
+ from = Math.min(from, fromB);
1707
+ to = Math.max(to, toB);
1708
+ });
1709
+ }
1710
+ return from == 1e9 ? null : {
1711
+ from: from,
1712
+ to: to
1713
+ };
1714
+ }
1692
1715
  }, {
1693
1716
  key: "addStep",
1694
1717
  value: function addStep(step, doc) {
package/dist/index.d.cts CHANGED
@@ -326,6 +326,16 @@ declare class Transform {
326
326
  */
327
327
  get docChanged(): boolean;
328
328
  /**
329
+ Return a single range, in post-transform document positions,
330
+ that covers all content changed by this transform. Returns null
331
+ if no replacements are made. Note that this will ignore changes
332
+ that add/remove marks without replacing the underlying content.
333
+ */
334
+ changedRange(): {
335
+ from: number;
336
+ to: number;
337
+ } | null;
338
+ /**
329
339
  Replace the part of the document between `from` and `to` with the
330
340
  given `slice`.
331
341
  */
package/dist/index.d.ts CHANGED
@@ -326,6 +326,16 @@ declare class Transform {
326
326
  */
327
327
  get docChanged(): boolean;
328
328
  /**
329
+ Return a single range, in post-transform document positions,
330
+ that covers all content changed by this transform. Returns null
331
+ if no replacements are made. Note that this will ignore changes
332
+ that add/remove marks without replacing the underlying content.
333
+ */
334
+ changedRange(): {
335
+ from: number;
336
+ to: number;
337
+ } | null;
338
+ /**
329
339
  Replace the part of the document between `from` and `to` with the
330
340
  given `slice`.
331
341
  */
package/dist/index.js CHANGED
@@ -982,13 +982,17 @@ can be lifted. Will not go across
982
982
  function liftTarget(range) {
983
983
  let parent = range.parent;
984
984
  let content = parent.content.cutByIndex(range.startIndex, range.endIndex);
985
- for (let depth = range.depth;; --depth) {
985
+ for (let depth = range.depth, contentBefore = 0, contentAfter = 0;; --depth) {
986
986
  let node = range.$from.node(depth);
987
- let index = range.$from.index(depth), endIndex = range.$to.indexAfter(depth);
987
+ let index = range.$from.index(depth) + contentBefore, endIndex = range.$to.indexAfter(depth) - contentAfter;
988
988
  if (depth < range.depth && node.canReplace(index, endIndex, content))
989
989
  return depth;
990
990
  if (depth == 0 || node.type.spec.isolating || !canCut(node, index, endIndex))
991
991
  break;
992
+ if (index)
993
+ contentBefore = 1;
994
+ if (endIndex < node.childCount)
995
+ contentAfter = 1;
992
996
  }
993
997
  return null;
994
998
  }
@@ -1639,7 +1643,7 @@ function replaceRange(tr, from, to, slice) {
1639
1643
  let $from = tr.doc.resolve(from), $to = tr.doc.resolve(to);
1640
1644
  if (fitsTrivially($from, $to, slice))
1641
1645
  return tr.step(new ReplaceStep(from, to, slice));
1642
- let targetDepths = coveredDepths($from, tr.doc.resolve(to));
1646
+ let targetDepths = coveredDepths($from, $to);
1643
1647
  // Can't replace the whole document, so remove 0 if it's present
1644
1648
  if (targetDepths[targetDepths.length - 1] == 0)
1645
1649
  targetDepths.pop();
@@ -1942,6 +1946,27 @@ class Transform {
1942
1946
  return this.steps.length > 0;
1943
1947
  }
1944
1948
  /**
1949
+ Return a single range, in post-transform document positions,
1950
+ that covers all content changed by this transform. Returns null
1951
+ if no replacements are made. Note that this will ignore changes
1952
+ that add/remove marks without replacing the underlying content.
1953
+ */
1954
+ changedRange() {
1955
+ let from = 1e9, to = -1e9;
1956
+ for (let i = 0; i < this.mapping.maps.length; i++) {
1957
+ let map = this.mapping.maps[i];
1958
+ if (i) {
1959
+ from = map.map(from, 1);
1960
+ to = map.map(to, -1);
1961
+ }
1962
+ map.forEach((_f, _t, fromB, toB) => {
1963
+ from = Math.min(from, fromB);
1964
+ to = Math.max(to, toB);
1965
+ });
1966
+ }
1967
+ return from == 1e9 ? null : { from, to };
1968
+ }
1969
+ /**
1945
1970
  @internal
1946
1971
  */
1947
1972
  addStep(step, doc) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-transform",
3
- "version": "1.10.4",
3
+ "version": "1.11.0",
4
4
  "description": "ProseMirror document transformations",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/replace.ts CHANGED
@@ -338,7 +338,7 @@ export function replaceRange(tr: Transform, from: number, to: number, slice: Sli
338
338
  if (fitsTrivially($from, $to, slice))
339
339
  return tr.step(new ReplaceStep(from, to, slice))
340
340
 
341
- let targetDepths = coveredDepths($from, tr.doc.resolve(to))
341
+ let targetDepths = coveredDepths($from, $to)
342
342
  // Can't replace the whole document, so remove 0 if it's present
343
343
  if (targetDepths[targetDepths.length - 1] == 0) targetDepths.pop()
344
344
  // Negative numbers represent not expansion over the whole node at
package/src/structure.ts CHANGED
@@ -15,12 +15,14 @@ function canCut(node: Node, start: number, end: number) {
15
15
  export function liftTarget(range: NodeRange): number | null {
16
16
  let parent = range.parent
17
17
  let content = parent.content.cutByIndex(range.startIndex, range.endIndex)
18
- for (let depth = range.depth;; --depth) {
18
+ for (let depth = range.depth, contentBefore = 0, contentAfter = 0;; --depth) {
19
19
  let node = range.$from.node(depth)
20
- let index = range.$from.index(depth), endIndex = range.$to.indexAfter(depth)
20
+ let index = range.$from.index(depth) + contentBefore, endIndex = range.$to.indexAfter(depth) - contentAfter
21
21
  if (depth < range.depth && node.canReplace(index, endIndex, content))
22
22
  return depth
23
23
  if (depth == 0 || node.type.spec.isolating || !canCut(node, index, endIndex)) break
24
+ if (index) contentBefore = 1
25
+ if (endIndex < node.childCount) contentAfter = 1
24
26
  }
25
27
  return null
26
28
  }
package/src/transform.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import {Node, NodeType, Mark, MarkType, ContentMatch, Slice, Fragment, NodeRange, Attrs} from "prosemirror-model"
2
-
3
2
  import {Mapping} from "./map"
4
3
  import {Step} from "./step"
5
4
  import {addMark, removeMark, clearIncompatible} from "./mark"
@@ -66,6 +65,26 @@ export class Transform {
66
65
  return this.steps.length > 0
67
66
  }
68
67
 
68
+ /// Return a single range, in post-transform document positions,
69
+ /// that covers all content changed by this transform. Returns null
70
+ /// if no replacements are made. Note that this will ignore changes
71
+ /// that add/remove marks without replacing the underlying content.
72
+ changedRange() {
73
+ let from = 1e9, to = -1e9
74
+ for (let i = 0; i < this.mapping.maps.length; i++) {
75
+ let map = this.mapping.maps[i]
76
+ if (i) {
77
+ from = map.map(from, 1)
78
+ to = map.map(to, -1)
79
+ }
80
+ map.forEach((_f, _t, fromB, toB) => {
81
+ from = Math.min(from, fromB)
82
+ to = Math.max(to, toB)
83
+ })
84
+ }
85
+ return from == 1e9 ? null : {from, to}
86
+ }
87
+
69
88
  /// @internal
70
89
  addStep(step: Step, doc: Node) {
71
90
  this.docs.push(this.doc)
@@ -206,7 +225,7 @@ export class Transform {
206
225
  if (mark instanceof Mark) {
207
226
  if (mark.isInSet(node.marks)) this.step(new RemoveNodeMarkStep(pos, mark))
208
227
  } else {
209
- let set = node.marks, found, steps: Step[] = []
228
+ let set = node.marks, found: Mark | undefined, steps: Step[] = []
210
229
  while (found = mark.isInSet(set)) {
211
230
  steps.push(new RemoveNodeMarkStep(pos, found))
212
231
  set = found.removeFromSet(set)