prosemirror-transform 1.8.0 → 1.10.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.cts CHANGED
@@ -406,7 +406,7 @@ declare class Transform {
406
406
  Set the type of all textblocks (partly) between `from` and `to` to
407
407
  the given node type with the given attributes.
408
408
  */
409
- setBlockType(from: number, to: number | undefined, type: NodeType, attrs?: Attrs | null): this;
409
+ setBlockType(from: number, to: number | undefined, type: NodeType, attrs?: Attrs | null | ((oldNode: Node) => Attrs)): this;
410
410
  /**
411
411
  Change the type, attributes, and/or marks of the node at `pos`.
412
412
  When `type` isn't given, the existing node type is preserved,
@@ -836,4 +836,4 @@ would be a no-op (an empty slice over an empty range).
836
836
  */
837
837
  declare function replaceStep(doc: Node, from: number, to?: number, slice?: Slice): Step | null;
838
838
 
839
- export { AddMarkStep, AddNodeMarkStep, AttrStep, DocAttrStep, MapResult, Mappable, Mapping, RemoveMarkStep, RemoveNodeMarkStep, ReplaceAroundStep, ReplaceStep, Step, StepMap, StepResult, Transform, canJoin, canSplit, dropPoint, findWrapping, insertPoint, joinPoint, liftTarget, replaceStep };
839
+ export { AddMarkStep, AddNodeMarkStep, AttrStep, DocAttrStep, MapResult, type Mappable, Mapping, RemoveMarkStep, RemoveNodeMarkStep, ReplaceAroundStep, ReplaceStep, Step, StepMap, StepResult, Transform, canJoin, canSplit, dropPoint, findWrapping, insertPoint, joinPoint, liftTarget, replaceStep };
package/dist/index.d.ts CHANGED
@@ -406,7 +406,7 @@ declare class Transform {
406
406
  Set the type of all textblocks (partly) between `from` and `to` to
407
407
  the given node type with the given attributes.
408
408
  */
409
- setBlockType(from: number, to: number | undefined, type: NodeType, attrs?: Attrs | null): this;
409
+ setBlockType(from: number, to: number | undefined, type: NodeType, attrs?: Attrs | null | ((oldNode: Node) => Attrs)): this;
410
410
  /**
411
411
  Change the type, attributes, and/or marks of the node at `pos`.
412
412
  When `type` isn't given, the existing node type is preserved,
@@ -836,4 +836,4 @@ would be a no-op (an empty slice over an empty range).
836
836
  */
837
837
  declare function replaceStep(doc: Node, from: number, to?: number, slice?: Slice): Step | null;
838
838
 
839
- export { AddMarkStep, AddNodeMarkStep, AttrStep, DocAttrStep, MapResult, Mappable, Mapping, RemoveMarkStep, RemoveNodeMarkStep, ReplaceAroundStep, ReplaceStep, Step, StepMap, StepResult, Transform, canJoin, canSplit, dropPoint, findWrapping, insertPoint, joinPoint, liftTarget, replaceStep };
839
+ export { AddMarkStep, AddNodeMarkStep, AttrStep, DocAttrStep, MapResult, type Mappable, Mapping, RemoveMarkStep, RemoveNodeMarkStep, ReplaceAroundStep, ReplaceStep, Step, StepMap, StepResult, Transform, canJoin, canSplit, dropPoint, findWrapping, insertPoint, joinPoint, liftTarget, replaceStep };
package/dist/index.js CHANGED
@@ -824,7 +824,8 @@ class ReplaceAroundStep extends Step {
824
824
  }
825
825
  map(mapping) {
826
826
  let from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1);
827
- let gapFrom = mapping.map(this.gapFrom, -1), gapTo = mapping.map(this.gapTo, 1);
827
+ let gapFrom = this.from == this.gapFrom ? from.pos : mapping.map(this.gapFrom, -1);
828
+ let gapTo = this.to == this.gapTo ? to.pos : mapping.map(this.gapTo, 1);
828
829
  if ((from.deletedAcross && to.deletedAcross) || gapFrom < from.pos || gapTo > to.pos)
829
830
  return null;
830
831
  return new ReplaceAroundStep(from.pos, to.pos, gapFrom, gapTo, this.slice, this.insert, this.structure);
@@ -936,7 +937,7 @@ function removeMark(tr, from, to, mark) {
936
937
  });
937
938
  matched.forEach(m => tr.step(new RemoveMarkStep(m.from, m.to, m.style)));
938
939
  }
939
- function clearIncompatible(tr, pos, parentType, match = parentType.contentMatch) {
940
+ function clearIncompatible(tr, pos, parentType, match = parentType.contentMatch, clearNewlines = true) {
940
941
  let node = tr.doc.nodeAt(pos);
941
942
  let replSteps = [], cur = pos + 1;
942
943
  for (let i = 0; i < node.childCount; i++) {
@@ -950,7 +951,7 @@ function clearIncompatible(tr, pos, parentType, match = parentType.contentMatch)
950
951
  for (let j = 0; j < child.marks.length; j++)
951
952
  if (!parentType.allowsMarkType(child.marks[j].type))
952
953
  tr.step(new RemoveMarkStep(cur, end, child.marks[j]));
953
- if (child.isText && !parentType.spec.code) {
954
+ if (clearNewlines && child.isText && parentType.whitespace != "pre") {
954
955
  let m, newline = /\r?\n|\r/g, slice;
955
956
  while (m = newline.exec(child.text)) {
956
957
  if (!slice)
@@ -1074,16 +1075,49 @@ function setBlockType(tr, from, to, type, attrs) {
1074
1075
  throw new RangeError("Type given to setBlockType should be a textblock");
1075
1076
  let mapFrom = tr.steps.length;
1076
1077
  tr.doc.nodesBetween(from, to, (node, pos) => {
1077
- if (node.isTextblock && !node.hasMarkup(type, attrs) && canChangeType(tr.doc, tr.mapping.slice(mapFrom).map(pos), type)) {
1078
+ let attrsHere = typeof attrs == "function" ? attrs(node) : attrs;
1079
+ if (node.isTextblock && !node.hasMarkup(type, attrsHere) &&
1080
+ canChangeType(tr.doc, tr.mapping.slice(mapFrom).map(pos), type)) {
1081
+ let convertNewlines = null;
1082
+ if (type.schema.linebreakReplacement) {
1083
+ let pre = type.whitespace == "pre", supportLinebreak = !!type.contentMatch.matchType(type.schema.linebreakReplacement);
1084
+ if (pre && !supportLinebreak)
1085
+ convertNewlines = false;
1086
+ else if (!pre && supportLinebreak)
1087
+ convertNewlines = true;
1088
+ }
1078
1089
  // Ensure all markup that isn't allowed in the new node type is cleared
1079
- tr.clearIncompatible(tr.mapping.slice(mapFrom).map(pos, 1), type);
1090
+ if (convertNewlines === false)
1091
+ replaceLinebreaks(tr, node, pos, mapFrom);
1092
+ clearIncompatible(tr, tr.mapping.slice(mapFrom).map(pos, 1), type, undefined, convertNewlines === null);
1080
1093
  let mapping = tr.mapping.slice(mapFrom);
1081
1094
  let startM = mapping.map(pos, 1), endM = mapping.map(pos + node.nodeSize, 1);
1082
- tr.step(new ReplaceAroundStep(startM, endM, startM + 1, endM - 1, new Slice(Fragment.from(type.create(attrs, null, node.marks)), 0, 0), 1, true));
1095
+ tr.step(new ReplaceAroundStep(startM, endM, startM + 1, endM - 1, new Slice(Fragment.from(type.create(attrsHere, null, node.marks)), 0, 0), 1, true));
1096
+ if (convertNewlines === true)
1097
+ replaceNewlines(tr, node, pos, mapFrom);
1083
1098
  return false;
1084
1099
  }
1085
1100
  });
1086
1101
  }
1102
+ function replaceNewlines(tr, node, pos, mapFrom) {
1103
+ node.forEach((child, offset) => {
1104
+ if (child.isText) {
1105
+ let m, newline = /\r?\n|\r/g;
1106
+ while (m = newline.exec(child.text)) {
1107
+ let start = tr.mapping.slice(mapFrom).map(pos + 1 + offset + m.index);
1108
+ tr.replaceWith(start, start + 1, node.type.schema.linebreakReplacement.create());
1109
+ }
1110
+ }
1111
+ });
1112
+ }
1113
+ function replaceLinebreaks(tr, node, pos, mapFrom) {
1114
+ node.forEach((child, offset) => {
1115
+ if (child.type == child.type.schema.linebreakReplacement) {
1116
+ let start = tr.mapping.slice(mapFrom).map(pos + 1 + offset);
1117
+ tr.replaceWith(start, start + 1, node.type.schema.text("\n"));
1118
+ }
1119
+ });
1120
+ }
1087
1121
  function canChangeType(doc, pos, type) {
1088
1122
  let $pos = doc.resolve(pos), index = $pos.index();
1089
1123
  return $pos.parent.canReplaceWith(index, index + 1, type);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-transform",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "description": "ProseMirror document transformations",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -24,7 +24,7 @@
24
24
  "url": "git://github.com/prosemirror/prosemirror-transform.git"
25
25
  },
26
26
  "dependencies": {
27
- "prosemirror-model": "^1.0.0"
27
+ "prosemirror-model": "^1.21.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@prosemirror/buildhelper": "^0.1.5",
package/src/mark.ts CHANGED
@@ -72,7 +72,9 @@ export function removeMark(tr: Transform, from: number, to: number, mark?: Mark
72
72
  matched.forEach(m => tr.step(new RemoveMarkStep(m.from, m.to, m.style)))
73
73
  }
74
74
 
75
- export function clearIncompatible(tr: Transform, pos: number, parentType: NodeType, match = parentType.contentMatch) {
75
+ export function clearIncompatible(tr: Transform, pos: number, parentType: NodeType,
76
+ match = parentType.contentMatch,
77
+ clearNewlines = true) {
76
78
  let node = tr.doc.nodeAt(pos)!
77
79
  let replSteps: Step[] = [], cur = pos + 1
78
80
  for (let i = 0; i < node.childCount; i++) {
@@ -85,7 +87,7 @@ export function clearIncompatible(tr: Transform, pos: number, parentType: NodeTy
85
87
  for (let j = 0; j < child.marks.length; j++) if (!parentType.allowsMarkType(child.marks[j].type))
86
88
  tr.step(new RemoveMarkStep(cur, end, child.marks[j]))
87
89
 
88
- if (child.isText && !parentType.spec.code) {
90
+ if (clearNewlines && child.isText && parentType.whitespace != "pre") {
89
91
  let m, newline = /\r?\n|\r/g, slice
90
92
  while (m = newline.exec(child.text!)) {
91
93
  if (!slice) slice = new Slice(Fragment.from(parentType.schema.text(" ", parentType.allowedMarks(child.marks))),
@@ -134,7 +134,8 @@ export class ReplaceAroundStep extends Step {
134
134
 
135
135
  map(mapping: Mappable) {
136
136
  let from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1)
137
- let gapFrom = mapping.map(this.gapFrom, -1), gapTo = mapping.map(this.gapTo, 1)
137
+ let gapFrom = this.from == this.gapFrom ? from.pos : mapping.map(this.gapFrom, -1)
138
+ let gapTo = this.to == this.gapTo ? to.pos : mapping.map(this.gapTo, 1)
138
139
  if ((from.deletedAcross && to.deletedAcross) || gapFrom < from.pos || gapTo > to.pos) return null
139
140
  return new ReplaceAroundStep(from.pos, to.pos, gapFrom, gapTo, this.slice, this.insert, this.structure)
140
141
  }
package/src/structure.ts CHANGED
@@ -2,6 +2,7 @@ import {Slice, Fragment, NodeRange, NodeType, Node, Mark, Attrs, ContentMatch} f
2
2
 
3
3
  import {Transform} from "./transform"
4
4
  import {ReplaceStep, ReplaceAroundStep} from "./replace_step"
5
+ import {clearIncompatible} from "./mark"
5
6
 
6
7
  function canCut(node: Node, start: number, end: number) {
7
8
  return (start == 0 || node.canReplace(start, node.childCount)) &&
@@ -111,22 +112,54 @@ export function wrap(tr: Transform, range: NodeRange, wrappers: readonly {type:
111
112
  tr.step(new ReplaceAroundStep(start, end, start, end, new Slice(content, 0, 0), wrappers.length, true))
112
113
  }
113
114
 
114
- export function setBlockType(tr: Transform, from: number, to: number, type: NodeType, attrs: Attrs | null) {
115
+ export function setBlockType(tr: Transform, from: number, to: number,
116
+ type: NodeType, attrs: Attrs | null | ((oldNode: Node) => Attrs)) {
115
117
  if (!type.isTextblock) throw new RangeError("Type given to setBlockType should be a textblock")
116
118
  let mapFrom = tr.steps.length
117
119
  tr.doc.nodesBetween(from, to, (node, pos) => {
118
- if (node.isTextblock && !node.hasMarkup(type, attrs) && canChangeType(tr.doc, tr.mapping.slice(mapFrom).map(pos), type)) {
120
+ let attrsHere = typeof attrs == "function" ? attrs(node) : attrs
121
+ if (node.isTextblock && !node.hasMarkup(type, attrsHere) &&
122
+ canChangeType(tr.doc, tr.mapping.slice(mapFrom).map(pos), type)) {
123
+ let convertNewlines = null
124
+ if (type.schema.linebreakReplacement) {
125
+ let pre = type.whitespace == "pre", supportLinebreak = !!type.contentMatch.matchType(type.schema.linebreakReplacement)
126
+ if (pre && !supportLinebreak) convertNewlines = false
127
+ else if (!pre && supportLinebreak) convertNewlines = true
128
+ }
119
129
  // Ensure all markup that isn't allowed in the new node type is cleared
120
- tr.clearIncompatible(tr.mapping.slice(mapFrom).map(pos, 1), type)
130
+ if (convertNewlines === false) replaceLinebreaks(tr, node, pos, mapFrom)
131
+ clearIncompatible(tr, tr.mapping.slice(mapFrom).map(pos, 1), type, undefined, convertNewlines === null)
121
132
  let mapping = tr.mapping.slice(mapFrom)
122
133
  let startM = mapping.map(pos, 1), endM = mapping.map(pos + node.nodeSize, 1)
123
134
  tr.step(new ReplaceAroundStep(startM, endM, startM + 1, endM - 1,
124
- new Slice(Fragment.from(type.create(attrs, null, node.marks)), 0, 0), 1, true))
135
+ new Slice(Fragment.from(type.create(attrsHere, null, node.marks)), 0, 0), 1, true))
136
+ if (convertNewlines === true) replaceNewlines(tr, node, pos, mapFrom)
125
137
  return false
126
138
  }
127
139
  })
128
140
  }
129
141
 
142
+ function replaceNewlines(tr: Transform, node: Node, pos: number, mapFrom: number) {
143
+ node.forEach((child, offset) => {
144
+ if (child.isText) {
145
+ let m, newline = /\r?\n|\r/g
146
+ while (m = newline.exec(child.text!)) {
147
+ let start = tr.mapping.slice(mapFrom).map(pos + 1 + offset + m.index)
148
+ tr.replaceWith(start, start + 1, node.type.schema.linebreakReplacement!.create())
149
+ }
150
+ }
151
+ })
152
+ }
153
+
154
+ function replaceLinebreaks(tr: Transform, node: Node, pos: number, mapFrom: number) {
155
+ node.forEach((child, offset) => {
156
+ if (child.type == child.type.schema.linebreakReplacement) {
157
+ let start = tr.mapping.slice(mapFrom).map(pos + 1 + offset)
158
+ tr.replaceWith(start, start + 1, node.type.schema.text("\n"))
159
+ }
160
+ })
161
+ }
162
+
130
163
  function canChangeType(doc: Node, pos: number, type: NodeType) {
131
164
  let $pos = doc.resolve(pos), index = $pos.index()
132
165
  return $pos.parent.canReplaceWith(index, index + 1, type)
package/src/transform.ts CHANGED
@@ -166,7 +166,7 @@ export class Transform {
166
166
 
167
167
  /// Set the type of all textblocks (partly) between `from` and `to` to
168
168
  /// the given node type with the given attributes.
169
- setBlockType(from: number, to = from, type: NodeType, attrs: Attrs | null = null): this {
169
+ setBlockType(from: number, to = from, type: NodeType, attrs: Attrs | null | ((oldNode: Node) => Attrs) = null): this {
170
170
  setBlockType(this, from, to, type, attrs)
171
171
  return this
172
172
  }