Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

prosemirror-transform

Package Overview
Dependencies
Maintainers
1
Versions
73
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

prosemirror-transform - npm Package Compare versions

Comparing version 0.22.2 to 0.23.0

dist/index.js.map

15

CONTRIBUTING.md

@@ -16,3 +16,3 @@ # How to contribute

[GitHub issue tracker](http://github.com/prosemirror/prosemirror/issues).
Before reporting a bug, read these pointers.
Before reporting a bug, please read these pointers.

@@ -26,6 +26,7 @@ - The issue tracker is for *bugs*, not requests for help. Questions

- Mention very precisely what went wrong. "X is broken" is not a good bug
report. What did you expect to happen? What happened instead? Describe the
exact steps a maintainer has to take to make the problem occur. We can not
fix something that we can not observe.
- Mention very precisely what went wrong. "X is broken" is not a good
bug report. What did you expect to happen? What happened instead?
Describe the exact steps a maintainer has to take to make the
problem occur. A screencast can be useful, but is no substitute for
a textual description.

@@ -50,4 +51,4 @@ - A great way to make it easy to reproduce your problem, if it can not

- Follow the code style of the rest of the project (see below). Run
`npm run lint` (in the main repository checkout) that the linter is
happy.
`npm run lint` (in the main repository checkout) to make sure that
the linter is happy.

@@ -54,0 +55,0 @@ - If your changes are easy to test or likely to regress, add tests in

{
"name": "prosemirror-transform",
"version": "0.22.2",
"version": "0.23.0",
"description": "ProseMirror document transformations",

@@ -19,16 +19,17 @@ "main": "dist/index.js",

"dependencies": {
"prosemirror-model": "^0.22.0"
"prosemirror-model": "^0.23.0"
},
"devDependencies": {
"buble": "^0.15.1",
"mocha": "^3.0.2",
"ist": "^1.0.0",
"rimraf": "^2.5.4",
"prosemirror-test-builder": "^0.22.0"
"prosemirror-test-builder": "^0.23.0",
"rollup": "^0.49.0",
"rollup-plugin-buble": "^0.15.0"
},
"scripts": {
"test": "mocha test/test-*.js",
"build": "rimraf dist && buble -i src -o dist",
"build": "rollup -c",
"watch": "rollup -c -w",
"prepare": "npm run build"
}
}

@@ -9,4 +9,4 @@ # prosemirror-transform

This [module](http://prosemirror.net/ref.html#transform) implements
document [transforms](http://prosemirror.net/guide/transform.html),
This [module](http://prosemirror.net/docs/ref/#transform) implements
document [transforms](http://prosemirror\.net/docs/guide/#transform),
which are used by the editor to treat changes as first-class values,

@@ -16,9 +16,5 @@ which can be saved, shared, and reasoned about.

The [project page](http://prosemirror.net) has more information, a
number of [demos](http://prosemirror.net/#demos) and the
[documentation](http://prosemirror.net/docs.html).
number of [examples](http://prosemirror.net/examples/) and the
[documentation](http://prosemirror.net/docs/).
**NOTE:** This project is in *BETA* stage. It isn't thoroughly tested,
and the API might still change across `0.x` releases. You are welcome
to use it, but don't expect it to be very stable yet.
This code is released under an

@@ -25,0 +21,0 @@ [MIT license](https://github.com/prosemirror/prosemirror/tree/master/LICENSE).

@@ -1,9 +0,8 @@

;({Transform: exports.Transform, TransformError: exports.TransformError} = require("./transform"))
;({Step: exports.Step, StepResult: exports.StepResult} = require("./step"))
;({joinPoint: exports.joinPoint, canJoin: exports.canJoin, canSplit: exports.canSplit,
insertPoint: exports.insertPoint, liftTarget: exports.liftTarget, findWrapping: exports.findWrapping} = require("./structure"))
;({StepMap: exports.StepMap, MapResult: exports.MapResult, Mapping: exports.Mapping} = require("./map"))
;({AddMarkStep: exports.AddMarkStep, RemoveMarkStep: exports.RemoveMarkStep} = require("./mark_step"))
;({ReplaceStep: exports.ReplaceStep, ReplaceAroundStep: exports.ReplaceAroundStep} = require("./replace_step"))
require("./mark")
;({replaceStep: exports.replaceStep} = require("./replace"))
export {Transform, TransformError} from "./transform"
export {Step, StepResult} from "./step"
export {joinPoint, canJoin, canSplit, insertPoint, liftTarget, findWrapping} from "./structure"
export {StepMap, MapResult, Mapping} from "./map"
export {AddMarkStep, RemoveMarkStep} from "./mark_step"
export {ReplaceStep, ReplaceAroundStep} from "./replace_step"
import "./mark"
export {replaceStep} from "./replace"
// Mappable:: interface
// There are several things that positions can be mapped through.
// We'll denote those as 'mappable'.
// Such objects conform to this interface.
//

@@ -9,4 +9,3 @@ // map:: (pos: number, assoc: ?number) → number

// position is associated, which determines in which direction to
// move when a chunk of content is inserted at the mapped position,
// and when to consider the position to be deleted.
// move when a chunk of content is inserted at the mapped position.
//

@@ -17,7 +16,9 @@ // mapResult:: (pos: number, assoc: ?number) → MapResult

// you whether the position was deleted (completely enclosed in a
// replaced range) during the mapping.
// replaced range) during the mapping. When content on only one side
// is deleted, the position itself is only considered deleted when
// `assoc` points in the direction of the deleted content.
// Recovery values encode a range index and an offset. They are
// represented as numbers, because tons of them will be created when
// mapping, for example, a large number of marked ranges. The number's
// mapping, for example, a large number of decorations. The number's
// lower 16 bits provide the index, the remaining bits the offset.

@@ -39,3 +40,3 @@ //

// information.
class MapResult {
export class MapResult {
constructor(pos, deleted = false, recover = null) {

@@ -50,9 +51,9 @@ // :: number The mapped version of the position.

}
exports.MapResult = MapResult
// ::- A map describing the deletions and insertions made by a step,
// which can be used to find the correspondence between positions in
// the pre-step version of a document and the same position in the
// post-step version. This class implements [`Mappable`](#transform.Mappable).
class StepMap {
// :: class extends Mappable
// A map describing the deletions and insertions made by a step, which
// can be used to find the correspondence between positions in the
// pre-step version of a document and the same position in the
// post-step version.
export class StepMap {
// :: ([number])

@@ -74,14 +75,7 @@ // Create a position map. The modifications to the document are

// :: (number, ?number) → MapResult
// Map the given position through this map. The `assoc` parameter can
// be used to control what happens when the transform inserted
// content at (or around) this position—if `assoc` is negative, the a
// position before the inserted content will be returned, if it is
// positive, a position after the insertion is returned.
mapResult(pos, assoc) { return this._map(pos, assoc, false) }
// : (number, ?number) → MapResult
mapResult(pos, assoc = 1) { return this._map(pos, assoc, false) }
// :: (number, ?number) → number
// Map the given position through this map, returning only the
// mapped position.
map(pos, assoc) { return this._map(pos, assoc, true) }
// : (number, ?number) → number
map(pos, assoc = 1) { return this._map(pos, assoc, true) }

@@ -120,3 +114,3 @@ _map(pos, assoc, simple) {

// :: ((oldStart: number, oldEnd: number, newStart: number, newEnd: number))
// Calls the given function on each of the changed ranges denoted by
// Calls the given function on each of the changed ranges included in
// this map.

@@ -143,14 +137,22 @@ forEach(f) {

}
// :: (n: number) → StepMap
// Create a map that moves all positions by offset `n` (which may be
// negative). This can be useful when applying steps meant for a
// sub-document to a larger document, or vice-versa.
static offset(n) {
return n == 0 ? StepMap.empty : new StepMap(n < 0 ? [0, -n, 0] : [0, 0, n])
}
}
exports.StepMap = StepMap
StepMap.empty = new StepMap([])
// ::- A mapping represents a pipeline of zero or more [step
// :: class extends Mappable
// A mapping represents a pipeline of zero or more [step
// maps](#transform.StepMap). It has special provisions for losslessly
// handling mapping positions through a series of steps in which some
// steps are inverted versions of earlier steps. (This comes up when
// ‘rebasing’ steps for collaboration or history management.) This
// class implements [`Mappable`](#transform.Mappable).
class Mapping {
// ‘[rebasing](/docs/guide/#transform.rebasing)’ steps for
// collaboration or history management.)
export class Mapping {
// :: (?[StepMap])

@@ -167,3 +169,3 @@ // Create a new mapping with the given position maps.

// :: number
// The end positions in the `maps` array.
// The end position in the `maps` array.
this.to = to == null ? this.maps.length : to

@@ -229,5 +231,5 @@ this.mirror = mirror

// :: (number, ?number) → number
// : (number, ?number) → number
// Map a position through this mapping.
map(pos, assoc) {
map(pos, assoc = 1) {
if (this.mirror) return this._map(pos, assoc, true)

@@ -239,6 +241,6 @@ for (let i = this.from; i < this.to; i++)

// :: (number, ?number) → MapResult
// : (number, ?number) → MapResult
// Map a position through this mapping, returning a mapping
// result.
mapResult(pos, assoc) { return this._map(pos, assoc, false) }
mapResult(pos, assoc = 1) { return this._map(pos, assoc, false) }

@@ -276,2 +278,1 @@ _map(pos, assoc, simple) {

}
exports.Mapping = Mapping

@@ -1,3 +0,3 @@

const {Fragment, Slice} = require("prosemirror-model")
const {Step, StepResult} = require("./step")
import {Fragment, Slice} from "prosemirror-model"
import {Step, StepResult} from "./step"

@@ -16,3 +16,3 @@ function mapFragment(fragment, f, parent) {

// ::- Add a mark to all inline content between two positions.
class AddMarkStep extends Step {
export class AddMarkStep extends Step {
// :: (number, number, Mark)

@@ -29,4 +29,4 @@ constructor(from, to, mark) {

let parent = $from.node($from.sharedDepth(this.to))
let slice = new Slice(mapFragment(oldSlice.content, (node, parent, index) => {
if (!parent.contentMatchAt(index).allowsMark(this.mark.type)) return node
let slice = new Slice(mapFragment(oldSlice.content, (node, parent) => {
if (!parent.type.allowsMarkType(this.mark.type)) return node
return node.mark(this.mark.addToSet(node.marks))

@@ -55,4 +55,5 @@ }, parent), oldSlice.openStart, oldSlice.openEnd)

offset(n) {
return new AddMarkStep(this.from + n, this.to + n, this.mark)
toJSON() {
return {stepType: "addMark", mark: this.mark.toJSON(),
from: this.from, to: this.to}
}

@@ -64,3 +65,2 @@

}
exports.AddMarkStep = AddMarkStep

@@ -70,3 +70,3 @@ Step.jsonID("addMark", AddMarkStep)

// ::- Remove a mark from all inline content between two positions.
class RemoveMarkStep extends Step {
export class RemoveMarkStep extends Step {
// :: (number, number, Mark)

@@ -106,4 +106,5 @@ constructor(from, to, mark) {

offset(n) {
return new RemoveMarkStep(this.from + n, this.to + n, this.mark)
toJSON() {
return {stepType: "removeMark", mark: this.mark.toJSON(),
from: this.from, to: this.to}
}

@@ -115,4 +116,3 @@

}
exports.RemoveMarkStep = RemoveMarkStep
Step.jsonID("removeMark", RemoveMarkStep)

@@ -1,6 +0,6 @@

const {MarkType, Slice, Fragment} = require("prosemirror-model")
import {MarkType, Slice, Fragment} from "prosemirror-model"
const {Transform} = require("./transform")
const {AddMarkStep, RemoveMarkStep} = require("./mark_step")
const {ReplaceStep} = require("./replace_step")
import {Transform} from "./transform"
import {AddMarkStep, RemoveMarkStep} from "./mark_step"
import {ReplaceStep} from "./replace_step"

@@ -11,6 +11,6 @@ // :: (number, number, Mark) → this

let removed = [], added = [], removing = null, adding = null
this.doc.nodesBetween(from, to, (node, pos, parent, index) => {
this.doc.nodesBetween(from, to, (node, pos, parent) => {
if (!node.isInline) return
let marks = node.marks
if (!mark.isInSet(marks) && parent.contentMatchAt(index).allowsMark(mark.type)) {
if (!mark.isInSet(marks) && parent.type.allowsMarkType(mark.type)) {
let start = Math.max(pos, from), end = Math.min(pos + node.nodeSize, to)

@@ -41,4 +41,6 @@ let newSet = mark.addToSet(marks)

// :: (number, number, ?union<Mark, MarkType>) → this
// Remove the given mark, or all marks of the given type, from inline
// nodes between `from` and `to`.
// Remove marks from inline nodes between `from` and `to`. When `mark`
// is a single mark, remove precisely that mark. When it is a mark type,
// remove all marks of that type. When it is null, remove all marks of
// any type.
Transform.prototype.removeMark = function(from, to, mark = null) {

@@ -79,20 +81,8 @@ let matched = [], step = 0

// :: (number, number) → this
// Remove all marks and non-text inline nodes from the given range.
Transform.prototype.clearMarkup = function(from, to) {
let delSteps = [] // Must be accumulated and applied in inverse order
this.doc.nodesBetween(from, to, (node, pos) => {
if (!node.isInline) return
if (!node.type.isText) {
delSteps.push(new ReplaceStep(pos, pos + node.nodeSize, Slice.empty))
return
}
for (let i = 0; i < node.marks.length; i++)
this.step(new RemoveMarkStep(Math.max(pos, from), Math.min(pos + node.nodeSize, to), node.marks[i]))
})
for (let i = delSteps.length - 1; i >= 0; i--) this.step(delSteps[i])
return this
}
Transform.prototype.clearNonMatching = function(pos, match) {
// :: (number, NodeType, ?ContentMatch) → this
// Removes all marks and nodes from the content of the node at `pos`
// that don't match the given new parent node type. Accepts an
// optional starting [content match](#model.ContentMatch) as third
// argument.
Transform.prototype.clearIncompatible = function(pos, parentType, match = parentType.contentMatch) {
let node = this.doc.nodeAt(pos)

@@ -107,3 +97,3 @@ let delSteps = [], cur = pos + 1

match = allowed
for (let j = 0; j < child.marks.length; j++) if (!match.allowsMark(child.marks[j]))
for (let j = 0; j < child.marks.length; j++) if (!parentType.allowsMarkType(child.marks[j].type))
this.step(new RemoveMarkStep(cur, end, child.marks[j]))

@@ -113,3 +103,3 @@ }

}
if (!match.validEnd()) {
if (!match.validEnd) {
let fill = match.fillBefore(Fragment.empty, true)

@@ -116,0 +106,0 @@ this.replace(cur, cur, new Slice(fill, 0, 0))

@@ -1,3 +0,4 @@

This module defines a way to transform documents. You can read more
about transformations in [this guide](/docs/guides/transform/).
This module defines a way of modifying documents that allows changes
to be recorded, replayed, and reordered. You can read more about
transformations in [the guide](/docs/guide/#transform).

@@ -26,4 +27,5 @@ ### Steps

Mapping positions from one document to another by running through the
[replacements](#transform.StepMap) produced by steps is a fundamental
operation in ProseMirror.
[step maps](#transform.StepMap) produced by steps is an important
operation in ProseMirror. It is used, for example, for updating the
selection when the document changes.

@@ -35,8 +37,8 @@ @Mappable

### Transform Helpers
### Document transforms
Because you often need to collect a number of steps together to effect
a composite change, ProseMirror provides an abstraction to make this
easy. A value of this class is also the payload in the
[transform action](#state.TransformAction).
easy. [State transactions](#state.Transaction) are a subclass of
transforms.

@@ -43,0 +45,0 @@ @Transform

@@ -1,8 +0,8 @@

const {Slice} = require("prosemirror-model")
import {Slice} from "prosemirror-model"
const {Step, StepResult} = require("./step")
const {StepMap} = require("./map")
import {Step, StepResult} from "./step"
import {StepMap} from "./map"
// ::- Replace a part of the document with a slice of new content.
class ReplaceStep extends Step {
export class ReplaceStep extends Step {
// :: (number, number, Slice, ?bool)

@@ -67,6 +67,2 @@ // The given `slice` should fit the 'gap' between `from` and

offset(n) {
return new ReplaceStep(this.from + n, this.to + n, this.slice, this.structure)
}
static fromJSON(schema, json) {

@@ -76,3 +72,2 @@ return new ReplaceStep(json.from, json.to, Slice.fromJSON(schema, json.slice), !!json.structure)

}
exports.ReplaceStep = ReplaceStep

@@ -84,8 +79,8 @@ Step.jsonID("replace", ReplaceStep)

// slice.
class ReplaceAroundStep extends Step {
export class ReplaceAroundStep extends Step {
// :: (number, number, number, number, Slice, number, ?bool)
// Create a replace-wrap step with the given range and gap. `insert`
// should be the point in the slice into which the gap should be
// moved. `structure` has the same meaning as it has in the
// [`ReplaceStep`](#transform.ReplaceStep) class.
// Create a replace-around step with the given range and gap.
// `insert` should be the point in the slice into which the content
// of the gap should be moved. `structure` has the same meaning as
// it has in the [`ReplaceStep`](#transform.ReplaceStep) class.
constructor(from, to, gapFrom, gapTo, slice, insert, structure) {

@@ -135,14 +130,10 @@ super()

static toJSON() {
toJSON() {
let json = {stepType: "replaceAround", from: this.from, to: this.to,
gapFrom: this.gapFrom, gapTo: this.gapTo, slice: this.slice.toJSON()}
gapFrom: this.gapFrom, gapTo: this.gapTo, insert: this.insert}
if (this.slice.size) json.slice = this.slice.toJSON()
if (this.structure) json.structure = true
return true
return json
}
offset(n) {
return new ReplaceAroundStep(this.from + n, this.to + n, this.gapFrom + n, this.gapTo + n,
this.slice, this.insert, this.structure)
}
static fromJSON(schema, json) {

@@ -153,3 +144,2 @@ return new ReplaceAroundStep(json.from, json.to, json.gapFrom, json.gapTo,

}
exports.ReplaceAroundStep = ReplaceAroundStep

@@ -156,0 +146,0 @@ Step.jsonID("replaceAround", ReplaceAroundStep)

@@ -1,146 +0,13 @@

const {Fragment, Slice} = require("prosemirror-model")
import {Fragment, Slice, Mark} from "prosemirror-model"
const {ReplaceStep, ReplaceAroundStep} = require("./replace_step")
const {Transform} = require("./transform")
const {insertPoint} = require("./structure")
import {ReplaceStep, ReplaceAroundStep} from "./replace_step"
import {Transform} from "./transform"
import {insertPoint} from "./structure"
// :: (number, number, Slice) → this
// Replace a range of the document with a given slice, using `from`,
// `to`, and the slice's [`openStart`](#model.Slice.openStart) property
// as hints, rather than fixed start and end points. This method may
// grow the replaced area or close open nodes in the slice in order to
// get a fit that is more in line with WYSIWYG expectations, by
// dropping fully covered parent nodes of the replaced region when
// they are marked [non-defining](#model.NodeSpec.defining), or
// including an open parent node from the slice that _is_ marked as
// [defining](#model.NodeSpec.defining).
//
// This is the method, for example, to handle paste. The similar
// [`replace`](#transform.Transform.replace) method is a more
// primitive tool which will _not_ move the start and end of its given
// range, and is useful in situations where you need more precise
// control over what happens.
Transform.prototype.replaceRange = function(from, to, slice) {
if (!slice.size) return this.deleteRange(from, to)
let $from = this.doc.resolve(from), $to = this.doc.resolve(to)
if (fitsTrivially($from, $to, slice))
return this.step(new ReplaceStep(from, to, slice))
let canExpand = coveredDepths($from, this.doc.resolve(to)), preferredExpand = 0
if (canExpand[canExpand.length - 1] == 0) canExpand.pop()
canExpand.unshift($from.depth + 1)
for (let d = $from.depth; d > 0; d--) {
if ($from.node(d).type.spec.defining) break
let found = canExpand.indexOf(d, 1)
if (found > -1) preferredExpand = found
}
let leftNodes = [], preferredDepth = slice.openStart
for (let content = slice.content, i = 0;; i++) {
let node = content.firstChild
leftNodes.push(node)
if (i == slice.openStart) break
content = node.content
}
// Back up if the node directly above openStart, or the node above
// that separated only by a non-defining textblock node, is defining.
if (preferredDepth > 0 && leftNodes[preferredDepth - 1].type.spec.defining)
preferredDepth -= 1
else if (preferredDepth >= 2 && leftNodes[preferredDepth - 1].isTextblock && leftNodes[preferredDepth - 2].type.spec.defining)
preferredDepth -= 2
for (let j = slice.openStart; j >= 0; j--) {
let openDepth = (j + preferredDepth + 1) % (slice.openStart + 1)
let insert = leftNodes[openDepth]
if (!insert) continue
for (let i = 0; i < canExpand.length; i++) {
// Loop over possible expansion levels, starting with the
// preferred one
let expandDepth = canExpand[(i + preferredExpand) % canExpand.length]
let parent = $from.node(expandDepth - 1), index = $from.index(expandDepth - 1)
if (parent.canReplaceWith(index, index, insert.type, insert.attrs, insert.marks))
return this.replace($from.before(expandDepth), expandDepth > $from.depth ? to : $to.after(expandDepth),
new Slice(closeFragment(slice.content, 0, slice.openStart, openDepth),
openDepth, slice.openEnd))
}
}
return this.replace(from, to, slice)
}
function closeFragment(fragment, depth, oldOpen, newOpen, parent) {
if (depth < oldOpen) {
let first = fragment.firstChild
fragment = fragment.replaceChild(0, first.copy(closeFragment(first.content, depth + 1, oldOpen, newOpen, first)))
}
if (depth > newOpen)
fragment = parent.contentMatchAt(0).fillBefore(fragment).append(fragment)
return fragment
}
// :: (number, number, Node) → this
// Replace the given range with a node, but use `from` and `to` as
// hints, rather than precise positions. When from and to are the same
// and are at the start or end of a parent node in which the given
// node doesn't fit, this method may _move_ them out towards a parent
// that does allow the given node to be placed. When the given range
// completely covers a parent node, this method may completely replace
// that parent node.
Transform.prototype.replaceRangeWith = function(from, to, node) {
if (!node.isInline && from == to && this.doc.resolve(from).parent.content.size) {
let point = insertPoint(this.doc, from, node.type, node.attrs)
if (point != null) from = to = point
}
return this.replaceRange(from, to, new Slice(Fragment.from(node), 0, 0))
}
// :: (number, number) → this
// Delete the given range, expanding it to cover fully covered
// parent nodes until a valid replace is found.
Transform.prototype.deleteRange = function(from, to) {
let $from = this.doc.resolve(from), $to = this.doc.resolve(to)
let covered = coveredDepths($from, $to)
for (let i = 0; i < covered.length; i++) {
let depth = covered[i], last = i == covered.length - 1
if ((last && depth == 0) || $from.node(depth).contentMatchAt(0).validEnd()) {
from = $from.start(depth)
to = $to.end(depth)
break
}
if (depth > 0 && (last || $from.node(depth - 1).canReplace($from.index(depth - 1), $to.indexAfter(depth - 1)))) {
from = $from.before(depth)
to = $to.after(depth)
break
}
}
return this.delete(from, to)
}
// : (ResolvedPos, ResolvedPos) → [number]
// Returns an array of all depths for which $from - $to spans the
// whole content of the nodes at that depth.
function coveredDepths($from, $to) {
let result = [], minDepth = Math.min($from.depth, $to.depth)
for (let d = minDepth; d >= 0; d--) {
let start = $from.start(d)
if (start < $from.pos - ($from.depth - d) ||
$to.end(d) > $to.pos + ($to.depth - d) ||
$from.node(d).type.spec.isolating ||
$to.node(d).type.spec.isolating) break
if (start == $to.start(d)) result.push(d)
}
return result
}
// :: (number, number) → this
// Delete the content between the given positions.
Transform.prototype.delete = function(from, to) {
return this.replace(from, to, Slice.empty)
}
// :: (Node, number, ?number, ?Slice) → ?Step
// "Fit" a slice into a given position in the document, producing a
// [step](#transform.Step) that inserts it.
function replaceStep(doc, from, to = from, slice = Slice.empty) {
// ‘Fit’ a slice into a given position in the document, producing a
// [step](#transform.Step) that inserts it. Will return null if
// there's no meaningful way to insert the slice here, or inserting it
// would be a no-op (an empty slice over an empty range).
export function replaceStep(doc, from, to = from, slice = Slice.empty) {
if (from == to && !slice.size) return null

@@ -165,3 +32,2 @@

}
exports.replaceStep = replaceStep

@@ -184,2 +50,8 @@ // :: (number, ?number, ?Slice) → this

// :: (number, number) → this
// Delete the content between the given positions.
Transform.prototype.delete = function(from, to) {
return this.replace(from, to, Slice.empty)
}
// :: (number, union<Fragment, Node, [Node]>) → this

@@ -248,3 +120,3 @@ // Insert the given content at the given position.

if (openEnd > 0)
match = match.matchNode(count == 1 && openStart > 0 ? $from.node(depth + 1) : content.lastChild)
match = match.matchType((count == 1 && openStart > 0 ? $from.node(depth + 1) : content.lastChild).type)

@@ -330,3 +202,3 @@ // If we're here, the next level can't be joined, so we see what

match = match.matchFragment($to.parent.content, $to.index())
return match && match.validEnd()
return match && match.validEnd
}

@@ -373,15 +245,14 @@

// Get the components of the node at this level
let curType, curAttrs, curFragment
let curType, curAttrs, curMarks, curFragment
if (dSlice >= 0) {
if (dSlice > 0) { // Inside slice
;({type: curType, attrs: curAttrs, content: curFragment} = nodeLeft(slice.content, dSlice))
;({type: curType, attrs: curAttrs, content: curFragment, marks: curMarks} = nodeLeft(slice.content, dSlice))
} else if (dSlice == 0) { // Top of slice
curFragment = slice.content
curMarks = Mark.none
}
if (dSlice < slice.openStart) curFragment = curFragment.cut(curFragment.firstChild.nodeSize)
if (dSlice < slice.openStart) curFragment = curFragment.cutByIndex(1, curFragment.childCount)
} else { // Outside slice, in generated wrappers (see below)
curFragment = Fragment.empty
let parent = parents[parents.length + dSlice - 1]
curType = parent.type
curAttrs = parent.attrs
;({type: curType, attrs: curAttrs, marks: curMarks} = parents[parents.length + dSlice - 1])
}

@@ -402,6 +273,6 @@ // If the last iteration left unplaced content, include it in the fragment

// If there was a fit, store it, and consider this content placed
if (found.fragment.size > 0) placed[found.depth] = {
content: found.fragment,
openEnd: endOfContent(slice, dSlice) ? slice.openEnd - dSlice : 0,
depth: found.depth
if (found.fragment.size > 0) {
let openEnd = endOfContent(slice, dSlice) ? slice.openEnd - dSlice : 0
if (placed[found.depth] && curFragment.size == 0) openEnd = placed[found.depth].openEnd
placed[found.depth] = {content: found.fragment, openEnd, depth: found.depth}
}

@@ -417,3 +288,3 @@ // If that was the last of the content, we're done

// Try to find a wrapping that makes its first child fit in the top node.
let wrap = top.contentMatchAt($from.index(0)).findWrappingFor(curFragment.firstChild)
let wrap = top.contentMatchAt($from.index(0)).findWrapping(curFragment.firstChild.type)
// If no such thing exists, give up.

@@ -423,10 +294,11 @@ if (!wrap || wrap.length == 0) break

// Check that the fragment actually fits in the wrapping.
if (!last.type.contentExpr.matches(last.attrs, curFragment)) break
if (!last.validContent(curFragment)) break
// Store the result for subsequent iterations.
parents = [{type: top.type, attrs: top.attrs}].concat(wrap)
;({type: curType, attrs: curAttrs} = last)
curType = last
curAttrs = null
}
if (curFragment.size) {
curFragment = curType.contentExpr.start(curAttrs).fillBefore(curFragment, true).append(curFragment)
unplaced = curType.create(curAttrs, curFragment)
curFragment = curType.contentMatch.fillBefore(curFragment, true).append(curFragment)
unplaced = curType.create(curAttrs, curFragment, curMarks)
} else {

@@ -454,3 +326,3 @@ unplaced = null

for (let d = start; d >= 0; d--) {
let startMatch = $from.node(d).contentMatchAt($from.indexAfter(d))
let parent = $from.node(d), startMatch = parent.contentMatchAt($from.indexAfter(d))
let existing = placed[d]

@@ -461,3 +333,3 @@ if (existing) startMatch = startMatch.matchFragment(existing.content)

if (hasMarks) {
let stripped = matchStrippingMarks(startMatch, fragment)
let stripped = matchStrippingMarks(parent.type, startMatch, fragment)
if (stripped) return {depth: d, fragment: existing ? existing.content.append(stripped) : stripped}

@@ -468,9 +340,9 @@ }

function matchStrippingMarks(match, fragment) {
function matchStrippingMarks(type, match, fragment) {
let newNodes = []
for (let i = 0; i < fragment.childCount; i++) {
let node = fragment.child(i), stripped = node.mark(node.marks.filter(m => match.allowsMark(m.type)))
match = match.matchNode(stripped)
let node = fragment.child(i)
match = match.matchType(node.type)
if (!match) return null
newNodes.push(stripped)
newNodes.push(node.mark(type.allowedMarks(node.marks)))
}

@@ -483,7 +355,151 @@ return Fragment.from(newNodes)

for (; dFrom > dFound; dFrom--) {
let here = $from.node(dFrom).contentMatchAt($from.indexAfter(dFrom))
for (let d = dSlice - 1; d >= 0; d--)
if (here.matchNode(nodeLeft(slice.content, d))) return true
let parent = $from.node(dFrom), here = parent.contentMatchAt($from.indexAfter(dFrom))
for (let d = dSlice - 1; d >= 0; d--) {
let node = nodeLeft(slice.content, d)
if (here.matchType(node.type) && parent.type.allowsMarks(node.marks)) return true
}
}
return false
}
// :: (number, number, Slice) → this
// Replace a range of the document with a given slice, using `from`,
// `to`, and the slice's [`openStart`](#model.Slice.openStart) property
// as hints, rather than fixed start and end points. This method may
// grow the replaced area or close open nodes in the slice in order to
// get a fit that is more in line with WYSIWYG expectations, by
// dropping fully covered parent nodes of the replaced region when
// they are marked [non-defining](#model.NodeSpec.defining), or
// including an open parent node from the slice that _is_ marked as
// [defining](#model.NodeSpec.defining).
//
// This is the method, for example, to handle paste. The similar
// [`replace`](#transform.Transform.replace) method is a more
// primitive tool which will _not_ move the start and end of its given
// range, and is useful in situations where you need more precise
// control over what happens.
Transform.prototype.replaceRange = function(from, to, slice) {
if (!slice.size) return this.deleteRange(from, to)
let $from = this.doc.resolve(from), $to = this.doc.resolve(to)
if (fitsTrivially($from, $to, slice))
return this.step(new ReplaceStep(from, to, slice))
let targetDepths = coveredDepths($from, this.doc.resolve(to))
// Can't replace the whole document, so remove 0 if it's present
if (targetDepths[targetDepths.length - 1] == 0) targetDepths.pop()
// Negative numbers represent not expansion over the whole node at
// that depth, but replacing from $from.before(-D) to $to.pos.
let preferredTarget = -($from.depth + 1)
targetDepths.unshift(preferredTarget)
// This loop picks a preferred target depth, if one of the covering
// depths is not outside of a defining node, and adds negative
// depths for any depth that has $from at its start and does not
// cross a defining node.
for (let d = $from.depth, pos = $from.pos - 1; d > 0; d--, pos--) {
let spec = $from.node(d).type.spec
if (spec.defining || spec.isolating) break
if (targetDepths.indexOf(d) > -1) preferredTarget = d
else if ($from.before(d) == pos) targetDepths.splice(1, 0, -d)
}
let leftNodes = [], preferredDepth = slice.openStart
for (let content = slice.content, i = 0;; i++) {
let node = content.firstChild
leftNodes.push(node)
if (i == slice.openStart) break
content = node.content
}
// Back up if the node directly above openStart, or the node above
// that separated only by a non-defining textblock node, is defining.
if (preferredDepth > 0 && leftNodes[preferredDepth - 1].type.spec.defining)
preferredDepth -= 1
else if (preferredDepth >= 2 && leftNodes[preferredDepth - 1].isTextblock && leftNodes[preferredDepth - 2].type.spec.defining)
preferredDepth -= 2
// Try to fit each possible depth of the slice into each possible
// target depth, starting with the preferred depths.
let preferredTargetIndex = targetDepths.indexOf(preferredTarget)
for (let j = slice.openStart; j >= 0; j--) {
let openDepth = (j + preferredDepth + 1) % (slice.openStart + 1)
let insert = leftNodes[openDepth]
if (!insert) continue
for (let i = 0; i < targetDepths.length; i++) {
// Loop over possible expansion levels, starting with the
// preferred one
let targetDepth = targetDepths[(i + preferredTargetIndex) % targetDepths.length], expand = true
if (targetDepth < 0) { expand = false; targetDepth = -targetDepth }
let parent = $from.node(targetDepth - 1), index = $from.index(targetDepth - 1)
if (parent.canReplaceWith(index, index, insert.type, insert.marks))
return this.replace($from.before(targetDepth), expand ? $to.after(targetDepth) : to,
new Slice(closeFragment(slice.content, 0, slice.openStart, openDepth),
openDepth, slice.openEnd))
}
}
return this.replace(from, to, slice)
}
function closeFragment(fragment, depth, oldOpen, newOpen, parent) {
if (depth < oldOpen) {
let first = fragment.firstChild
fragment = fragment.replaceChild(0, first.copy(closeFragment(first.content, depth + 1, oldOpen, newOpen, first)))
}
if (depth > newOpen)
fragment = parent.contentMatchAt(0).fillBefore(fragment).append(fragment)
return fragment
}
// :: (number, number, Node) → this
// Replace the given range with a node, but use `from` and `to` as
// hints, rather than precise positions. When from and to are the same
// and are at the start or end of a parent node in which the given
// node doesn't fit, this method may _move_ them out towards a parent
// that does allow the given node to be placed. When the given range
// completely covers a parent node, this method may completely replace
// that parent node.
Transform.prototype.replaceRangeWith = function(from, to, node) {
if (!node.isInline && from == to && this.doc.resolve(from).parent.content.size) {
let point = insertPoint(this.doc, from, node.type)
if (point != null) from = to = point
}
return this.replaceRange(from, to, new Slice(Fragment.from(node), 0, 0))
}
// :: (number, number) → this
// Delete the given range, expanding it to cover fully covered
// parent nodes until a valid replace is found.
Transform.prototype.deleteRange = function(from, to) {
let $from = this.doc.resolve(from), $to = this.doc.resolve(to)
let covered = coveredDepths($from, $to)
for (let i = 0; i < covered.length; i++) {
let depth = covered[i], last = i == covered.length - 1
if ((last && depth == 0) || $from.node(depth).type.contentMatch.validEnd) {
from = $from.start(depth)
to = $to.end(depth)
break
}
if (depth > 0 && (last || $from.node(depth - 1).canReplace($from.index(depth - 1), $to.indexAfter(depth - 1)))) {
from = $from.before(depth)
to = $to.after(depth)
break
}
}
return this.delete(from, to)
}
// : (ResolvedPos, ResolvedPos) → [number]
// Returns an array of all depths for which $from - $to spans the
// whole content of the nodes at that depth.
function coveredDepths($from, $to) {
let result = [], minDepth = Math.min($from.depth, $to.depth)
for (let d = minDepth; d >= 0; d--) {
let start = $from.start(d)
if (start < $from.pos - ($from.depth - d) ||
$to.end(d) > $to.pos + ($to.depth - d) ||
$from.node(d).type.spec.isolating ||
$to.node(d).type.spec.isolating) break
if (start == $to.start(d)) result.push(d)
}
return result
}

@@ -1,4 +0,4 @@

const {ReplaceError} = require("prosemirror-model")
import {ReplaceError} from "prosemirror-model"
const {StepMap} = require("./map")
import {StepMap} from "./map"

@@ -9,5 +9,5 @@ function mustOverride() { throw new Error("Override me") }

// ::- A step object wraps an atomic operation. It generally applies
// ::- A step object represents an atomic change. It generally applies
// only to the document it was created for, since the positions
// associated with it will only make sense for that document.
// stored in it will only make sense for that document.
//

@@ -19,3 +19,3 @@ // New steps are defined by creating classes that extend `Step`,

// [`Step.jsonID`](#transform.Step^jsonID).
class Step {
export class Step {
// :: (doc: Node) → StepResult

@@ -29,4 +29,5 @@ // Applies this step to the given document, returning a result

// :: () → StepMap
// Get the step map that represents the changes made by this
// step.
// Get the step map that represents the changes made by this step,
// and which can be used to transform between positions in the old
// and the new document.
getMap() { return StepMap.empty }

@@ -51,23 +52,8 @@

// :: (n: number) → Step
// Returns a copy of this step in which all positions have `n` added
// to them. The main use for this is to take a step in one document,
// and make it apply to a sub-document, or a larger document that
// the original document is a part of.
offset(_n) { return mustOverride() }
// :: () → Object
// Create a JSON-serializeable representation of this step. By
// default, it'll create an object with the step's [JSON
// id](#transform.Step^jsonID), and each of the steps's own properties,
// automatically calling `toJSON` on the property values that have
// such a method.
toJSON() {
let obj = {stepType: this.jsonID}
for (let prop in this) if (this.hasOwnProperty(prop)) {
let val = this[prop]
obj[prop] = val && val.toJSON ? val.toJSON() : val
}
return obj
}
// Create a JSON-serializeable representation of this step. When
// defining this for a custom subclass, make sure the result object
// includes the step type's [JSON id](#transform.Step^jsonID) under
// the `stepType` property.
toJSON() { return mustOverride() }

@@ -93,7 +79,6 @@ // :: (Schema, Object) → Step

}
exports.Step = Step
// ::- The result of [applying](#transform.Step.apply) a step. Contains either a
// new document or a failure value.
class StepResult {
export class StepResult {
// : (?Node, ?string)

@@ -128,2 +113,1 @@ constructor(doc, failed) {

}
exports.StepResult = StepResult

@@ -1,5 +0,5 @@

const {Slice, Fragment} = require("prosemirror-model")
import {Slice, Fragment} from "prosemirror-model"
const {Transform} = require("./transform")
const {ReplaceStep, ReplaceAroundStep} = require("./replace_step")
import {Transform} from "./transform"
import {ReplaceStep, ReplaceAroundStep} from "./replace_step"

@@ -15,3 +15,3 @@ function canCut(node, start, end) {

// [isolating](#model.NodeSpec.isolating) parent nodes.
function liftTarget(range) {
export function liftTarget(range) {
let parent = range.parent

@@ -27,3 +27,2 @@ let content = parent.content.cutByIndex(range.startIndex, range.endIndex)

}
exports.liftTarget = liftTarget

@@ -34,4 +33,4 @@ // :: (NodeRange, number) → this

// the depth specified by `target`. You'll probably want to use
// `liftTarget` to compute `target`, in order to be sure the lift is
// valid.
// [`liftTarget`](#transform.liftTarget) to compute `target`, to make
// sure the lift is valid.
Transform.prototype.lift = function(range, target) {

@@ -72,31 +71,29 @@ let {$from, $to, depth} = range

// could be found.
function findWrapping(range, nodeType, attrs, innerRange = range) {
let wrap = {type: nodeType, attrs}
let around = findWrappingOutside(range, wrap)
let inner = around && findWrappingInside(innerRange, wrap)
export function findWrapping(range, nodeType, attrs, innerRange = range) {
let around = findWrappingOutside(range, nodeType)
let inner = around && findWrappingInside(innerRange, nodeType)
if (!inner) return null
return around.concat(wrap).concat(inner)
return around.map(withAttrs).concat({type: nodeType, attrs}).concat(inner.map(withAttrs))
}
exports.findWrapping = findWrapping
function findWrappingOutside(range, wrap) {
function withAttrs(type) { return {type, attrs: null} }
function findWrappingOutside(range, type) {
let {parent, startIndex, endIndex} = range
let around = parent.contentMatchAt(startIndex).findWrapping(wrap.type, wrap.attrs)
let around = parent.contentMatchAt(startIndex).findWrapping(type)
if (!around) return null
let outer = around.length ? around[0] : wrap
if (!parent.canReplaceWith(startIndex, endIndex, outer.type, outer.attrs))
return null
return around
let outer = around.length ? around[0] : type
return parent.canReplaceWith(startIndex, endIndex, outer) ? around : null
}
function findWrappingInside(range, wrap) {
function findWrappingInside(range, type) {
let {parent, startIndex, endIndex} = range
let inner = parent.child(startIndex)
let inside = wrap.type.contentExpr.start(wrap.attrs).findWrappingFor(inner)
let inside = type.contentMatch.findWrapping(inner.type)
if (!inside) return null
let last = inside.length ? inside[inside.length - 1] : wrap
let innerMatch = last.type.contentExpr.start(last.attrs)
for (let i = startIndex; i < endIndex; i++)
innerMatch = innerMatch && innerMatch.matchNode(parent.child(i))
if (!innerMatch || !innerMatch.validEnd()) return null
let lastType = inside.length ? inside[inside.length - 1] : type
let innerMatch = lastType.contentMatch
for (let i = startIndex; innerMatch && i < endIndex; i++)
innerMatch = innerMatch.matchType(parent.child(i).type)
if (!innerMatch || !innerMatch.validEnd) return null
return inside

@@ -108,3 +105,3 @@ }

// The wrappers are assumed to be valid in this position, and should
// probably be computed with `findWrapping`.
// probably be computed with [`findWrapping`](#transform.findWrapping).
Transform.prototype.wrap = function(range, wrappers) {

@@ -128,3 +125,3 @@ let content = Fragment.empty

// Ensure all markup that isn't allowed in the new node type is cleared
this.clearNonMatching(this.mapping.slice(mapFrom).map(pos, 1), type.contentExpr.start(attrs))
this.clearIncompatible(this.mapping.slice(mapFrom).map(pos, 1), type)
let mapping = this.mapping.slice(mapFrom)

@@ -141,3 +138,4 @@ let startM = mapping.map(pos, 1), endM = mapping.map(pos + node.nodeSize, 1)

// :: (number, ?NodeType, ?Object, ?[Mark]) → this
// Change the type and attributes of the node after `pos`.
// Change the type, attributes, and/or marks of the node at `pos`.
// When `nodeType` is null, the existing node type is preserved,
Transform.prototype.setNodeType = function(pos, type, attrs, marks) {

@@ -151,3 +149,3 @@ let node = this.doc.nodeAt(pos)

if (!type.validContent(node.content, attrs))
if (!type.validContent(node.content))
throw new RangeError("Invalid content for node type " + type.name)

@@ -161,3 +159,3 @@

// Check whether splitting at the given position is allowed.
function canSplit(doc, pos, depth = 1, typesAfter) {
export function canSplit(doc, pos, depth = 1, typesAfter) {
let $pos = doc.resolve(pos), base = $pos.depth - depth

@@ -167,3 +165,3 @@ let innerType = (typesAfter && typesAfter[typesAfter.length - 1]) || $pos.parent

!$pos.parent.canReplace($pos.index(), $pos.parent.childCount) ||
!innerType.type.validContent($pos.parent.content.cutByIndex($pos.index(), $pos.parent.childCount), innerType.attrs))
!innerType.type.validContent($pos.parent.content.cutByIndex($pos.index(), $pos.parent.childCount)))
return false

@@ -175,3 +173,3 @@ for (let d = $pos.depth - 1, i = depth - 2; d > base; d--, i--) {

if (after != node) rest = rest.replaceChild(0, after.type.create(after.attrs))
if (!node.canReplace(index + 1, node.childCount) || !after.type.validContent(rest, after.attrs))
if (!node.canReplace(index + 1, node.childCount) || !after.type.validContent(rest))
return false

@@ -181,6 +179,4 @@ }

let baseType = typesAfter && typesAfter[0]
return $pos.node(base).canReplaceWith(index, index, baseType ? baseType.type : $pos.node(base + 1).type,
baseType ? baseType.attrs : $pos.node(base + 1).attrs)
return $pos.node(base).canReplaceWith(index, index, baseType ? baseType.type : $pos.node(base + 1).type)
}
exports.canSplit = canSplit

@@ -206,3 +202,3 @@ // :: (number, ?number, ?[?{type: NodeType, attrs: ?Object}]) → this

// joined.
function canJoin(doc, pos) {
export function canJoin(doc, pos) {
let $pos = doc.resolve(pos), index = $pos.index()

@@ -212,3 +208,2 @@ return joinable($pos.nodeBefore, $pos.nodeAfter) &&

}
exports.canJoin = canJoin

@@ -223,3 +218,3 @@ function joinable(a, b) {

// point, if any.
function joinPoint(doc, pos, dir = -1) {
export function joinPoint(doc, pos, dir = -1) {
let $pos = doc.resolve(pos)

@@ -243,3 +238,2 @@ for (let d = $pos.depth;; d--) {

}
exports.joinPoint = joinPoint

@@ -254,3 +248,3 @@ // :: (number, ?number, ?bool) → this

// :: (Node, number, NodeType, ?Object) → ?number
// :: (Node, number, NodeType) → ?number
// Try to find a point where a node of the given type can be inserted

@@ -260,5 +254,5 @@ // near `pos`, by searching up the node hierarchy when `pos` itself

// null if no position was found.
function insertPoint(doc, pos, nodeType, attrs) {
export function insertPoint(doc, pos, nodeType) {
let $pos = doc.resolve(pos)
if ($pos.parent.canReplaceWith($pos.index(), $pos.index(), nodeType, attrs)) return pos
if ($pos.parent.canReplaceWith($pos.index(), $pos.index(), nodeType)) return pos

@@ -268,3 +262,3 @@ if ($pos.parentOffset == 0)

let index = $pos.index(d)
if ($pos.node(d).canReplaceWith(index, index, nodeType, attrs)) return $pos.before(d + 1)
if ($pos.node(d).canReplaceWith(index, index, nodeType)) return $pos.before(d + 1)
if (index > 0) return null

@@ -275,6 +269,5 @@ }

let index = $pos.indexAfter(d)
if ($pos.node(d).canReplaceWith(index, index, nodeType, attrs)) return $pos.after(d + 1)
if ($pos.node(d).canReplaceWith(index, index, nodeType)) return $pos.after(d + 1)
if (index < $pos.node(d).childCount) return null
}
}
exports.insertPoint = insertPoint

@@ -1,17 +0,16 @@

const {Mapping} = require("./map")
import {Mapping} from "./map"
class TransformError extends Error {
export class TransformError extends Error {
constructor(message) { super(message) }
get name() { return "TransformError" }
}
exports.TransformError = TransformError
// ::- Abstraction to build up and track such an array of
// [steps](#transform.Step).
// ::- Abstraction to build up and track an array of
// [steps](#transform.Step) representing a document transformation.
//
// The high-level transforming methods return the `Transform` object
// itself, so that they can be chained.
class Transform {
// Most transforming methods return the `Transform` object itself, so
// that they can be chained.
export class Transform {
// :: (Node)
// Create a transformation that starts with the given document.
// Create a transform that starts with the given document.
constructor(doc) {

@@ -33,8 +32,8 @@ // :: Node

// :: Node The document at the start of the transformation.
// :: Node The starting document.
get before() { return this.docs.length ? this.docs[0] : this.doc }
// :: (step: Step) → this
// Apply a new step in this transformation, saving the result.
// Throws an error when the step fails.
// Apply a new step in this transform, saving the result. Throws an
// error when the step fails.
step(object) {

@@ -56,3 +55,4 @@ let result = this.maybeStep(object)

// :: bool
// True when this transaction changes the document.
// True when the document has been changed (when there are any
// steps).
get docChanged() {

@@ -69,2 +69,1 @@ return this.steps.length > 0

}
exports.Transform = Transform

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc