1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-28 09:29:49 +02:00

refactor to eliminate ./utils/normalize, fixes #372 (#1060)

* refactor to eliminate ./utils/normalize, fixes #372

* fix mark default value
This commit is contained in:
Ian Storm Taylor
2017-09-06 14:24:48 -07:00
committed by GitHub
parent e77cae7bf7
commit 8d47f8e8b6
24 changed files with 537 additions and 644 deletions

View File

@@ -14,6 +14,7 @@
"immutable": "^3.8.1",
"is-empty": "^1.0.0",
"is-in-browser": "^1.1.3",
"is-plain-object": "^2.0.4",
"is-window": "^1.0.2",
"keycode": "^2.1.2",
"lodash": "^4.17.4",

View File

@@ -1,5 +1,7 @@
import Normalize from '../utils/normalize'
import Block from '../models/block'
import Inline from '../models/inline'
import Mark from '../models/mark'
/**
* Changes.
@@ -49,7 +51,7 @@ PROXY_TRANSFORMS.forEach((method) => {
*/
Changes.addMark = (change, mark) => {
mark = Normalize.mark(mark)
mark = Mark.create(mark)
const { state } = change
const { document, selection } = state
@@ -95,7 +97,7 @@ Changes.delete = (change) => {
*/
Changes.insertBlock = (change, block) => {
block = Normalize.block(block)
block = Block.create(block)
const { state } = change
const { selection } = state
change.insertBlockAtRange(selection, block)
@@ -155,7 +157,7 @@ Changes.insertFragment = (change, fragment) => {
*/
Changes.insertInline = (change, inline) => {
inline = Normalize.inline(inline)
inline = Inline.create(inline)
const { state } = change
const { selection } = state
change.insertInlineAtRange(selection, inline)
@@ -209,7 +211,7 @@ Changes.splitBlock = (change, depth = 1) => {
*/
Changes.removeMark = (change, mark) => {
mark = Normalize.mark(mark)
mark = Mark.create(mark)
const { state } = change
const { document, selection } = state
@@ -239,7 +241,7 @@ Changes.removeMark = (change, mark) => {
*/
Changes.toggleMark = (change, mark) => {
mark = Normalize.mark(mark)
mark = Mark.create(mark)
const { state } = change
const exists = state.activeMarks.has(mark)

View File

@@ -1,5 +1,8 @@
import Normalize from '../utils/normalize'
import Block from '../models/block'
import Inline from '../models/inline'
import Mark from '../models/mark'
import Node from '../models/node'
import String from '../utils/string'
import SCHEMA from '../schemas/core'
import { List } from 'immutable'
@@ -597,7 +600,7 @@ Changes.deleteForwardAtRange = (change, range, n = 1, options = {}) => {
*/
Changes.insertBlockAtRange = (change, range, block, options = {}) => {
block = Normalize.block(block)
block = Block.create(block)
const { normalize = true } = options
if (range.isExpanded) {
@@ -766,7 +769,7 @@ Changes.insertFragmentAtRange = (change, range, fragment, options = {}) => {
Changes.insertInlineAtRange = (change, range, inline, options = {}) => {
const { normalize = true } = options
inline = Normalize.inline(inline)
inline = Inline.create(inline)
if (range.isExpanded) {
change.deleteAtRange(range, OPTS)
@@ -978,7 +981,7 @@ Changes.splitInlineAtRange = (change, range, height = Infinity, options = {}) =>
Changes.toggleMarkAtRange = (change, range, mark, options = {}) => {
if (range.isCollapsed) return
mark = Normalize.mark(mark)
mark = Mark.create(mark)
const { normalize = true } = options
const { state } = change
@@ -1004,7 +1007,7 @@ Changes.toggleMarkAtRange = (change, range, mark, options = {}) => {
*/
Changes.unwrapBlockAtRange = (change, range, properties, options = {}) => {
properties = Normalize.nodeProperties(properties)
properties = Node.createProperties(properties)
const { normalize = true } = options
let { state } = change
@@ -1097,7 +1100,7 @@ Changes.unwrapBlockAtRange = (change, range, properties, options = {}) => {
*/
Changes.unwrapInlineAtRange = (change, range, properties, options = {}) => {
properties = Normalize.nodeProperties(properties)
properties = Node.createProperties(properties)
const { normalize = true } = options
const { state } = change
@@ -1143,7 +1146,7 @@ Changes.unwrapInlineAtRange = (change, range, properties, options = {}) => {
*/
Changes.wrapBlockAtRange = (change, range, block, options = {}) => {
block = Normalize.block(block)
block = Block.create(block)
block = block.set('nodes', block.nodes.clear())
const { normalize = true } = options
@@ -1229,7 +1232,7 @@ Changes.wrapInlineAtRange = (change, range, inline, options = {}) => {
return change.wrapInlineByKey(inlineParent.key, inline, options)
}
inline = Normalize.inline(inline)
inline = Inline.create(inline)
inline = inline.set('nodes', inline.nodes.clear())
const blocks = document.getBlocksAtRange(range)

View File

@@ -1,5 +1,8 @@
import Normalize from '../utils/normalize'
import Block from '../models/block'
import Inline from '../models/inline'
import Mark from '../models/mark'
import Node from '../models/node'
import SCHEMA from '../schemas/core'
/**
@@ -23,7 +26,7 @@ const Changes = {}
*/
Changes.addMarkByKey = (change, key, offset, length, mark, options = {}) => {
mark = Normalize.mark(mark)
mark = Mark.create(mark)
const { normalize = true } = options
const { state } = change
const { document } = state
@@ -232,7 +235,7 @@ Changes.moveNodeByKey = (change, key, newKey, newIndex, options = {}) => {
*/
Changes.removeMarkByKey = (change, key, offset, length, mark, options = {}) => {
mark = Normalize.mark(mark)
mark = Mark.create(mark)
const { normalize = true } = options
const { state } = change
const { document } = state
@@ -376,8 +379,8 @@ Changes.removeTextByKey = (change, key, offset, length, options = {}) => {
*/
Changes.setMarkByKey = (change, key, offset, length, mark, properties, options = {}) => {
mark = Normalize.mark(mark)
properties = Normalize.markProperties(properties)
mark = Mark.create(mark)
properties = Mark.createProperties(properties)
const { normalize = true } = options
const { state } = change
const { document } = state
@@ -409,7 +412,7 @@ Changes.setMarkByKey = (change, key, offset, length, mark, properties, options =
*/
Changes.setNodeByKey = (change, key, properties, options = {}) => {
properties = Normalize.nodeProperties(properties)
properties = Node.createProperties(properties)
const { normalize = true } = options
const { state } = change
const { document } = state
@@ -599,7 +602,7 @@ Changes.unwrapNodeByKey = (change, key, options = {}) => {
*/
Changes.wrapInlineByKey = (change, key, inline, options) => {
inline = Normalize.inline(inline)
inline = Inline.create(inline)
inline = inline.set('nodes', inline.nodes.clear())
const { document } = change.state
@@ -622,7 +625,7 @@ Changes.wrapInlineByKey = (change, key, inline, options) => {
*/
Changes.wrapBlockByKey = (change, key, block, options) => {
block = Normalize.block(block)
block = Block.create(block)
block = block.set('nodes', block.nodes.clear())
const { document } = change.state

View File

@@ -1,5 +1,4 @@
import Normalize from '../utils/normalize'
import Schema from '../models/schema'
import { Set } from 'immutable'
@@ -49,11 +48,9 @@ Changes.normalizeNodeByKey = (change, key, schema) => {
// If the schema has no validation rules, there's nothing to normalize.
if (!schema.hasValidators) return
key = Normalize.key(key)
const { state } = change
const { document } = state
const node = document.assertNode(key)
normalizeNodeAndChildren(change, node, schema)
}

View File

@@ -1,5 +1,5 @@
import Normalize from '../utils/normalize'
import Selection from '../models/selection'
import isEmpty from 'is-empty'
import logger from '../utils/logger'
import pick from 'lodash/pick'
@@ -20,7 +20,7 @@ const Changes = {}
*/
Changes.select = (change, properties, options = {}) => {
properties = Normalize.selectionProperties(properties)
properties = Selection.createProperties(properties)
const { snapshot = false } = options
const { state } = change

View File

@@ -11,11 +11,11 @@ import './document'
import Data from './data'
import Node from './node'
import Inline from './inline'
import Text from './text'
import MODEL_TYPES from '../constants/model-types'
import generateKey from '../utils/generate-key'
import { Map, List, Record } from 'immutable'
import isPlainObject from 'is-plain-object'
import { List, Map, Record } from 'immutable'
/**
* Default properties.
@@ -26,9 +26,9 @@ import { Map, List, Record } from 'immutable'
const DEFAULTS = {
data: new Map(),
isVoid: false,
key: null,
key: undefined,
nodes: new List(),
type: null
type: undefined,
}
/**
@@ -37,55 +37,64 @@ const DEFAULTS = {
* @type {Block}
*/
class Block extends new Record(DEFAULTS) {
class Block extends Record(DEFAULTS) {
/**
* Create a new `Block` with `attrs`.
*
* @param {Object|Block} attrs
* @param {Object|String|Block} attrs
* @return {Block}
*/
static create(attrs = {}) {
if (Block.isBlock(attrs)) return attrs
if (Inline.isInline(attrs)) return attrs
if (Text.isText(attrs)) return attrs
if (!attrs.type) {
throw new Error('You must pass a block `type`.')
if (Block.isBlock(attrs)) {
return attrs
}
const { nodes } = attrs
const empty = !nodes || nodes.size == 0 || nodes.length == 0
const block = new Block({
type: attrs.type,
key: attrs.key || generateKey(),
data: Data.create(attrs.data),
isVoid: !!attrs.isVoid,
nodes: Node.createList(empty ? [Text.create()] : nodes),
})
if (typeof attrs == 'string') {
attrs = { type: attrs }
}
return block
if (isPlainObject(attrs)) {
const { data, isVoid, key, type } = attrs
let { nodes } = attrs
if (typeof type != 'string') {
throw new Error('`Block.create` requires a block `type` string.')
}
if (nodes == null || nodes.length == 0) {
nodes = [Text.create()]
}
const block = new Block({
data: Data.create(data),
isVoid: !!isVoid,
key: key || generateKey(),
nodes: Node.createList(nodes),
type,
})
return block
}
throw new Error(`\`Block.create\` only accepts objects, strings or blocks, but you passed it: ${attrs}`)
}
/**
* Create a list of `Blocks` from `elements`.
*
* @param {Array<Object|Block>|List<Block>} elements
* @param {Array<Block|Object>|List<Block|Object>} elements
* @return {List<Block>}
*/
static createList(elements = []) {
if (List.isList(elements)) {
return elements
}
if (Array.isArray(elements)) {
if (List.isList(elements) || Array.isArray(elements)) {
const list = new List(elements.map(Block.create))
return list
}
throw new Error(`Block.createList() must be passed an \`Array\` or a \`List\`. You passed: ${elements}`)
throw new Error(`\`Block.createList\` only accepts arrays or lists, but you passed it: ${elements}`)
}
/**
@@ -110,7 +119,7 @@ class Block extends new Record(DEFAULTS) {
}
/**
* Is the node empty?
* Check if the block is empty.
*
* @return {Boolean}
*/
@@ -120,7 +129,7 @@ class Block extends new Record(DEFAULTS) {
}
/**
* Get the concatenated text `string` of all child nodes.
* Get the concatenated text of all the block's children.
*
* @return {String}
*/

View File

@@ -1,6 +1,8 @@
import Mark from './mark'
import MODEL_TYPES from '../constants/model-types'
import Mark from './mark'
import isPlainObject from 'is-plain-object'
import logger from '../utils/logger'
import { List, Record, Set } from 'immutable'
/**
@@ -11,7 +13,7 @@ import { List, Record, Set } from 'immutable'
const DEFAULTS = {
marks: new Set(),
text: ''
text: '',
}
/**
@@ -20,58 +22,56 @@ const DEFAULTS = {
* @type {Character}
*/
class Character extends new Record(DEFAULTS) {
class Character extends Record(DEFAULTS) {
/**
* Create a `Character` with `attrs`.
*
* @param {Object|Character} attrs
* @param {Object|String|Character} attrs
* @return {Character}
*/
static create(attrs = {}) {
if (Character.isCharacter(attrs)) return attrs
if (Character.isCharacter(attrs)) {
return attrs
}
const character = new Character({
text: attrs.text,
marks: Mark.createSet(attrs.marks),
})
if (typeof attrs == 'string') {
attrs = { text: attrs }
}
return character
if (isPlainObject(attrs)) {
const { marks, text } = attrs
const character = new Character({
text,
marks: Mark.createSet(marks),
})
return character
}
throw new Error(`\`Character.create\` only accepts objects, strings or characters, but you passed it: ${attrs}`)
}
/**
* Create a list of `Characters` from `elements`.
*
* @param {Array<Object|Character>|List<Character>} elements
* @param {String|Array<Object|Character|String>|List<Object|Character|String>} elements
* @return {List<Character>}
*/
static createList(elements = []) {
if (List.isList(elements)) {
return elements
if (typeof elements == 'string') {
elements = elements.split('')
}
if (Array.isArray(elements)) {
if (List.isList(elements) || Array.isArray(elements)) {
const list = new List(elements.map(Character.create))
return list
}
throw new Error(`Character.createList() must be passed an \`Array\` or a \`List\`. You passed: ${elements}`)
}
/**
* Create a characters list from a `string` and optional `marks`.
*
* @param {String} string
* @param {Set<Mark>} marks (optional)
* @return {List<Character>}
*/
static createListFromText(string, marks) {
const chars = string.split('').map(text => ({ text, marks }))
const list = Character.createList(chars)
return list
throw new Error(`\`Block.createList\` only accepts strings, arrays or lists, but you passed it: ${elements}`)
}
/**
@@ -85,6 +85,15 @@ class Character extends new Record(DEFAULTS) {
return !!(value && value[MODEL_TYPES.CHARACTER])
}
/**
* Deprecated.
*/
static createListFromText(string) {
logger.deprecate('0.22.0', 'The `Character.createListFromText(string)` method is deprecated, use `Character.createList(string)` instead.')
return this.createList(string)
}
/**
* Get the kind.
*

View File

@@ -1,4 +1,5 @@
import isPlainObject from 'is-plain-object'
import { Map } from 'immutable'
/**
@@ -15,14 +16,20 @@ const Data = {
/**
* Create a new `Data` with `attrs`.
*
* @param {Object} attrs
* @param {Object|Data|Map} attrs
* @return {Data} data
*/
create(attrs = {}) {
return Map.isMap(attrs)
? attrs
: new Map(attrs)
if (Map.isMap(attrs)) {
return attrs
}
if (isPlainObject(attrs)) {
return new Map(attrs)
}
throw new Error(`\`Data.create\` only accepts objects or maps, but you passed it: ${attrs}`)
}
}

View File

@@ -14,6 +14,7 @@ import Data from './data'
import Node from './node'
import MODEL_TYPES from '../constants/model-types'
import generateKey from '../utils/generate-key'
import isPlainObject from 'is-plain-object'
import { List, Map, Record } from 'immutable'
/**
@@ -24,7 +25,7 @@ import { List, Map, Record } from 'immutable'
const DEFAULTS = {
data: new Map(),
key: null,
key: undefined,
nodes: new List(),
}
@@ -34,25 +35,36 @@ const DEFAULTS = {
* @type {Document}
*/
class Document extends new Record(DEFAULTS) {
class Document extends Record(DEFAULTS) {
/**
* Create a new `Document` with `attrs`.
*
* @param {Object|Document} attrs
* @param {Object|Array|List|Text} attrs
* @return {Document}
*/
static create(attrs = {}) {
if (Document.isDocument(attrs)) return attrs
if (Document.isDocument(attrs)) {
return attrs
}
const document = new Document({
key: attrs.key || generateKey(),
data: Data.create(attrs.data),
nodes: Node.createList(attrs.nodes),
})
if (List.isList(attrs) || Array.isArray(attrs)) {
attrs = { nodes: attrs }
}
return document
if (isPlainObject(attrs)) {
const { data, key, nodes } = attrs
const document = new Document({
key: key || generateKey(),
data: Data.create(data),
nodes: Node.createList(nodes),
})
return document
}
throw new Error(`\`Document.create\` only accepts objects, arrays, lists or documents, but you passed it: ${attrs}`)
}
/**
@@ -77,7 +89,7 @@ class Document extends new Record(DEFAULTS) {
}
/**
* Is the document empty?
* Check if the document is empty.
*
* @return {Boolean}
*/
@@ -87,7 +99,7 @@ class Document extends new Record(DEFAULTS) {
}
/**
* Get the concatenated text `string` of all child nodes.
* Get the concatenated text of all the document's children.
*
* @return {String}
*/

View File

@@ -2,6 +2,7 @@
import MODEL_TYPES from '../constants/model-types'
import Debug from 'debug'
import isEqual from 'lodash/isEqual'
import isPlainObject from 'is-plain-object'
import { Record, Stack } from 'immutable'
/**
@@ -29,24 +30,30 @@ const DEFAULTS = {
* @type {History}
*/
class History extends new Record(DEFAULTS) {
class History extends Record(DEFAULTS) {
/**
* Create a new `History` with `attrs`.
*
* @param {Object} attrs
* @param {Object|History} attrs
* @return {History}
*/
static create(attrs = {}) {
if (History.isHistory(attrs)) return attrs
if (History.isHistory(attrs)) {
return attrs
}
const history = new History({
undos: attrs.undos || new Stack(),
redos: attrs.redos || new Stack(),
})
if (isPlainObject(attrs)) {
const history = new History({
undos: attrs.undos || new Stack(),
redos: attrs.redos || new Stack(),
})
return history
return history
}
throw new Error(`\`History.create\` only accepts objects or histories, but you passed it: ${attrs}`)
}
/**

View File

@@ -9,12 +9,12 @@ import './document'
* Dependencies.
*/
import Block from './block'
import Data from './data'
import Node from './node'
import Text from './text'
import MODEL_TYPES from '../constants/model-types'
import generateKey from '../utils/generate-key'
import isPlainObject from 'is-plain-object'
import { List, Map, Record } from 'immutable'
/**
@@ -26,9 +26,9 @@ import { List, Map, Record } from 'immutable'
const DEFAULTS = {
data: new Map(),
isVoid: false,
key: null,
key: undefined,
nodes: new List(),
type: null
type: undefined,
}
/**
@@ -37,47 +37,64 @@ const DEFAULTS = {
* @type {Inline}
*/
class Inline extends new Record(DEFAULTS) {
class Inline extends Record(DEFAULTS) {
/**
* Create a new `Inline` with `attrs`.
*
* @param {Object|Inline} attrs
* @param {Object|String|Inline} attrs
* @return {Inline}
*/
static create(attrs = {}) {
if (Block.isBlock(attrs)) return attrs
if (Inline.isInline(attrs)) return attrs
if (Text.isText(attrs)) return attrs
if (!attrs.type) {
throw new Error('You must pass an inline `type`.')
if (Inline.isInline(attrs)) {
return attrs
}
const { nodes } = attrs
const empty = !nodes || nodes.size == 0 || nodes.length == 0
const inline = new Inline({
type: attrs.type,
key: attrs.key || generateKey(),
data: Data.create(attrs.data),
isVoid: !!attrs.isVoid,
nodes: Node.createList(empty ? [Text.create()] : nodes),
})
if (typeof attrs == 'string') {
attrs = { type: attrs }
}
return inline
if (isPlainObject(attrs)) {
const { data, isVoid, key, type } = attrs
let { nodes } = attrs
if (typeof type != 'string') {
throw new Error('`Inline.create` requires a block `type` string.')
}
if (nodes == null || nodes.length == 0) {
nodes = [Text.create()]
}
const inline = new Inline({
data: Data.create(data),
isVoid: !!isVoid,
key: key || generateKey(),
nodes: Node.createList(nodes),
type,
})
return inline
}
throw new Error(`\`Inline.create\` only accepts objects, strings or inlines, but you passed it: ${attrs}`)
}
/**
* Create a list of `Inlines` from an array.
*
* @param {Array<Object|Inline>} elements
* @param {Array<Inline|Object>|List<Inline|Object>} elements
* @return {List<Inline>}
*/
static createList(elements = []) {
if (List.isList(elements)) return elements
return new List(elements.map(Inline.create))
if (List.isList(elements) || Array.isArray(elements)) {
const list = new List(elements.map(Inline.create))
return list
}
throw new Error(`\`Inline.createList\` only accepts arrays or lists, but you passed it: ${elements}`)
}
/**
@@ -102,7 +119,7 @@ class Inline extends new Record(DEFAULTS) {
}
/**
* Is the node empty?
* Check if the inline is empty.
*
* @return {Boolean}
*/
@@ -112,7 +129,7 @@ class Inline extends new Record(DEFAULTS) {
}
/**
* Get the concatenated text `string` of all child nodes.
* Get the concatenated text of all the inline's children.
*
* @return {String}
*/

View File

@@ -1,7 +1,8 @@
import Data from './data'
import memoize from '../utils/memoize'
import MODEL_TYPES from '../constants/model-types'
import Data from './data'
import isPlainObject from 'is-plain-object'
import memoize from '../utils/memoize'
import { Map, Record, Set } from 'immutable'
/**
@@ -12,7 +13,7 @@ import { Map, Record, Set } from 'immutable'
const DEFAULTS = {
data: new Map(),
type: null
type: undefined,
}
/**
@@ -21,7 +22,7 @@ const DEFAULTS = {
* @type {Mark}
*/
class Mark extends new Record(DEFAULTS) {
class Mark extends Record(DEFAULTS) {
/**
* Create a new `Mark` with `attrs`.
@@ -31,18 +32,30 @@ class Mark extends new Record(DEFAULTS) {
*/
static create(attrs = {}) {
if (Mark.isMark(attrs)) return attrs
if (!attrs.type) {
throw new Error(`You must provide \`attrs.type\` to \`Mark.create(attrs)\`.`)
if (Mark.isMark(attrs)) {
return attrs
}
const mark = new Mark({
type: attrs.type,
data: Data.create(attrs.data),
})
if (typeof attrs == 'string') {
attrs = { type: attrs }
}
return mark
if (isPlainObject(attrs)) {
const { data, type } = attrs
if (typeof type != 'string') {
throw new Error('`Mark.create` requires a mark `type` string.')
}
const mark = new Mark({
type,
data: Data.create(data),
})
return mark
}
throw new Error(`\`Mark.create\` only accepts objects, strings or marks, but you passed it: ${attrs}`)
}
/**
@@ -53,11 +66,7 @@ class Mark extends new Record(DEFAULTS) {
*/
static createSet(elements) {
if (Set.isSet(elements)) {
return elements
}
if (Array.isArray(elements)) {
if (Set.isSet(elements) || Array.isArray(elements)) {
const marks = new Set(elements.map(Mark.create))
return marks
}
@@ -66,7 +75,36 @@ class Mark extends new Record(DEFAULTS) {
return new Set()
}
throw new Error(`Mark.createSet() must be passed an \`Array\`, a \`List\` or \`null\`. You passed: ${elements}`)
throw new Error(`\`Mark.createSet\` only accepts sets, arrays or null, but you passed it: ${elements}`)
}
/**
* Create a dictionary of settable mark properties from `attrs`.
*
* @param {Object|String|Mark} attrs
* @return {Object}
*/
static createProperties(attrs = {}) {
if (Mark.isMark(attrs)) {
return {
data: attrs.data,
type: attrs.type,
}
}
if (typeof attrs == 'string') {
return { type: attrs }
}
if (isPlainObject(attrs)) {
const props = {}
if ('type' in attrs) props.type = attrs.type
if ('data' in attrs) props.data = Data.create(attrs.data)
return props
}
throw new Error(`\`Mark.createProperties\` only accepts objects, strings or marks, but you passed it: ${attrs}`)
}
/**

View File

@@ -1,12 +1,13 @@
import Block from './block'
import Data from './data'
import Document from './document'
import Inline from './inline'
import Normalize from '../utils/normalize'
import Text from './text'
import direction from 'direction'
import generateKey from '../utils/generate-key'
import isInRange from '../utils/is-in-range'
import isPlainObject from 'is-plain-object'
import logger from '../utils/logger'
import memoize from '../utils/memoize'
import { List, OrderedSet, Set } from 'immutable'
@@ -30,20 +31,23 @@ class Node {
*/
static create(attrs = {}) {
if (Block.isBlock(attrs)) return attrs
if (Document.isDocument(attrs)) return attrs
if (Inline.isInline(attrs)) return attrs
if (Text.isText(attrs)) return attrs
if (Node.isNode(attrs)) {
return attrs
}
switch (attrs.kind) {
case 'block': return Block.create(attrs)
case 'document': return Document.create(attrs)
case 'inline': return Inline.create(attrs)
case 'text': return Text.create(attrs)
default: {
throw new Error(`You must pass a \`kind\` attribute to create a \`Node\`.`)
if (isPlainObject(attrs)) {
switch (attrs.kind) {
case 'block': return Block.create(attrs)
case 'document': return Document.create(attrs)
case 'inline': return Inline.create(attrs)
case 'text': return Text.create(attrs)
default: {
throw new Error('`Node.create` requires a `kind` string.')
}
}
}
throw new Error(`\`Node.create\` only accepts objects or nodes but you passed it: ${attrs}`)
}
/**
@@ -54,16 +58,43 @@ class Node {
*/
static createList(elements = []) {
if (List.isList(elements)) {
return elements
}
if (Array.isArray(elements)) {
if (List.isList(elements) || Array.isArray(elements)) {
const list = new List(elements.map(Node.create))
return list
}
throw new Error(`Node.createList() must be passed an \`Array\` or a \`List\`. You passed: ${elements}`)
throw new Error(`\`Node.createList\` only accepts lists or arrays, but you passed it: ${elements}`)
}
/**
* Create a dictionary of settable node properties from `attrs`.
*
* @param {Object|String|Node} attrs
* @return {Object}
*/
static createProperties(attrs = {}) {
if (Block.isBlock(attrs) || Inline.isInline(attrs)) {
return {
data: attrs.data,
isVoid: attrs.isVoid,
type: attrs.type,
}
}
if (typeof attrs == 'string') {
return { type: attrs }
}
if (isPlainObject(attrs)) {
const props = {}
if ('type' in attrs) props.type = attrs.type
if ('data' in attrs) props.data = Data.create(attrs.data)
if ('isVoid' in attrs) props.isVoid = attrs.isVoid
return props
}
throw new Error(`\`Node.createProperties\` only accepts objects, strings, blocks or inlines, but you passed it: ${attrs}`)
}
/**
@@ -92,8 +123,8 @@ class Node {
*/
areDescendantsSorted(first, second) {
first = Normalize.key(first)
second = Normalize.key(second)
first = normalizeKey(first)
second = normalizeKey(second)
let sorted
@@ -121,7 +152,7 @@ class Node {
const child = this.getChild(key)
if (!child) {
key = Normalize.key(key)
key = normalizeKey(key)
throw new Error(`Could not find a child node with key "${key}".`)
}
@@ -139,7 +170,7 @@ class Node {
const descendant = this.getDescendant(key)
if (!descendant) {
key = Normalize.key(key)
key = normalizeKey(key)
throw new Error(`Could not find a descendant node with key "${key}".`)
}
@@ -157,7 +188,7 @@ class Node {
const node = this.getNode(key)
if (!node) {
key = Normalize.key(key)
key = normalizeKey(key)
throw new Error(`Could not find a node with key "${key}".`)
}
@@ -251,7 +282,7 @@ class Node {
*/
getAncestors(key) {
key = Normalize.key(key)
key = normalizeKey(key)
if (key == this.key) return List()
if (this.hasChild(key)) return List([this])
@@ -428,7 +459,7 @@ class Node {
*/
getChild(key) {
key = Normalize.key(key)
key = normalizeKey(key)
return this.nodes.find(node => node.key == key)
}
@@ -441,7 +472,7 @@ class Node {
*/
getClosest(key, iterator) {
key = Normalize.key(key)
key = normalizeKey(key)
const ancestors = this.getAncestors(key)
if (!ancestors) {
throw new Error(`Could not find a descendant node with key "${key}".`)
@@ -493,8 +524,8 @@ class Node {
*/
getCommonAncestor(one, two) {
one = Normalize.key(one)
two = Normalize.key(two)
one = normalizeKey(one)
two = normalizeKey(two)
if (one == this.key) return this
if (two == this.key) return this
@@ -562,7 +593,7 @@ class Node {
*/
getDescendant(key) {
key = Normalize.key(key)
key = normalizeKey(key)
let descendantFound = null
const found = this.nodes.find((node) => {
@@ -710,7 +741,7 @@ class Node {
getFurthest(key, iterator) {
const ancestors = this.getAncestors(key)
if (!ancestors) {
key = Normalize.key(key)
key = normalizeKey(key)
throw new Error(`Could not find a descendant node with key "${key}".`)
}
@@ -748,7 +779,7 @@ class Node {
*/
getFurthestAncestor(key) {
key = Normalize.key(key)
key = normalizeKey(key)
return this.nodes.find((node) => {
if (node.key == key) return true
if (node.kind == 'text') return false
@@ -767,7 +798,7 @@ class Node {
const ancestors = this.getAncestors(key)
if (!ancestors) {
key = Normalize.key(key)
key = normalizeKey(key)
throw new Error(`Could not find a descendant node with key "${key}".`)
}
@@ -1111,7 +1142,7 @@ class Node {
*/
getNextSibling(key) {
key = Normalize.key(key)
key = normalizeKey(key)
const parent = this.getParent(key)
const after = parent.nodes
@@ -1131,7 +1162,7 @@ class Node {
*/
getNextText(key) {
key = Normalize.key(key)
key = normalizeKey(key)
return this.getTexts()
.skipUntil(text => text.key == key)
.get(1)
@@ -1145,7 +1176,7 @@ class Node {
*/
getNode(key) {
key = Normalize.key(key)
key = normalizeKey(key)
return this.key == key ? this : this.getDescendant(key)
}
@@ -1277,7 +1308,7 @@ class Node {
*/
getPreviousSibling(key) {
key = Normalize.key(key)
key = normalizeKey(key)
const parent = this.getParent(key)
const before = parent.nodes
.takeUntil(child => child.key == key)
@@ -1297,7 +1328,7 @@ class Node {
*/
getPreviousText(key) {
key = Normalize.key(key)
key = normalizeKey(key)
return this.getTexts()
.takeUntil(text => text.key == key)
.last()
@@ -1611,7 +1642,7 @@ class Node {
*/
removeDescendant(key) {
key = Normalize.key(key)
key = normalizeKey(key)
let node = this
let parent = node.getParent(key)
@@ -1872,6 +1903,25 @@ class Node {
}
/**
* Normalize a key argument `value`.
*
* @param {String|Node} value
* @return {String}
*/
function normalizeKey(value) {
if (typeof value == 'string') return value
logger.deprecate('0.14.0', 'An object was passed to a Node method instead of a `key` string. This was previously supported, but is being deprecated because it can have a negative impact on performance. The object in question was:', value)
if (Node.isNode(value)) {
return value.key
}
throw new Error(`Invalid \`key\` argument! It must be either a block, an inline, a text, or a string. You passed: ${value}`)
}
/**
* Memoize read methods.
*/

View File

@@ -1,7 +1,8 @@
import MODEL_TYPES from '../constants/model-types'
import Character from './character'
import Mark from './mark'
import MODEL_TYPES from '../constants/model-types'
import isPlainObject from 'is-plain-object'
import { Record, Set } from 'immutable'
/**
@@ -21,7 +22,7 @@ const DEFAULTS = {
* @type {Range}
*/
class Range extends new Record(DEFAULTS) {
class Range extends Record(DEFAULTS) {
/**
* Create a new `Range` with `attrs`.
@@ -31,14 +32,25 @@ class Range extends new Record(DEFAULTS) {
*/
static create(attrs = {}) {
if (Range.isRange(attrs)) return attrs
if (Range.isRange(attrs)) {
return attrs
}
const range = new Range({
text: attrs.text,
marks: Mark.createSet(attrs.marks),
})
if (typeof attrs == 'string') {
attrs = { text: attrs }
}
return range
if (isPlainObject(attrs)) {
const { marks, text } = attrs
const range = new Range({
text,
marks: Mark.createSet(marks),
})
return range
}
throw new Error(`\`Range.create\` only accepts objects, strings or ranges, but you passed it: ${attrs}`)
}
/**

View File

@@ -2,6 +2,7 @@
import MODEL_TYPES from '../constants/model-types'
import React from 'react'
import find from 'lodash/find'
import isPlainObject from 'is-plain-object'
import isReactComponent from '../utils/is-react-component'
import logger from '../utils/logger'
import typeOf from 'type-of'
@@ -23,7 +24,7 @@ const DEFAULTS = {
* @type {Schema}
*/
class Schema extends new Record(DEFAULTS) {
class Schema extends Record(DEFAULTS) {
/**
* Create a new `Schema` with `attrs`.
@@ -33,9 +34,16 @@ class Schema extends new Record(DEFAULTS) {
*/
static create(attrs = {}) {
if (Schema.isSchema(attrs)) return attrs
const schema = new Schema(normalizeProperties(attrs))
return schema
if (Schema.isSchema(attrs)) {
return attrs
}
if (isPlainObject(attrs)) {
const schema = new Schema(normalizeProperties(attrs))
return schema
}
throw new Error(`\`Schema.create\` only accepts objects or schemas, but you passed it: ${attrs}`)
}
/**

View File

@@ -1,6 +1,7 @@
import logger from '../utils/logger'
import MODEL_TYPES from '../constants/model-types'
import isPlainObject from 'is-plain-object'
import logger from '../utils/logger'
import { Record } from 'immutable'
/**
@@ -25,7 +26,7 @@ const DEFAULTS = {
* @type {Selection}
*/
class Selection extends new Record(DEFAULTS) {
class Selection extends Record(DEFAULTS) {
/**
* Create a new `Selection` with `attrs`.
@@ -35,9 +36,51 @@ class Selection extends new Record(DEFAULTS) {
*/
static create(attrs = {}) {
if (Selection.isSelection(attrs)) return attrs
const selection = new Selection(attrs)
return selection
if (Selection.isSelection(attrs)) {
return attrs
}
if (isPlainObject(attrs)) {
const selection = new Selection(attrs)
return selection
}
throw new Error(`\`Selection.create\` only accepts objects or selections, but you passed it: ${attrs}`)
}
/**
* Create a dictionary of settable selection properties from `attrs`.
*
* @param {Object|String|Selection} attrs
* @return {Object}
*/
static createProperties(attrs = {}) {
if (Selection.isSelection(attrs)) {
return {
anchorKey: attrs.anchorKey,
anchorOffset: attrs.anchorOffset,
focusKey: attrs.focusKey,
focusOffset: attrs.focusOffset,
isBackward: attrs.isBackward,
isFocused: attrs.isFocused,
marks: attrs.marks,
}
}
if (isPlainObject(attrs)) {
const props = {}
if ('anchorKey' in attrs) props.anchorKey = attrs.anchorKey
if ('anchorOffset' in attrs) props.anchorOffset = attrs.anchorOffset
if ('focusKey' in attrs) props.focusKey = attrs.focusKey
if ('focusOffset' in attrs) props.focusOffset = attrs.focusOffset
if ('isBackward' in attrs) props.isBackward = attrs.isBackward
if ('isFocused' in attrs) props.isFocused = attrs.isFocused
if ('marks' in attrs) props.marks = attrs.marks
return props
}
throw new Error(`\`Selection.createProperties\` only accepts objects or selections, but you passed it: ${attrs}`)
}
/**

View File

@@ -51,7 +51,7 @@ const DEFAULTS = {
* @type {Stack}
*/
class Stack extends new Record(DEFAULTS) {
class Stack extends Record(DEFAULTS) {
/**
* Constructor.

View File

@@ -5,6 +5,7 @@ import Change from './change'
import Document from './document'
import History from './history'
import Selection from './selection'
import isPlainObject from 'is-plain-object'
import logger from '../utils/logger'
import { Record, Set, List, Map } from 'immutable'
@@ -15,11 +16,11 @@ import { Record, Set, List, Map } from 'immutable'
*/
const DEFAULTS = {
document: new Document(),
selection: new Selection(),
history: new History(),
document: Document.create(),
selection: Selection.create(),
history: History.create(),
data: new Map(),
isNative: false
isNative: false,
}
/**
@@ -28,7 +29,7 @@ const DEFAULTS = {
* @type {State}
*/
class State extends new Record(DEFAULTS) {
class State extends Record(DEFAULTS) {
/**
* Create a new `State` with `attrs`.
@@ -40,37 +41,43 @@ class State extends new Record(DEFAULTS) {
*/
static create(attrs = {}, options = {}) {
if (State.isState(attrs)) return attrs
const document = Document.create(attrs.document)
let selection = Selection.create(attrs.selection)
let data = new Map()
if (selection.isUnset) {
const text = document.getFirstText()
if (text) selection = selection.collapseToStartOf(text)
if (State.isState(attrs)) {
return attrs
}
// Set default value for `data`.
if (options.plugins) {
for (const plugin of options.plugins) {
if (plugin.data) data = data.merge(plugin.data)
if (isPlainObject(attrs)) {
const document = Document.create(attrs.document)
let selection = Selection.create(attrs.selection)
let data = new Map()
if (selection.isUnset) {
const text = document.getFirstText()
if (text) selection = selection.collapseToStartOf(text)
}
// Set default value for `data`.
if (options.plugins) {
for (const plugin of options.plugins) {
if (plugin.data) data = data.merge(plugin.data)
}
}
// Then add data provided in `attrs`.
if (attrs.data) data = data.merge(attrs.data)
let state = new State({ document, selection, data })
if (options.normalize !== false) {
state = state
.change({ save: false })
.normalize(SCHEMA)
.state
}
return state
}
// Then add data provided in `attrs`.
if (attrs.data) data = data.merge(attrs.data)
let state = new State({ document, selection, data })
if (options.normalize !== false) {
state = state
.change({ save: false })
.normalize(SCHEMA)
.state
}
return state
throw new Error(`\`State.create\` only accepts objects or states, but you passed it: ${attrs}`)
}
/**

View File

@@ -3,9 +3,11 @@ import Character from './character'
import Mark from './mark'
import Range from './range'
import MODEL_TYPES from '../constants/model-types'
import memoize from '../utils/memoize'
import generateKey from '../utils/generate-key'
import { List, Record, OrderedSet, Set, is } from 'immutable'
import isPlainObject from 'is-plain-object'
import logger from '../utils/logger'
import memoize from '../utils/memoize'
import { List, Record, OrderedSet, is } from 'immutable'
/**
* Default properties.
@@ -15,7 +17,7 @@ import { List, Record, OrderedSet, Set, is } from 'immutable'
const DEFAULTS = {
characters: new List(),
key: null
key: undefined,
}
/**
@@ -24,57 +26,45 @@ const DEFAULTS = {
* @type {Text}
*/
class Text extends new Record(DEFAULTS) {
class Text extends Record(DEFAULTS) {
/**
* Create a new `Text` with `attrs`.
*
* @param {Object|Text} attrs
* @param {Object|Array|List|String|Text} attrs
* @return {Text}
*/
static create(attrs = {}) {
if (Text.isText(attrs)) return attrs
if (attrs.ranges) return Text.createFromRanges(attrs.ranges)
if (Text.isText(attrs)) {
return attrs
}
const text = new Text({
characters: Character.createList(attrs.characters),
key: attrs.key || generateKey(),
})
if (List.isList(attrs) || Array.isArray(attrs)) {
attrs = { ranges: attrs }
}
return text
}
if (typeof attrs == 'string') {
attrs = { ranges: [{ text: attrs }] }
}
/**
* Create a new `Text` from a string
*
* @param {String} text
* @param {Set<Mark>} marks (optional)
* @return {Text}
*/
if (isPlainObject(attrs)) {
const { characters, ranges, key } = attrs
const chars = ranges
? ranges
.map(Range.create)
.reduce((l, r) => l.concat(r.getCharacters()), Character.createList())
: Character.createList(characters)
static createFromString(string, marks = Set()) {
const range = Range.create({ text: string, marks })
const text = Text.createFromRanges([range])
return text
}
const text = new Text({
characters: chars,
key: key || generateKey(),
})
/**
* Create a new `Text` from a list of ranges
*
* @param {List<Range>|Array<Range>} ranges
* @return {Text}
*/
return text
}
static createFromRanges(ranges) {
const characters = ranges
.map(Range.create)
.reduce((list, range) => {
return list.concat(range.getCharacters())
}, Character.createList())
const text = Text.create({ characters })
return text
throw new Error(`\`Text.create\` only accepts objects, arrays, strings or texts, but you passed it: ${attrs}`)
}
/**
@@ -104,6 +94,24 @@ class Text extends new Record(DEFAULTS) {
return !!(value && value[MODEL_TYPES.TEXT])
}
/**
* Deprecated.
*/
static createFromString(string) {
logger.deprecate('0.22.0', 'The `Text.createFromString(string)` method is deprecated, use `Text.create(string)` instead.')
return Text.create(string)
}
/**
* Deprecated.
*/
static createFromRanges(ranges) {
logger.deprecate('0.22.0', 'The `Text.createFromRanges(ranges)` method is deprecated, use `Text.create(ranges)` instead.')
return Text.create(ranges)
}
/**
* Get the node's kind.
*
@@ -319,7 +327,7 @@ class Text extends new Record(DEFAULTS) {
insertText(index, text, marks) {
let { characters } = this
const chars = Character.createListFromText(text, marks)
const chars = Character.createList(text.split('').map(char => ({ text: char, marks })))
characters = characters.slice(0, index)
.concat(chars)

View File

@@ -1,6 +1,7 @@
import Debug from 'debug'
import Normalize from '../utils/normalize'
import Node from '../models/node'
import Mark from '../models/mark'
import logger from '../utils/logger'
/**
@@ -29,7 +30,7 @@ const APPLIERS = {
add_mark(state, operation) {
const { path, offset, length } = operation
const mark = Normalize.mark(operation.mark)
const mark = Mark.create(operation.mark)
let { document } = state
let node = document.assertPath(path)
node = node.addMark(offset, length, mark)
@@ -48,7 +49,7 @@ const APPLIERS = {
insert_node(state, operation) {
const { path } = operation
const node = Normalize.node(operation.node)
const node = Node.create(operation.node)
const index = path[path.length - 1]
const rest = path.slice(0, -1)
let { document } = state
@@ -71,7 +72,7 @@ const APPLIERS = {
const { path, offset, text } = operation
let { marks } = operation
if (Array.isArray(marks)) marks = Normalize.marks(marks)
if (Array.isArray(marks)) marks = Mark.createSet(marks)
let { document, selection } = state
const { anchorKey, focusKey, anchorOffset, focusOffset } = selection
@@ -207,7 +208,7 @@ const APPLIERS = {
remove_mark(state, operation) {
const { path, offset, length } = operation
const mark = Normalize.mark(operation.mark)
const mark = Mark.create(operation.mark)
let { document } = state
let node = document.assertPath(path)
node = node.removeMark(offset, length, mark)
@@ -341,7 +342,7 @@ const APPLIERS = {
set_mark(state, operation) {
const { path, offset, length, properties } = operation
const mark = Normalize.mark(operation.mark)
const mark = Mark.create(operation.mark)
let { document } = state
let node = document.assertPath(path)
node = node.updateMark(offset, length, mark, properties)
@@ -393,8 +394,8 @@ const APPLIERS = {
const properties = { ...operation.properties }
let { document, selection } = state
if (properties.marks !== undefined) {
properties.marks = Normalize.marks(properties.marks)
if (properties.marks != null) {
properties.marks = Mark.createSet(properties.marks)
}
if (properties.anchorPath !== undefined) {

View File

@@ -125,7 +125,7 @@ const rules = [
return node.text !== ' ' || node.nodes.size !== 1
},
normalize: (change, node, result) => {
const text = Text.createFromString(' ')
const text = Text.create(' ')
const index = node.nodes.size
change.insertNodeByKey(node.key, index, text, OPTS)

View File

@@ -1,351 +0,0 @@
import Block from '../models/block'
import Document from '../models/document'
import Inline from '../models/inline'
import Data from '../models/data'
import Mark from '../models/mark'
import Selection from '../models/selection'
import Text from '../models/text'
import logger from './logger'
import typeOf from 'type-of'
import { Set } from 'immutable'
/**
* Normalize a block argument `value`.
*
* @param {Block|String|Object} value
* @return {Block}
*/
function block(value) {
if (Block.isBlock(value)) return value
if (
Inline.isInline(value) ||
Mark.isMark(value) ||
Text.isText(value) ||
Selection.isSelection(value)
) {
throw new Error(`Invalid \`block\` argument! It must be a block, an object, or a string. You passed: ${value}`)
}
switch (typeOf(value)) {
case 'string':
case 'object': {
return Block.create(nodeProperties(value))
}
default: {
throw new Error(`Invalid \`block\` argument! It must be a block, an object, or a string. You passed: ${value}`)
}
}
}
/**
* Normalize an inline argument `value`.
*
* @param {Inline|String|Object} value
* @return {Inline}
*/
function inline(value) {
if (Inline.isInline(value)) return value
if (
Block.isBlock(value) ||
Mark.isMark(value) ||
Text.isText(value) ||
Selection.isSelection(value)
) {
throw new Error(`Invalid \`inline\` argument! It must be an inline, an object, or a string. You passed: ${value}`)
}
switch (typeOf(value)) {
case 'string':
case 'object': {
return Inline.create(nodeProperties(value))
}
default: {
throw new Error(`Invalid \`inline\` argument! It must be an inline, an object, or a string. You passed: ${value}`)
}
}
}
/**
* Normalize an text argument `value`.
*
* @param {Text|String|Object} value
* @return {Text}
*/
function text(value) {
if (Text.isText(value)) return value
if (
Block.isBlock(value) ||
Inline.isInline(value) ||
Mark.isMark(value) ||
Selection.isSelection(value)
) {
throw new Error(`Invalid \`text\` argument! It must be a text, an object, or a string. You passed: ${value}`)
}
switch (typeOf(value)) {
case 'object': {
return Text.create(value)
}
default: {
throw new Error(`Invalid \`text\` argument! It must be an text, an object, or a string. You passed: ${value}`)
}
}
}
/**
* Normalize a node `value`.
*
* @param {Node|Object} value
* @return {Node}
*/
function node(value) {
if (Block.isBlock(value)) return value
if (Document.isDocument(value)) return value
if (Inline.isInline(value)) return value
if (Text.isText(value)) return value
switch (typeOf(value)) {
case 'object': {
switch (value.kind) {
case 'block': return block(value)
case 'inline': return inline(value)
case 'text': return text(value)
default: {
throw new Error(`Invalid \`node.kind\` property. It must be either "block" or "inline". You passed: ${value}`)
}
}
}
default: {
throw new Error(`Invalid \`node\` argument! It must be a block, an inline, a text, or an object. You passed: ${value}`)
}
}
}
/**
* Normalize a key argument `value`.
*
* @param {String|Node} value
* @return {String}
*/
function key(value) {
if (typeOf(value) == 'string') return value
logger.warn('An object was passed to a Node method instead of a `key` string. This was previously supported, but is being deprecated because it can have a negative impact on performance. The object in question was:', value)
if (
Block.isBlock(value) ||
Document.isDocument(value) ||
Inline.isInline(value) ||
Text.isText(value)
) {
return value.key
}
throw new Error(`Invalid \`key\` argument! It must be either a block, an inline, a text, or a string. You passed: ${value}`)
}
/**
* Normalize a mark argument `value`.
*
* @param {Mark|String|Object} value
* @return {Mark}
*/
function mark(value) {
if (Mark.isMark(value)) return value
if (
Block.isBlock(value) ||
Inline.isInline(value) ||
Text.isText(value) ||
Selection.isSelection(value)
) {
throw new Error(`Invalid \`mark\` argument! It must be a mark, an object, or a string. You passed: ${value}`)
}
switch (typeOf(value)) {
case 'string':
case 'object': {
return Mark.create(markProperties(value))
}
default: {
throw new Error(`Invalid \`mark\` argument! It must be a mark, an object, or a string. You passed: ${value}`)
}
}
}
/**
* Normalize a set of marks argument `values`.
*
* @param {Set<Marks>|Array} values
* @return {Set<Marks>}
*/
function marks(values) {
if (Set.isSet(values)) return values
switch (typeOf(values)) {
case 'array': {
return Mark.createSet(values)
}
case 'null': {
return null
}
default: {
throw new Error(`Invalid \`marks\` argument! It must be a set of marks or an array. You passed: ${values}`)
}
}
}
/**
* Normalize a mark properties argument `value`.
*
* @param {String|Object|Mark} value
* @return {Object}
*/
function markProperties(value = {}) {
const ret = {}
switch (typeOf(value)) {
case 'string': {
ret.type = value
break
}
case 'object': {
for (const k in value) {
if (k == 'data') {
if (value[k] !== undefined) ret[k] = Data.create(value[k])
} else if (!k.startsWith('@@__SLATE')) {
ret[k] = value[k]
}
}
break
}
default: {
throw new Error(`Invalid mark \`properties\` argument! It must be an object, a string or a mark. You passed: ${value}`)
}
}
return ret
}
/**
* Normalize a node properties argument `value`.
*
* @param {String|Object|Node} value
* @return {Object}
*/
function nodeProperties(value = {}) {
const ret = {}
switch (typeOf(value)) {
case 'string': {
ret.type = value
break
}
case 'object': {
if (value.isVoid !== undefined) ret.isVoid = !!value.isVoid
for (const k in value) {
if (k == 'data') {
if (value[k] !== undefined) ret[k] = Data.create(value[k])
} else if (!k.startsWith('@@__SLATE')) {
ret[k] = value[k]
}
}
break
}
default: {
throw new Error(`Invalid node \`properties\` argument! It must be an object, a string or a node. You passed: ${value}`)
}
}
return ret
}
/**
* Normalize a selection argument `value`.
*
* @param {Selection|Object} value
* @return {Selection}
*/
function selection(value) {
if (Selection.isSelection(value)) return value
if (
Mark.isMark(value) ||
Block.isBlock(value) ||
Inline.isInline(value) ||
Text.isText(value)
) {
throw new Error(`Invalid \`selection\` argument! It must be a selection or an object. You passed: ${value}`)``
}
switch (typeOf(value)) {
case 'object': {
return Selection.create(value)
}
default: {
throw new Error(`Invalid \`selection\` argument! It must be a selection or an object. You passed: ${value}`)
}
}
}
/**
* Normalize a selection properties argument `value`.
*
* @param {Object|Selection} value
* @return {Object}
*/
function selectionProperties(value = {}) {
const ret = {}
switch (typeOf(value)) {
case 'object': {
if (value.anchorKey !== undefined) ret.anchorKey = value.anchorKey
if (value.anchorOffset !== undefined) ret.anchorOffset = value.anchorOffset
if (value.focusKey !== undefined) ret.focusKey = value.focusKey
if (value.focusOffset !== undefined) ret.focusOffset = value.focusOffset
if (value.isBackward !== undefined) ret.isBackward = !!value.isBackward
if (value.isFocused !== undefined) ret.isFocused = !!value.isFocused
if (value.marks !== undefined) ret.marks = value.marks
break
}
default: {
throw new Error(`Invalid selection \`properties\` argument! It must be an object or a selection. You passed: ${value}`)
}
}
return ret
}
/**
* Export.
*
* @type {Object}
*/
export default {
block,
inline,
node,
key,
mark,
marks,
markProperties,
nodeProperties,
selection,
selectionProperties,
text,
}

View File

@@ -3251,6 +3251,12 @@ is-path-inside@^1.0.0:
dependencies:
path-is-inside "^1.0.1"
is-plain-object@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
dependencies:
isobject "^3.0.1"
is-posix-bracket@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
@@ -3329,6 +3335,10 @@ isobject@^2.0.0:
dependencies:
isarray "1.0.0"
isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"