mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-11 17:53:59 +02:00
refactor schema transform logic
This commit is contained in:
@@ -5,6 +5,7 @@ This directory contains the core logic of Slate. It's separated further into a s
|
|||||||
- [**Constants**](./constants) — containing constants that are used in Slate's codebase.
|
- [**Constants**](./constants) — containing constants that are used in Slate's codebase.
|
||||||
- [**Models**](./models) — containing the models that define Slate's internal data structure.
|
- [**Models**](./models) — containing the models that define Slate's internal data structure.
|
||||||
- [**Plugins**](./plugins) — containing the plugins that ship with Slate by default.
|
- [**Plugins**](./plugins) — containing the plugins that ship with Slate by default.
|
||||||
|
- [**Schemas**](./schemas) - containing the schemas that ship with Slate by default.
|
||||||
- [**Serializers**](./serializers) — containing the serializers that ship with Slate by default.
|
- [**Serializers**](./serializers) — containing the serializers that ship with Slate by default.
|
||||||
- [**Transforms**](./transforms) — containing the transforms that are used to alter a Slate document.
|
- [**Transforms**](./transforms) — containing the transforms that are used to alter a Slate document.
|
||||||
- [**Utils**](./utils) — containing a few private convenience modules.
|
- [**Utils**](./utils) — containing a few private convenience modules.
|
||||||
|
@@ -85,6 +85,24 @@ const Node = {
|
|||||||
return descendant
|
return descendant
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert that a node's tree has a node by `key` and return it.
|
||||||
|
*
|
||||||
|
* @param {String} key
|
||||||
|
* @return {Node}
|
||||||
|
*/
|
||||||
|
|
||||||
|
assertNode(key) {
|
||||||
|
const node = this.getNode(key)
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
key = Normalize.key(key)
|
||||||
|
throw new Error(`Could not find a node with key "${key}".`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assert that a node exists at `path` and return it.
|
* Assert that a node exists at `path` and return it.
|
||||||
*
|
*
|
||||||
@@ -137,10 +155,11 @@ const Node = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
findDescendant(iterator) {
|
findDescendant(iterator) {
|
||||||
const found = this.nodes.find(iterator)
|
const childFound = this.nodes.find(iterator)
|
||||||
if (found) return found
|
if (childFound) return childFound
|
||||||
|
|
||||||
let descendantFound = null
|
let descendantFound = null
|
||||||
|
|
||||||
this.nodes.find(node => {
|
this.nodes.find(node => {
|
||||||
if (node.kind != 'text') {
|
if (node.kind != 'text') {
|
||||||
descendantFound = node.findDescendant(iterator)
|
descendantFound = node.findDescendant(iterator)
|
||||||
@@ -765,6 +784,18 @@ const Node = {
|
|||||||
.get(1)
|
.get(1)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a node in the tree by `key`.
|
||||||
|
*
|
||||||
|
* @param {String} key
|
||||||
|
* @return {Node|Null}
|
||||||
|
*/
|
||||||
|
|
||||||
|
getNode(key) {
|
||||||
|
key = Normalize.key(key)
|
||||||
|
return this.key == key ? this : this.getDescendant(key)
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the offset for a descendant text node by `key`.
|
* Get the offset for a descendant text node by `key`.
|
||||||
*
|
*
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import Document from './document'
|
import Document from './document'
|
||||||
|
import SCHEMA from '../schemas/core'
|
||||||
import Selection from './selection'
|
import Selection from './selection'
|
||||||
import Transform from './transform'
|
import Transform from './transform'
|
||||||
import { Record, Set, Stack, List } from 'immutable'
|
import { Record, Set, Stack, List } from 'immutable'
|
||||||
@@ -57,7 +58,7 @@ class State extends new Record(DEFAULTS) {
|
|||||||
|
|
||||||
const state = new State({ document, selection })
|
const state = new State({ document, selection })
|
||||||
return state.transform({ normalized: false })
|
return state.transform({ normalized: false })
|
||||||
.normalize()
|
.normalize(SCHEMA)
|
||||||
.apply({ save: false })
|
.apply({ save: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -53,7 +53,7 @@ function Plugin(options = {}) {
|
|||||||
if (prevState && state.document == prevState.document) return state
|
if (prevState && state.document == prevState.document) return state
|
||||||
|
|
||||||
const newState = state.transform()
|
const newState = state.transform()
|
||||||
.normalizeWith(schema)
|
.normalize(schema)
|
||||||
.apply({ save: false })
|
.apply({ save: false })
|
||||||
|
|
||||||
return newState
|
return newState
|
||||||
@@ -748,7 +748,7 @@ function Plugin(options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the core schema with rendering rules.
|
* Add default rendering rules to the schema.
|
||||||
*
|
*
|
||||||
* @type {Object}
|
* @type {Object}
|
||||||
*/
|
*/
|
||||||
|
2
src/schemas/Readme.md
Normal file
2
src/schemas/Readme.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
This directory contains the core schema that ships with Slate by default, which controls all of the "core" document and selection validation logic. For example, it ensures that two adjacent text nodes are always joined, or that the top-level document only ever contains block nodes. It is not exposed by default, since it is only needed internally.
|
@@ -290,12 +290,12 @@ function isInlineVoid(node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default schema.
|
* The core schema.
|
||||||
*
|
*
|
||||||
* @type {Schema}
|
* @type {Schema}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const schema = Schema.create({
|
const SCHEMA = Schema.create({
|
||||||
rules: [
|
rules: [
|
||||||
DOCUMENT_CHILDREN_RULE,
|
DOCUMENT_CHILDREN_RULE,
|
||||||
BLOCK_CHILDREN_RULE,
|
BLOCK_CHILDREN_RULE,
|
||||||
@@ -315,4 +315,4 @@ const schema = Schema.create({
|
|||||||
* @type {Schema}
|
* @type {Schema}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default schema
|
export default SCHEMA
|
@@ -1,7 +1,8 @@
|
|||||||
/* eslint no-console: 0 */
|
/* eslint no-console: 0 */
|
||||||
|
|
||||||
import { List } from 'immutable'
|
|
||||||
import Normalize from '../utils/normalize'
|
import Normalize from '../utils/normalize'
|
||||||
|
import SCHEMA from '../schemas/core'
|
||||||
|
import { List } from 'immutable'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new `mark` to the characters at `range`.
|
* Add a new `mark` to the characters at `range`.
|
||||||
@@ -109,10 +110,10 @@ export function deleteAtRange(transform, range, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform.normalizeNodeByKey(ancestor.key)
|
transform.normalizeNodeByKey(ancestor.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
transform.normalizeDocument()
|
transform.normalizeDocument(SCHEMA)
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
@@ -298,7 +299,7 @@ export function insertBlockAtRange(transform, range, block, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -393,7 +394,7 @@ export function insertFragmentAtRange(transform, range, fragment, options = {})
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -434,7 +435,7 @@ export function insertInlineAtRange(transform, range, inline, options = {}) {
|
|||||||
transform.insertNodeByKey(parent.key, index + 1, inline, { normalize: false })
|
transform.insertNodeByKey(parent.key, index + 1, inline, { normalize: false })
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -467,7 +468,7 @@ export function insertTextAtRange(transform, range, text, marks, options = {}) {
|
|||||||
transform.deleteAtRange(range, { normalize: false })
|
transform.deleteAtRange(range, { normalize: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unless specified, don't normalize if only inserting text
|
// PERF: Unless specified, don't normalize if only inserting text.
|
||||||
if (normalize !== undefined) {
|
if (normalize !== undefined) {
|
||||||
normalize = range.isExpanded
|
normalize = range.isExpanded
|
||||||
}
|
}
|
||||||
@@ -756,7 +757,7 @@ export function unwrapBlockAtRange(transform, range, properties, options = {}) {
|
|||||||
|
|
||||||
// TODO: optmize to only normalize the right block
|
// TODO: optmize to only normalize the right block
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform.normalizeDocument()
|
transform.normalizeDocument(SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -805,7 +806,7 @@ export function unwrapInlineAtRange(transform, range, properties, options = {})
|
|||||||
|
|
||||||
// TODO: optmize to only normalize the right block
|
// TODO: optmize to only normalize the right block
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform.normalizeDocument()
|
transform.normalizeDocument(SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -877,7 +878,7 @@ export function wrapBlockAtRange(transform, range, block, options = {}) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -955,7 +956,7 @@ export function wrapInlineAtRange(transform, range, inline, options = {}) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform.normalizeNodeByKey(startBlock.key)
|
transform.normalizeNodeByKey(startBlock.key, SCHEMA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -986,8 +987,8 @@ export function wrapInlineAtRange(transform, range, inline, options = {}) {
|
|||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform
|
transform
|
||||||
.normalizeNodeByKey(startBlock.key)
|
.normalizeNodeByKey(startBlock.key, SCHEMA)
|
||||||
.normalizeNodeByKey(endBlock.key)
|
.normalizeNodeByKey(endBlock.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks.slice(1, -1).forEach((block) => {
|
blocks.slice(1, -1).forEach((block) => {
|
||||||
@@ -999,7 +1000,7 @@ export function wrapInlineAtRange(transform, range, inline, options = {}) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform.normalizeNodeByKey(block.key)
|
transform.normalizeNodeByKey(block.key, SCHEMA)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
import Normalize from '../utils/normalize'
|
import Normalize from '../utils/normalize'
|
||||||
|
import SCHEMA from '../schemas/core'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add mark to text at `offset` and `length` in node by `key`.
|
* Add mark to text at `offset` and `length` in node by `key`.
|
||||||
@@ -21,9 +23,10 @@ export function addMarkByKey(transform, key, offset, length, mark, options = {})
|
|||||||
const path = document.getPath(key)
|
const path = document.getPath(key)
|
||||||
|
|
||||||
transform.addMarkOperation(path, offset, length, mark)
|
transform.addMarkOperation(path, offset, length, mark)
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getParent(key)
|
const parent = document.getParent(key)
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -48,8 +51,9 @@ export function insertNodeByKey(transform, key, index, node, options = {}) {
|
|||||||
const path = document.getPath(key)
|
const path = document.getPath(key)
|
||||||
|
|
||||||
transform.insertNodeOperation(path, index, node)
|
transform.insertNodeOperation(path, index, node)
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
transform.normalizeNodeByKey(key)
|
transform.normalizeNodeByKey(key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -75,9 +79,10 @@ export function insertTextByKey(transform, key, offset, text, marks, options = {
|
|||||||
const path = document.getPath(key)
|
const path = document.getPath(key)
|
||||||
|
|
||||||
transform.insertTextOperation(path, offset, text, marks)
|
transform.insertTextOperation(path, offset, text, marks)
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getParent(key)
|
const parent = document.getParent(key)
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -106,9 +111,9 @@ export function joinNodeByKey(transform, key, withKey, options = {}) {
|
|||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getCommonAncestor(key, withKey)
|
const parent = document.getCommonAncestor(key, withKey)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
} else {
|
} else {
|
||||||
transform.normalizeDocument()
|
transform.normalizeDocument(SCHEMA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +144,7 @@ export function moveNodeByKey(transform, key, newKey, newIndex, options = {}) {
|
|||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.key == newKey ? document : document.getCommonAncestor(key, newKey)
|
const parent = document.key == newKey ? document : document.getCommonAncestor(key, newKey)
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -166,9 +171,10 @@ export function removeMarkByKey(transform, key, offset, length, mark, options =
|
|||||||
const path = document.getPath(key)
|
const path = document.getPath(key)
|
||||||
|
|
||||||
transform.removeMarkOperation(path, offset, length, mark)
|
transform.removeMarkOperation(path, offset, length, mark)
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getParent(key)
|
const parent = document.getParent(key)
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -195,9 +201,9 @@ export function removeNodeByKey(transform, key, options = {}) {
|
|||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getParent(key)
|
const parent = document.getParent(key)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
} else {
|
} else {
|
||||||
transform.normalizeDocument()
|
transform.normalizeDocument(SCHEMA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,9 +229,10 @@ export function removeTextByKey(transform, key, offset, length, options = {}) {
|
|||||||
const path = document.getPath(key)
|
const path = document.getPath(key)
|
||||||
|
|
||||||
transform.removeTextOperation(path, offset, length)
|
transform.removeTextOperation(path, offset, length)
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getParent(key)
|
const parent = document.getParent(key)
|
||||||
transform.normalizeParentsByKey(parent.key)
|
transform.normalizeParentsByKey(parent.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -254,9 +261,10 @@ export function setMarkByKey(transform, key, offset, length, mark, properties, o
|
|||||||
const path = document.getPath(key)
|
const path = document.getPath(key)
|
||||||
|
|
||||||
transform.setMarkOperation(path, offset, length, mark, newMark)
|
transform.setMarkOperation(path, offset, length, mark, newMark)
|
||||||
|
|
||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getParent(key)
|
const parent = document.getParent(key)
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -285,9 +293,9 @@ export function setNodeByKey(transform, key, properties, options = {}) {
|
|||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getParent(key)
|
const parent = document.getParent(key)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
} else {
|
} else {
|
||||||
transform.normalizeDocument()
|
transform.normalizeDocument(SCHEMA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,9 +324,9 @@ export function splitNodeByKey(transform, key, offset, options = {}) {
|
|||||||
if (normalize) {
|
if (normalize) {
|
||||||
const parent = document.getParent(key)
|
const parent = document.getParent(key)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
transform.normalizeNodeByKey(parent.key)
|
transform.normalizeNodeByKey(parent.key, SCHEMA)
|
||||||
} else {
|
} else {
|
||||||
transform.normalizeDocument()
|
transform.normalizeDocument(SCHEMA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -148,9 +148,6 @@ import {
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
normalize,
|
normalize,
|
||||||
normalizeWith,
|
|
||||||
normalizeNodeWith,
|
|
||||||
normalizeParentsWith,
|
|
||||||
normalizeDocument,
|
normalizeDocument,
|
||||||
normalizeSelection,
|
normalizeSelection,
|
||||||
normalizeNodeByKey,
|
normalizeNodeByKey,
|
||||||
@@ -299,9 +296,6 @@ export default {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
normalize,
|
normalize,
|
||||||
normalizeWith,
|
|
||||||
normalizeNodeWith,
|
|
||||||
normalizeParentsWith,
|
|
||||||
normalizeDocument,
|
normalizeDocument,
|
||||||
normalizeSelection,
|
normalizeSelection,
|
||||||
normalizeNodeByKey,
|
normalizeNodeByKey,
|
||||||
|
@@ -1,78 +1,69 @@
|
|||||||
|
|
||||||
import Normalize from '../utils/normalize'
|
import Normalize from '../utils/normalize'
|
||||||
|
import Schema from '../models/schema'
|
||||||
import warn from '../utils/warn'
|
import warn from '../utils/warn'
|
||||||
import { default as coreSchema } from '../plugins/schema'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the document and selection with the core schema.
|
* Normalize the document and selection with a `schema`.
|
||||||
*
|
|
||||||
* @param {Transform} transform
|
|
||||||
* @return {Transform}
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function normalize(transform) {
|
|
||||||
return transform
|
|
||||||
.normalizeDocument()
|
|
||||||
.normalizeSelection()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalize the document with the core schema.
|
|
||||||
*
|
|
||||||
* @param {Transform} transform
|
|
||||||
* @return {Transform}
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function normalizeDocument(transform) {
|
|
||||||
return transform.normalizeWith(coreSchema)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalize state with a `schema`.
|
|
||||||
*
|
*
|
||||||
* @param {Transform} transform
|
* @param {Transform} transform
|
||||||
* @param {Schema} schema
|
* @param {Schema} schema
|
||||||
* @return {Transform}
|
* @return {Transform}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function normalizeWith(transform, schema) {
|
export function normalize(transform, schema) {
|
||||||
const { state } = transform
|
assertSchema(schema)
|
||||||
const { document } = state
|
|
||||||
|
return transform
|
||||||
|
.normalizeDocument(schema)
|
||||||
|
.normalizeSelection(schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize the document with a `schema`.
|
||||||
|
*
|
||||||
|
* @param {Transform} transform
|
||||||
|
* @param {Schema} schema
|
||||||
|
* @return {Transform}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function normalizeDocument(transform, schema) {
|
||||||
|
assertSchema(schema)
|
||||||
|
|
||||||
// If the schema has no validation rules, there's nothing to normalize.
|
// If the schema has no validation rules, there's nothing to normalize.
|
||||||
if (!schema.hasValidators) {
|
if (!schema.hasValidators) {
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform.normalizeNodeWith(schema, document)
|
const { state } = transform
|
||||||
|
const { document } = state
|
||||||
|
|
||||||
|
return normalizeNodeWith(transform, document, schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize a `node` and its children with a `schema`.
|
* Normalize a `node` and its children with a `schema`.
|
||||||
*
|
*
|
||||||
* @param {Transform} transform
|
* @param {Transform} transform
|
||||||
|
* @param {Node|String} key
|
||||||
* @param {Schema} schema
|
* @param {Schema} schema
|
||||||
* @param {Node} node
|
|
||||||
* @return {Transform}
|
* @return {Transform}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function normalizeNodeWith(transform, schema, node) {
|
export function normalizeNodeByKey(transform, key, schema) {
|
||||||
// For performance considerations, we will check if the transform was changed.
|
assertSchema(schema)
|
||||||
const opCount = transform.operations.length
|
key = Normalize.key(key)
|
||||||
|
|
||||||
// Iterate over its children.
|
// If the schema has no validation rules, there's nothing to normalize.
|
||||||
normalizeChildrenWith(transform, schema, node)
|
if (!schema.hasValidators) {
|
||||||
|
return transform
|
||||||
// Re-find the node reference if necessary.
|
|
||||||
if (transform.operations.length != opCount) {
|
|
||||||
node = refindNode(transform, node)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now normalize the node itself if it still exists.
|
const { state } = transform
|
||||||
if (node) {
|
const { document } = state
|
||||||
normalizeNodeOnly(transform, schema, node)
|
const node = document.assertNode(key)
|
||||||
}
|
|
||||||
|
|
||||||
|
normalizeNodeWith(transform, node, schema)
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,66 +71,25 @@ export function normalizeNodeWith(transform, schema, node) {
|
|||||||
* Normalize a `node` and its parents with a `schema`.
|
* Normalize a `node` and its parents with a `schema`.
|
||||||
*
|
*
|
||||||
* @param {Transform} transform
|
* @param {Transform} transform
|
||||||
|
* @param {Node|String} key
|
||||||
* @param {Schema} schema
|
* @param {Schema} schema
|
||||||
* @param {Node} node
|
|
||||||
* @return {Transform}
|
* @return {Transform}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function normalizeParentsWith(transform, schema, node) {
|
export function normalizeParentsByKey(transform, key, schema) {
|
||||||
normalizeNodeOnly(transform, schema, node)
|
assertSchema(schema)
|
||||||
|
key = Normalize.key(key)
|
||||||
|
|
||||||
// Normalize went back up to the very top of the document.
|
// If the schema has no validation rules, there's nothing to normalize.
|
||||||
if (node.kind == 'document') {
|
if (!schema.hasValidators) {
|
||||||
return transform
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-find the node first.
|
|
||||||
node = refindNode(transform, node)
|
|
||||||
|
|
||||||
if (!node) {
|
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
|
||||||
const { state } = transform
|
const { state } = transform
|
||||||
const { document } = state
|
const { document } = state
|
||||||
const parent = document.getParent(node.key)
|
const node = document.assertNode(key)
|
||||||
|
|
||||||
return normalizeParentsWith(transform, schema, parent)
|
normalizeParentsWith(transform, node, schema)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalize a `node` and its children with the core schema.
|
|
||||||
*
|
|
||||||
* @param {Transform} transform
|
|
||||||
* @param {Node|String} key
|
|
||||||
* @return {Transform}
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function normalizeNodeByKey(transform, key) {
|
|
||||||
key = Normalize.key(key)
|
|
||||||
const { state } = transform
|
|
||||||
const { document } = state
|
|
||||||
const node = document.key == key ? document : document.assertDescendant(key)
|
|
||||||
|
|
||||||
transform.normalizeNodeWith(coreSchema, node)
|
|
||||||
return transform
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalize a `node` and its parent with the core schema.
|
|
||||||
*
|
|
||||||
* @param {Transform} transform
|
|
||||||
* @param {Node|String} key
|
|
||||||
* @return {Transform}
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function normalizeParentsByKey(transform, key) {
|
|
||||||
key = Normalize.key(key)
|
|
||||||
const { state } = transform
|
|
||||||
const { document } = state
|
|
||||||
const node = document.key == key ? document : document.assertDescendant(key)
|
|
||||||
|
|
||||||
transform.normalizeParentsWith(coreSchema, node)
|
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +112,8 @@ export function normalizeSelection(transform) {
|
|||||||
!document.hasDescendant(selection.anchorKey) ||
|
!document.hasDescendant(selection.anchorKey) ||
|
||||||
!document.hasDescendant(selection.focusKey)
|
!document.hasDescendant(selection.focusKey)
|
||||||
) {
|
) {
|
||||||
warn('Selection was invalid and reset to start of the document')
|
warn('The selection was invalid and reset to start of the document.')
|
||||||
|
|
||||||
const firstText = document.getFirstText()
|
const firstText = document.getFirstText()
|
||||||
selection = selection.merge({
|
selection = selection.merge({
|
||||||
anchorKey: firstText.key,
|
anchorKey: firstText.key,
|
||||||
@@ -178,6 +129,66 @@ export function normalizeSelection(transform) {
|
|||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a `node` and its children with a `schema`.
|
||||||
|
*
|
||||||
|
* @param {Transform} transform
|
||||||
|
* @param {Node} node
|
||||||
|
* @param {Schema} schema
|
||||||
|
* @return {Transform}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function normalizeNodeWith(transform, node, schema) {
|
||||||
|
// For performance considerations, we will check if the transform was changed.
|
||||||
|
const opCount = transform.operations.length
|
||||||
|
|
||||||
|
// Iterate over its children.
|
||||||
|
normalizeChildrenWith(transform, node, schema)
|
||||||
|
|
||||||
|
// Re-find the node reference if necessary.
|
||||||
|
if (transform.operations.length != opCount) {
|
||||||
|
node = refindNode(transform, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now normalize the node itself if it still exists.
|
||||||
|
if (node) {
|
||||||
|
normalizeNodeOnly(transform, node, schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
return transform
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a `node` and its parents with a `schema`.
|
||||||
|
*
|
||||||
|
* @param {Transform} transform
|
||||||
|
* @param {Node} node
|
||||||
|
* @param {Schema} schema
|
||||||
|
* @return {Transform}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function normalizeParentsWith(transform, node, schema) {
|
||||||
|
normalizeNodeOnly(transform, node, schema)
|
||||||
|
|
||||||
|
// Normalize went back up to the very top of the document.
|
||||||
|
if (node.kind == 'document') {
|
||||||
|
return transform
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-find the node first.
|
||||||
|
node = refindNode(transform, node)
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
return transform
|
||||||
|
}
|
||||||
|
|
||||||
|
const { state } = transform
|
||||||
|
const { document } = state
|
||||||
|
const parent = document.getParent(node.key)
|
||||||
|
|
||||||
|
return normalizeParentsWith(transform, parent, schema)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-find a reference to a node that may have been modified or removed
|
* Re-find a reference to a node that may have been modified or removed
|
||||||
* entirely by a transform.
|
* entirely by a transform.
|
||||||
@@ -199,16 +210,16 @@ function refindNode(transform, node) {
|
|||||||
* Normalize the children of a `node` with a `schema`.
|
* Normalize the children of a `node` with a `schema`.
|
||||||
*
|
*
|
||||||
* @param {Transform} transform
|
* @param {Transform} transform
|
||||||
* @param {Schema} schema
|
|
||||||
* @param {Node} node
|
* @param {Node} node
|
||||||
|
* @param {Schema} schema
|
||||||
* @return {Transform}
|
* @return {Transform}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function normalizeChildrenWith(transform, schema, node) {
|
function normalizeChildrenWith(transform, node, schema) {
|
||||||
if (node.kind == 'text') return transform
|
if (node.kind == 'text') return transform
|
||||||
|
|
||||||
node.nodes.forEach((child) => {
|
node.nodes.forEach((child) => {
|
||||||
transform.normalizeNodeWith(schema, child)
|
normalizeNodeWith(transform, child, schema)
|
||||||
})
|
})
|
||||||
|
|
||||||
return transform
|
return transform
|
||||||
@@ -218,12 +229,12 @@ function normalizeChildrenWith(transform, schema, node) {
|
|||||||
* Normalize a `node` with a `schema`, but not its children.
|
* Normalize a `node` with a `schema`, but not its children.
|
||||||
*
|
*
|
||||||
* @param {Transform} transform
|
* @param {Transform} transform
|
||||||
* @param {Schema} schema
|
|
||||||
* @param {Node} node
|
* @param {Node} node
|
||||||
|
* @param {Schema} schema
|
||||||
* @return {Transform}
|
* @return {Transform}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function normalizeNodeOnly(transform, schema, node) {
|
function normalizeNodeOnly(transform, node, schema) {
|
||||||
let max = schema.rules.length
|
let max = schema.rules.length
|
||||||
let iterations = 0
|
let iterations = 0
|
||||||
|
|
||||||
@@ -257,3 +268,19 @@ function normalizeNodeOnly(transform, schema, node) {
|
|||||||
|
|
||||||
return iterate(transform, node)
|
return iterate(transform, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert that a `schema` exists.
|
||||||
|
*
|
||||||
|
* @param {Schema} schema
|
||||||
|
*/
|
||||||
|
|
||||||
|
function assertSchema(schema) {
|
||||||
|
if (schema instanceof Schema) return
|
||||||
|
|
||||||
|
if (schema == null) {
|
||||||
|
throw new Error('You must pass a `schema` object.')
|
||||||
|
} else {
|
||||||
|
throw new Error(`You passed an invalid \`schema\` object: ${schema}.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,11 +1,9 @@
|
|||||||
|
|
||||||
import 'jsdom-global/register'
|
import 'jsdom-global/register'
|
||||||
import React from 'react'
|
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import readMetadata from 'read-metadata'
|
import readMetadata from 'read-metadata'
|
||||||
import strip from '../helpers/strip-dynamic'
|
import strip from '../helpers/strip-dynamic'
|
||||||
import { Raw, Schema } from '../..'
|
import { Raw, Schema } from '../..'
|
||||||
import { mount } from 'enzyme'
|
|
||||||
import { resolve } from 'path'
|
import { resolve } from 'path'
|
||||||
import { strictEqual } from '../helpers/assert-json'
|
import { strictEqual } from '../helpers/assert-json'
|
||||||
|
|
||||||
@@ -32,7 +30,7 @@ describe('schema', () => {
|
|||||||
const expected = readMetadata.sync(resolve(testDir, 'output.yaml'))
|
const expected = readMetadata.sync(resolve(testDir, 'output.yaml'))
|
||||||
const schema = Schema.create(require(testDir))
|
const schema = Schema.create(require(testDir))
|
||||||
const state = Raw.deserialize(input, { terse: true })
|
const state = Raw.deserialize(input, { terse: true })
|
||||||
const normalized = state.transform().normalizeWith(schema).apply()
|
const normalized = state.transform().normalize(schema).apply()
|
||||||
const output = Raw.serialize(normalized, { terse: true })
|
const output = Raw.serialize(normalized, { terse: true })
|
||||||
strictEqual(strip(output), strip(expected))
|
strictEqual(strip(output), strip(expected))
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user