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.24.0 to 1.0.0

4

CONTRIBUTING.md

@@ -37,2 +37,6 @@ # How to contribute

If you want to make a change that involves a significant overhaul of
the code or introduces a user-visible new feature, create an
[RFC](https://github.com/ProseMirror/rfcs/) first with your proposal.
- Make sure you have a [GitHub Account](https://github.com/signup/free)

@@ -39,0 +43,0 @@

6

package.json
{
"name": "prosemirror-transform",
"version": "0.24.0",
"version": "1.0.0",
"description": "ProseMirror document transformations",

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

"dependencies": {
"prosemirror-model": "^0.24.0"
"prosemirror-model": "^1.0.0"
},

@@ -25,3 +25,3 @@ "devDependencies": {

"ist": "^1.0.0",
"prosemirror-test-builder": "^0.24.0",
"prosemirror-test-builder": "^1.0.0",
"rollup": "^0.49.0",

@@ -28,0 +28,0 @@ "rollup-plugin-buble": "^0.15.0"

@@ -5,2 +5,3 @@ # prosemirror-transform

This is a [core module](http://prosemirror.net/docs/ref/#transform) of [ProseMirror](http://prosemirror.net).
ProseMirror is a well-behaved rich semantic content editor based on

@@ -25,1 +26,6 @@ contentEditable, with support for collaborative editing and custom

is the place to report issues.
We aim to be an inclusive, welcoming community. To make that explicit,
we have a [code of
conduct](http://contributor-covenant.org/version/1/1/0/) that applies
to communication around the project.

@@ -1,2 +0,2 @@

import {Fragment, Slice, Mark} from "prosemirror-model"
import {Fragment, Slice} from "prosemirror-model"

@@ -202,2 +202,12 @@ import {ReplaceStep, ReplaceAroundStep} from "./replace_step"

function nodeLeft(content, depth) {
for (let i = 1; i < depth; i++) content = content.firstChild.content
return content.firstChild
}
function nodeRight(content, depth) {
for (let i = 1; i < depth; i++) content = content.lastChild.content
return content.lastChild
}
// Algorithm for 'placing' the elements of a slice into a gap:

@@ -223,80 +233,65 @@ //

function nodeLeft(content, depth) {
for (let i = 1; i < depth; i++) content = content.firstChild.content
return content.firstChild
}
function nodeRight(content, depth) {
for (let i = 1; i < depth; i++) content = content.lastChild.content
return content.lastChild
}
// : (ResolvedPos, Slice) → [{content: Fragment, openEnd: number, depth: number}]
function placeSlice($from, slice) {
let dFrom = $from.depth, unplaced = null
let placed = [], parents = null
let placed = []
if (!slice.content.size) return placed
// Loop over the open side of the slice, trying to find a place for
// each open fragment.
for (let dSlice = slice.openStart;; --dSlice) {
// Get the components of the node at this level
let curType, curAttrs, curMarks, curFragment
if (dSlice >= 0) {
if (dSlice > 0) { // Inside slice
;({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.cutByIndex(1, curFragment.childCount)
} else { // Outside slice, in generated wrappers (see below)
curFragment = Fragment.empty
;({type: curType, attrs: curAttrs, marks: curMarks} = parents[parents.length + dSlice - 1])
// each open fragment. The first pass tries to find direct fits, the
// second allows wrapping.
let dSlice = slice.openStart, lastPlaced = $from.depth + 1
for (let dFrom = $from.depth, pass = 1; dFrom >= 0 && dSlice >= 0; dFrom--) {
// If we've reached the end of the first pass, go to the second
if (dFrom == 0 && pass == 1) {
dFrom = lastPlaced
pass = 2
continue
}
// If the last iteration left unplaced content, include it in the fragment
if (unplaced) curFragment = curFragment.addToStart(unplaced)
let parent = $from.node(dFrom), match = parent.contentMatchAt($from.indexAfter(dFrom))
let existing = placed[dFrom]
let placedHere = existing ? existing.content : Fragment.empty, openEnd = existing ? existing.openEnd : 0
// If there's nothing left to place, we're done
if (curFragment.size == 0 && dSlice <= 0) break
for (let d = dSlice; d >= 0; d--) {
let content = sliceRange(slice.content, d, dSlice == slice.openStart ? null : dSlice + 1)
// This will go through the positions in $from, down from dFrom,
// to find a fit
let found = findPlacement(curFragment, $from, dFrom, placed)
if (found && unneccesaryFallthrough($from, dFrom, found.depth, slice, dSlice))
found = null
if (found) {
// If there was a fit, store it, and consider this content placed
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}
}
// If that was the last of the content, we're done
if (dSlice <= 0) break
unplaced = null
dFrom = found.depth - (curType == $from.node(found.depth).type ? 1 : 0)
} else {
if (dSlice == 0) {
// This is the top of the slice, and we haven't found a place to insert it.
let top = $from.node(0)
// Try to find a wrapping that makes its first child fit in the top node.
let wrap = top.contentMatchAt($from.index(0)).findWrapping(curFragment.firstChild.type)
// If no such thing exists, give up.
if (!wrap || wrap.length == 0) break
let last = wrap[wrap.length - 1]
// Check that the fragment actually fits in the wrapping.
if (!last.validContent(curFragment)) break
// Store the result for subsequent iterations.
parents = [{type: top.type, attrs: top.attrs}].concat(wrap)
curType = last
curAttrs = null
}
if (curFragment.size) {
curFragment = curType.contentMatch.fillBefore(curFragment, true).append(curFragment)
unplaced = curType.create(curAttrs, curFragment, curMarks)
if (pass == 1) {
// First pass, search for direct fits (possibly by stripping marks
let fits = match.fillBefore(content)
if (!fits && hasMarks(content)) {
let stripped = matchStrippingMarks(parent.type, match, content)
if (stripped) { content = stripped; fits = Fragment.empty }
}
if (fits) {
content = fits.append(closeStart(content, dSlice - d))
placedHere = placedHere.append(content)
if (content.size) openEnd = endOfContent(slice, d) ? slice.openEnd - d : 0
dSlice = d - 1
lastPlaced = dFrom
if (nodeLeft(slice.content, d).type == parent.type) break
}
} else {
unplaced = null
// Second pass, allows introducing wrapper nodes
if (content.size == 0) continue
let wrap = match.findWrapping(content.firstChild.type)
if (!wrap) continue
let atEnd = endOfContent(slice, d)
if (!wrap.length) {
if (!match.matchFragment(content)) continue
} else if (d && wrap[wrap.length - 1] == nodeLeft(slice.content, d).type) {
// Don't create wrappers that correspond to exiting wrapper nodes
continue
} else if (!atEnd) {
let after = wrap[wrap.length - 1].contentMatch.matchFragment(content)
if (!after) continue
content = content.append(after.fillBefore(Fragment.empty, true))
}
content = closeStart(content, dSlice - d)
for (let i = wrap.length - 1; i >= 0; i--) content = Fragment.from(wrap[i].create(null, content))
placedHere = placedHere.append(content)
if (content.size) openEnd = atEnd ? wrap.length + slice.openEnd : 0
dSlice = d - 1
}
}
if (placedHere.size) placed[dFrom] = {content: placedHere, openEnd, depth: dFrom}
}

@@ -315,17 +310,6 @@

function findPlacement(fragment, $from, start, placed) {
let hasMarks = false
function hasMarks(fragment) {
for (let i = 0; i < fragment.childCount; i++)
if (fragment.child(i).marks.length) hasMarks = true
for (let d = start; d >= 0; d--) {
let parent = $from.node(d), startMatch = parent.contentMatchAt($from.indexAfter(d))
let existing = placed[d]
if (existing) startMatch = startMatch.matchFragment(existing.content)
let match = startMatch.fillBefore(fragment)
if (match) return {depth: d, fragment: (existing ? existing.content.append(match) : match).append(fragment)}
if (hasMarks) {
let stripped = matchStrippingMarks(parent.type, startMatch, fragment)
if (stripped) return {depth: d, fragment: existing ? existing.content.append(stripped) : stripped}
}
}
if (fragment.child(i).marks.length) return true
return false
}

@@ -344,14 +328,25 @@

function unneccesaryFallthrough($from, dFrom, dFound, slice, dSlice) {
if (dSlice < 1) return false
for (; dFrom > dFound; dFrom--) {
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
// : (Fragment, number, ?number) → Fragment
// Pick the fragment at `startDepth` out of a slice's content,
// dropping the first node at depth `endDepth`, if not null.
function sliceRange(content, startDepth, endDepth) {
for (let i = 0; i < startDepth; i++) content = content.firstChild.content
if (endDepth != null) content = dropFirstAt(content, endDepth - startDepth)
return content
}
function dropFirstAt(fragment, depth) {
if (depth == 1) return fragment.cutByIndex(1, fragment.childCount)
let first = fragment.firstChild
return fragment.replaceChild(0, first.copy(dropFirstAt(first.content, depth - 1)))
}
function closeStart(fragment, depth) {
if (depth == 0) return fragment
let first = fragment.firstChild, content = closeStart(first.content, depth - 1)
if (!content.size) return fragment.cutByIndex(1, fragment.childCount)
let fill = first.type.contentMatch.fillBefore(content)
return fragment.replaceChild(0, first.copy(fill.append(content)))
}
// :: (number, number, Slice) → this

@@ -358,0 +353,0 @@ // Replace a range of the document with a given slice, using `from`,

@@ -118,3 +118,3 @@ import {Slice, Fragment} from "prosemirror-model"

this.doc.nodesBetween(from, to, (node, pos) => {
if (node.isTextblock && !node.hasMarkup(type, attrs)) {
if (node.isTextblock && !node.hasMarkup(type, attrs) && canChangeType(this.doc, this.mapping.slice(mapFrom).map(pos), type)) {
// Ensure all markup that isn't allowed in the new node type is cleared

@@ -132,9 +132,5 @@ this.clearIncompatible(this.mapping.slice(mapFrom).map(pos, 1), type)

let warnedAboutSetNodeType = false
Transform.prototype.setNodeType = function(pos, type, attrs, marks) {
if (!warnedAboutSetNodeType && typeof console == "object" && console.warn) {
warnedAboutSetNodeType = true
console.warn("setNodeType has been renamed to setNodeMarkup")
}
return this.setNodeMarkup(pos, type, attrs, marks)
function canChangeType(doc, pos, type) {
let $pos = doc.resolve(pos), index = $pos.index()
return $pos.parent.canReplaceWith(index, index + 1, type)
}

@@ -165,3 +161,3 @@

let innerType = (typesAfter && typesAfter[typesAfter.length - 1]) || $pos.parent
if (base < 0 ||
if (base < 0 || $pos.parent.type.spec.isolating ||
!$pos.parent.canReplace($pos.index(), $pos.parent.childCount) ||

@@ -172,2 +168,3 @@ !innerType.type.validContent($pos.parent.content.cutByIndex($pos.index(), $pos.parent.childCount)))

let node = $pos.node(d), index = $pos.index(d)
if (node.type.spec.isolating) return false
let rest = node.content.cutByIndex(index, node.childCount)

@@ -174,0 +171,0 @@ let after = (typesAfter && typesAfter[i]) || node

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