prosemirror-transform 1.4.1 → 1.5.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/src/map.js DELETED
@@ -1,264 +0,0 @@
1
- // Mappable:: interface
2
- // There are several things that positions can be mapped through.
3
- // Such objects conform to this interface.
4
- //
5
- // map:: (pos: number, assoc: ?number) → number
6
- // Map a position through this object. When given, `assoc` (should
7
- // be -1 or 1, defaults to 1) determines with which side the
8
- // position is associated, which determines in which direction to
9
- // move when a chunk of content is inserted at the mapped position.
10
- //
11
- // mapResult:: (pos: number, assoc: ?number) → MapResult
12
- // Map a position, and return an object containing additional
13
- // information about the mapping. The result's `deleted` field tells
14
- // you whether the position was deleted (completely enclosed in a
15
- // replaced range) during the mapping. When content on only one side
16
- // is deleted, the position itself is only considered deleted when
17
- // `assoc` points in the direction of the deleted content.
18
-
19
- // Recovery values encode a range index and an offset. They are
20
- // represented as numbers, because tons of them will be created when
21
- // mapping, for example, a large number of decorations. The number's
22
- // lower 16 bits provide the index, the remaining bits the offset.
23
- //
24
- // Note: We intentionally don't use bit shift operators to en- and
25
- // decode these, since those clip to 32 bits, which we might in rare
26
- // cases want to overflow. A 64-bit float can represent 48-bit
27
- // integers precisely.
28
-
29
- const lower16 = 0xffff
30
- const factor16 = Math.pow(2, 16)
31
-
32
- function makeRecover(index, offset) { return index + offset * factor16 }
33
- function recoverIndex(value) { return value & lower16 }
34
- function recoverOffset(value) { return (value - (value & lower16)) / factor16 }
35
-
36
- // ::- An object representing a mapped position with extra
37
- // information.
38
- export class MapResult {
39
- constructor(pos, deleted = false, recover = null) {
40
- // :: number The mapped version of the position.
41
- this.pos = pos
42
- // :: bool Tells you whether the position was deleted, that is,
43
- // whether the step removed its surroundings from the document.
44
- this.deleted = deleted
45
- this.recover = recover
46
- }
47
- }
48
-
49
- // :: class extends Mappable
50
- // A map describing the deletions and insertions made by a step, which
51
- // can be used to find the correspondence between positions in the
52
- // pre-step version of a document and the same position in the
53
- // post-step version.
54
- export class StepMap {
55
- // :: ([number])
56
- // Create a position map. The modifications to the document are
57
- // represented as an array of numbers, in which each group of three
58
- // represents a modified chunk as `[start, oldSize, newSize]`.
59
- constructor(ranges, inverted = false) {
60
- if (!ranges.length && StepMap.empty) return StepMap.empty
61
- this.ranges = ranges
62
- this.inverted = inverted
63
- }
64
-
65
- recover(value) {
66
- let diff = 0, index = recoverIndex(value)
67
- if (!this.inverted) for (let i = 0; i < index; i++)
68
- diff += this.ranges[i * 3 + 2] - this.ranges[i * 3 + 1]
69
- return this.ranges[index * 3] + diff + recoverOffset(value)
70
- }
71
-
72
- // : (number, ?number) → MapResult
73
- mapResult(pos, assoc = 1) { return this._map(pos, assoc, false) }
74
-
75
- // : (number, ?number) → number
76
- map(pos, assoc = 1) { return this._map(pos, assoc, true) }
77
-
78
- _map(pos, assoc, simple) {
79
- let diff = 0, oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2
80
- for (let i = 0; i < this.ranges.length; i += 3) {
81
- let start = this.ranges[i] - (this.inverted ? diff : 0)
82
- if (start > pos) break
83
- let oldSize = this.ranges[i + oldIndex], newSize = this.ranges[i + newIndex], end = start + oldSize
84
- if (pos <= end) {
85
- let side = !oldSize ? assoc : pos == start ? -1 : pos == end ? 1 : assoc
86
- let result = start + diff + (side < 0 ? 0 : newSize)
87
- if (simple) return result
88
- let recover = pos == (assoc < 0 ? start : end) ? null : makeRecover(i / 3, pos - start)
89
- return new MapResult(result, assoc < 0 ? pos != start : pos != end, recover)
90
- }
91
- diff += newSize - oldSize
92
- }
93
- return simple ? pos + diff : new MapResult(pos + diff)
94
- }
95
-
96
- touches(pos, recover) {
97
- let diff = 0, index = recoverIndex(recover)
98
- let oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2
99
- for (let i = 0; i < this.ranges.length; i += 3) {
100
- let start = this.ranges[i] - (this.inverted ? diff : 0)
101
- if (start > pos) break
102
- let oldSize = this.ranges[i + oldIndex], end = start + oldSize
103
- if (pos <= end && i == index * 3) return true
104
- diff += this.ranges[i + newIndex] - oldSize
105
- }
106
- return false
107
- }
108
-
109
- // :: ((oldStart: number, oldEnd: number, newStart: number, newEnd: number))
110
- // Calls the given function on each of the changed ranges included in
111
- // this map.
112
- forEach(f) {
113
- let oldIndex = this.inverted ? 2 : 1, newIndex = this.inverted ? 1 : 2
114
- for (let i = 0, diff = 0; i < this.ranges.length; i += 3) {
115
- let start = this.ranges[i], oldStart = start - (this.inverted ? diff : 0), newStart = start + (this.inverted ? 0 : diff)
116
- let oldSize = this.ranges[i + oldIndex], newSize = this.ranges[i + newIndex]
117
- f(oldStart, oldStart + oldSize, newStart, newStart + newSize)
118
- diff += newSize - oldSize
119
- }
120
- }
121
-
122
- // :: () → StepMap
123
- // Create an inverted version of this map. The result can be used to
124
- // map positions in the post-step document to the pre-step document.
125
- invert() {
126
- return new StepMap(this.ranges, !this.inverted)
127
- }
128
-
129
- toString() {
130
- return (this.inverted ? "-" : "") + JSON.stringify(this.ranges)
131
- }
132
-
133
- // :: (n: number) → StepMap
134
- // Create a map that moves all positions by offset `n` (which may be
135
- // negative). This can be useful when applying steps meant for a
136
- // sub-document to a larger document, or vice-versa.
137
- static offset(n) {
138
- return n == 0 ? StepMap.empty : new StepMap(n < 0 ? [0, -n, 0] : [0, 0, n])
139
- }
140
- }
141
-
142
- // :: StepMap
143
- // A StepMap that contains no changed ranges.
144
- StepMap.empty = new StepMap([])
145
-
146
- // :: class extends Mappable
147
- // A mapping represents a pipeline of zero or more [step
148
- // maps](#transform.StepMap). It has special provisions for losslessly
149
- // handling mapping positions through a series of steps in which some
150
- // steps are inverted versions of earlier steps. (This comes up when
151
- // ‘[rebasing](/docs/guide/#transform.rebasing)’ steps for
152
- // collaboration or history management.)
153
- export class Mapping {
154
- // :: (?[StepMap])
155
- // Create a new mapping with the given position maps.
156
- constructor(maps, mirror, from, to) {
157
- // :: [StepMap]
158
- // The step maps in this mapping.
159
- this.maps = maps || []
160
- // :: number
161
- // The starting position in the `maps` array, used when `map` or
162
- // `mapResult` is called.
163
- this.from = from || 0
164
- // :: number
165
- // The end position in the `maps` array.
166
- this.to = to == null ? this.maps.length : to
167
- this.mirror = mirror
168
- }
169
-
170
- // :: (?number, ?number) → Mapping
171
- // Create a mapping that maps only through a part of this one.
172
- slice(from = 0, to = this.maps.length) {
173
- return new Mapping(this.maps, this.mirror, from, to)
174
- }
175
-
176
- copy() {
177
- return new Mapping(this.maps.slice(), this.mirror && this.mirror.slice(), this.from, this.to)
178
- }
179
-
180
- // :: (StepMap, ?number)
181
- // Add a step map to the end of this mapping. If `mirrors` is
182
- // given, it should be the index of the step map that is the mirror
183
- // image of this one.
184
- appendMap(map, mirrors) {
185
- this.to = this.maps.push(map)
186
- if (mirrors != null) this.setMirror(this.maps.length - 1, mirrors)
187
- }
188
-
189
- // :: (Mapping)
190
- // Add all the step maps in a given mapping to this one (preserving
191
- // mirroring information).
192
- appendMapping(mapping) {
193
- for (let i = 0, startSize = this.maps.length; i < mapping.maps.length; i++) {
194
- let mirr = mapping.getMirror(i)
195
- this.appendMap(mapping.maps[i], mirr != null && mirr < i ? startSize + mirr : null)
196
- }
197
- }
198
-
199
- // :: (number) → ?number
200
- // Finds the offset of the step map that mirrors the map at the
201
- // given offset, in this mapping (as per the second argument to
202
- // `appendMap`).
203
- getMirror(n) {
204
- if (this.mirror) for (let i = 0; i < this.mirror.length; i++)
205
- if (this.mirror[i] == n) return this.mirror[i + (i % 2 ? -1 : 1)]
206
- }
207
-
208
- setMirror(n, m) {
209
- if (!this.mirror) this.mirror = []
210
- this.mirror.push(n, m)
211
- }
212
-
213
- // :: (Mapping)
214
- // Append the inverse of the given mapping to this one.
215
- appendMappingInverted(mapping) {
216
- for (let i = mapping.maps.length - 1, totalSize = this.maps.length + mapping.maps.length; i >= 0; i--) {
217
- let mirr = mapping.getMirror(i)
218
- this.appendMap(mapping.maps[i].invert(), mirr != null && mirr > i ? totalSize - mirr - 1 : null)
219
- }
220
- }
221
-
222
- // :: () → Mapping
223
- // Create an inverted version of this mapping.
224
- invert() {
225
- let inverse = new Mapping
226
- inverse.appendMappingInverted(this)
227
- return inverse
228
- }
229
-
230
- // : (number, ?number) → number
231
- // Map a position through this mapping.
232
- map(pos, assoc = 1) {
233
- if (this.mirror) return this._map(pos, assoc, true)
234
- for (let i = this.from; i < this.to; i++)
235
- pos = this.maps[i].map(pos, assoc)
236
- return pos
237
- }
238
-
239
- // : (number, ?number) → MapResult
240
- // Map a position through this mapping, returning a mapping
241
- // result.
242
- mapResult(pos, assoc = 1) { return this._map(pos, assoc, false) }
243
-
244
- _map(pos, assoc, simple) {
245
- let deleted = false
246
-
247
- for (let i = this.from; i < this.to; i++) {
248
- let map = this.maps[i], result = map.mapResult(pos, assoc)
249
- if (result.recover != null) {
250
- let corr = this.getMirror(i)
251
- if (corr != null && corr > i && corr < this.to) {
252
- i = corr
253
- pos = this.maps[corr].recover(result.recover)
254
- continue
255
- }
256
- }
257
-
258
- if (result.deleted) deleted = true
259
- pos = result.pos
260
- }
261
-
262
- return simple ? pos : new MapResult(pos, deleted)
263
- }
264
- }
package/src/step.js DELETED
@@ -1,110 +0,0 @@
1
- import {ReplaceError} from "prosemirror-model"
2
-
3
- import {StepMap} from "./map"
4
-
5
- function mustOverride() { throw new Error("Override me") }
6
-
7
- const stepsByID = Object.create(null)
8
-
9
- // ::- A step object represents an atomic change. It generally applies
10
- // only to the document it was created for, since the positions
11
- // stored in it will only make sense for that document.
12
- //
13
- // New steps are defined by creating classes that extend `Step`,
14
- // overriding the `apply`, `invert`, `map`, `getMap` and `fromJSON`
15
- // methods, and registering your class with a unique
16
- // JSON-serialization identifier using
17
- // [`Step.jsonID`](#transform.Step^jsonID).
18
- export class Step {
19
- // :: (doc: Node) → StepResult
20
- // Applies this step to the given document, returning a result
21
- // object that either indicates failure, if the step can not be
22
- // applied to this document, or indicates success by containing a
23
- // transformed document.
24
- apply(_doc) { return mustOverride() }
25
-
26
- // :: () → StepMap
27
- // Get the step map that represents the changes made by this step,
28
- // and which can be used to transform between positions in the old
29
- // and the new document.
30
- getMap() { return StepMap.empty }
31
-
32
- // :: (doc: Node) → Step
33
- // Create an inverted version of this step. Needs the document as it
34
- // was before the step as argument.
35
- invert(_doc) { return mustOverride() }
36
-
37
- // :: (mapping: Mappable) → ?Step
38
- // Map this step through a mappable thing, returning either a
39
- // version of that step with its positions adjusted, or `null` if
40
- // the step was entirely deleted by the mapping.
41
- map(_mapping) { return mustOverride() }
42
-
43
- // :: (other: Step) → ?Step
44
- // Try to merge this step with another one, to be applied directly
45
- // after it. Returns the merged step when possible, null if the
46
- // steps can't be merged.
47
- merge(_other) { return null }
48
-
49
- // :: () → Object
50
- // Create a JSON-serializeable representation of this step. When
51
- // defining this for a custom subclass, make sure the result object
52
- // includes the step type's [JSON id](#transform.Step^jsonID) under
53
- // the `stepType` property.
54
- toJSON() { return mustOverride() }
55
-
56
- // :: (Schema, Object) → Step
57
- // Deserialize a step from its JSON representation. Will call
58
- // through to the step class' own implementation of this method.
59
- static fromJSON(schema, json) {
60
- if (!json || !json.stepType) throw new RangeError("Invalid input for Step.fromJSON")
61
- let type = stepsByID[json.stepType]
62
- if (!type) throw new RangeError(`No step type ${json.stepType} defined`)
63
- return type.fromJSON(schema, json)
64
- }
65
-
66
- // :: (string, constructor<Step>)
67
- // To be able to serialize steps to JSON, each step needs a string
68
- // ID to attach to its JSON representation. Use this method to
69
- // register an ID for your step classes. Try to pick something
70
- // that's unlikely to clash with steps from other modules.
71
- static jsonID(id, stepClass) {
72
- if (id in stepsByID) throw new RangeError("Duplicate use of step JSON ID " + id)
73
- stepsByID[id] = stepClass
74
- stepClass.prototype.jsonID = id
75
- return stepClass
76
- }
77
- }
78
-
79
- // ::- The result of [applying](#transform.Step.apply) a step. Contains either a
80
- // new document or a failure value.
81
- export class StepResult {
82
- // : (?Node, ?string)
83
- constructor(doc, failed) {
84
- // :: ?Node The transformed document.
85
- this.doc = doc
86
- // :: ?string Text providing information about a failed step.
87
- this.failed = failed
88
- }
89
-
90
- // :: (Node) → StepResult
91
- // Create a successful step result.
92
- static ok(doc) { return new StepResult(doc, null) }
93
-
94
- // :: (string) → StepResult
95
- // Create a failed step result.
96
- static fail(message) { return new StepResult(null, message) }
97
-
98
- // :: (Node, number, number, Slice) → StepResult
99
- // Call [`Node.replace`](#model.Node.replace) with the given
100
- // arguments. Create a successful result if it succeeds, and a
101
- // failed one if it throws a `ReplaceError`.
102
- static fromReplace(doc, from, to, slice) {
103
- try {
104
- return StepResult.ok(doc.replace(from, to, slice))
105
- } catch (e) {
106
- if (e instanceof ReplaceError) return StepResult.fail(e.message)
107
- throw e
108
- }
109
- }
110
- }
package/src/transform.js DELETED
@@ -1,71 +0,0 @@
1
- import {Mapping} from "./map"
2
-
3
- export function TransformError(message) {
4
- let err = Error.call(this, message)
5
- err.__proto__ = TransformError.prototype
6
- return err
7
- }
8
-
9
- TransformError.prototype = Object.create(Error.prototype)
10
- TransformError.prototype.constructor = TransformError
11
- TransformError.prototype.name = "TransformError"
12
-
13
- // ::- Abstraction to build up and track an array of
14
- // [steps](#transform.Step) representing a document transformation.
15
- //
16
- // Most transforming methods return the `Transform` object itself, so
17
- // that they can be chained.
18
- export class Transform {
19
- // :: (Node)
20
- // Create a transform that starts with the given document.
21
- constructor(doc) {
22
- // :: Node
23
- // The current document (the result of applying the steps in the
24
- // transform).
25
- this.doc = doc
26
- // :: [Step]
27
- // The steps in this transform.
28
- this.steps = []
29
- // :: [Node]
30
- // The documents before each of the steps.
31
- this.docs = []
32
- // :: Mapping
33
- // A mapping with the maps for each of the steps in this transform.
34
- this.mapping = new Mapping
35
- }
36
-
37
- // :: Node The starting document.
38
- get before() { return this.docs.length ? this.docs[0] : this.doc }
39
-
40
- // :: (step: Step) → this
41
- // Apply a new step in this transform, saving the result. Throws an
42
- // error when the step fails.
43
- step(object) {
44
- let result = this.maybeStep(object)
45
- if (result.failed) throw new TransformError(result.failed)
46
- return this
47
- }
48
-
49
- // :: (Step) → StepResult
50
- // Try to apply a step in this transformation, ignoring it if it
51
- // fails. Returns the step result.
52
- maybeStep(step) {
53
- let result = step.apply(this.doc)
54
- if (!result.failed) this.addStep(step, result.doc)
55
- return result
56
- }
57
-
58
- // :: bool
59
- // True when the document has been changed (when there are any
60
- // steps).
61
- get docChanged() {
62
- return this.steps.length > 0
63
- }
64
-
65
- addStep(step, doc) {
66
- this.docs.push(this.doc)
67
- this.steps.push(step)
68
- this.mapping.appendMap(step.getMap())
69
- this.doc = doc
70
- }
71
- }