Skip to content

Commit

Permalink
Add support for validating functions inside schema's rules (#2151)
Browse files Browse the repository at this point in the history
* Add specs, defaults, and documentation to next/previous rule properties

* Add comparator function support for kind/object, type, data, and mark
  • Loading branch information
Calyhre authored and ianstormtaylor committed Sep 4, 2018
1 parent 6369d05 commit 405cef0
Show file tree
Hide file tree
Showing 26 changed files with 872 additions and 2 deletions.
84 changes: 84 additions & 0 deletions docs/reference/slate/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,24 @@ Will determine whether the node is treated as a "void" node or not, making its c

Will validate the last child node against a [`match`](#match).

### `next`

`Object|Array`

```js
{
next: { type: 'quote' },
}
```

```js
{
next: [{ type: 'quote' }, { type: 'paragraph' }],
}
```

Will validate the next sibling node against a [`match`](#match).

### `nodes`

`Array`
Expand Down Expand Up @@ -231,6 +249,24 @@ For more information on the arguments passed to `normalize`, see the [Normalizin

Will validate a node's parent against a [`match`](#match).

### `previous`

`Object|Array`

```js
{
previous: { type: 'quote' },
}
```

```js
{
previous: [{ type: 'quote' }, { type: 'paragraph' }],
}
```

Will validate the previous sibling node against a [`match`](#match).

### `text`

`RegExp|Function`
Expand Down Expand Up @@ -380,6 +416,30 @@ Raised when the `object` property of the last child node is invalid, when a spec

Raised when the `type` property of the last child node is invalid, when a specific `last` rule was defined in a schema.

### `'next_sibling_object_invalid'`

```js
{
next: Node,
node: Node,
rule: Object,
}
```

Raised when the `object` property of the next sibling node is invalid, when a specific `next` rule was defined in a schema.

### `'next_sibling_type_invalid'`

```js
{
next: Node,
node: Node,
rule: Object,
}
```

Raised when the `type` property of the next sibling node is invalid, when a specific `next` rule was defined in a schema.

### `'node_data_invalid'`

```js
Expand Down Expand Up @@ -451,3 +511,27 @@ Raised when the `object` property of the parent of a node is invalid, when a spe
```

Raised when the `type` property of the parent of a node is invalid, when a specific `parent` rule was defined in a schema.

### `'previous_sibling_object_invalid'`

```js
{
previous: Node,
node: Node,
rule: Object,
}
```

Raised when the `object` property of the previous sibling node is invalid, when a specific `previous` rule was defined in a schema.

### `'previous_sibling_type_invalid'`

```js
{
previous: Node,
node: Node,
rule: Object,
}
```

Raised when the `type` property of the previous sibling node is invalid, when a specific `previous` rule was defined in a schema.
34 changes: 32 additions & 2 deletions packages/slate/src/models/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ class Schema extends Record(DEFAULTS) {
*/

function defaultNormalize(change, error) {
const { code, node, child, key, mark } = error
const { code, node, child, next, previous, key, mark } = error

switch (code) {
case 'child_object_invalid':
Expand All @@ -403,6 +403,24 @@ function defaultNormalize(change, error) {
: change.removeNodeByKey(child.key, { normalize: false })
}

case 'previous_sibling_object_invalid':
case 'previous_sibling_type_invalid': {
return previous.object === 'text' &&
node.object === 'block' &&
node.nodes.size === 1
? change.removeNodeByKey(node.key, { normalize: false })
: change.removeNodeByKey(previous.key, { normalize: false })
}

case 'next_sibling_object_invalid':
case 'next_sibling_type_invalid': {
return next.object === 'text' &&
node.object === 'block' &&
node.nodes.size === 1
? change.removeNodeByKey(node.key, { normalize: false })
: change.removeNodeByKey(next.key, { normalize: false })
}

case 'child_required':
case 'node_text_invalid':
case 'parent_object_invalid':
Expand Down Expand Up @@ -493,19 +511,26 @@ function validateRules(object, rule, rules, options = {}) {
function validateObject(node, rule) {
if (rule.object == null) return
if (rule.object === node.object) return
if (typeof rule.object === 'function' && rule.object(node.object)) return
return fail('node_object_invalid', { rule, node })
}

function validateType(node, rule) {
if (rule.type == null) return
if (rule.type === node.type) return
if (typeof rule.type === 'function' && rule.type(node.type)) return
return fail('node_type_invalid', { rule, node })
}

function validateData(node, rule) {
if (rule.data == null) return
if (node.data == null) return

if (typeof rule.data === 'function') {
if (rule.data(node.data)) return
return fail('node_data_invalid', { rule, node })
}

for (const key in rule.data) {
const fn = rule.data[key]
const value = node.data && node.data.get(key)
Expand All @@ -520,7 +545,12 @@ function validateMarks(node, rule) {
const marks = node.getMarks().toArray()

for (const mark of marks) {
const valid = rule.marks.some(def => def.type === mark.type)
const valid = rule.marks.some(
def =>
typeof def.type === 'function'
? def.type(mark.type)
: def.type === mark.type
)
if (valid) continue
return fail('node_mark_invalid', { rule, node, mark })
}
Expand Down
34 changes: 34 additions & 0 deletions packages/slate/test/schema/custom/child-kind-invalid-function.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/** @jsx h */

import h from '../../helpers/h'

export const schema = {
blocks: {
paragraph: {},
quote: {
nodes: [
{
match: [{ object: o => ['inline', 'text'].includes(o) }],
},
],
},
},
}

export const input = (
<value>
<document>
<quote>
<paragraph>text</paragraph>
</quote>
</document>
</value>
)

export const output = (
<value>
<document>
<quote />
</document>
</value>
)
32 changes: 32 additions & 0 deletions packages/slate/test/schema/custom/child-type-invalid-function.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/** @jsx h */

import h from '../../helpers/h'

export const schema = {
blocks: {
paragraph: {},
quote: {
nodes: [
{
match: [{ type: t => t === 'paragraph' }],
},
],
},
},
}

export const input = (
<value>
<document>
<quote>
<image />
</quote>
</document>
</value>
)

export const output = (
<value>
<document />
</value>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/** @jsx h */

import h from '../../helpers/h'

export const schema = {
blocks: {
paragraph: {},
quote: {
first: [{ object: o => o === 'text' }],
},
},
}

export const input = (
<value>
<document>
<quote>
<paragraph />
</quote>
</document>
</value>
)

export const output = (
<value>
<document>
<quote />
</document>
</value>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/** @jsx h */

import h from '../../helpers/h'

export const schema = {
blocks: {
paragraph: {},
quote: {
first: { type: t => t === 'paragraph' },
},
},
}

export const input = (
<value>
<document>
<quote>
<image />
<paragraph />
<paragraph />
</quote>
</document>
</value>
)

export const output = (
<value>
<document>
<quote>
<paragraph />
<paragraph />
</quote>
</document>
</value>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/** @jsx h */

import h from '../../helpers/h'

export const schema = {
blocks: {
paragraph: {},
quote: {
last: [{ object: o => o === 'text' }],
},
},
}

export const input = (
<value>
<document>
<quote>
<paragraph />
</quote>
</document>
</value>
)

export const output = (
<value>
<document>
<quote />
</document>
</value>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/** @jsx h */

import h from '../../helpers/h'

export const schema = {
blocks: {
paragraph: {},
quote: {
last: { type: t => t === 'paragraph' },
},
},
}

export const input = (
<value>
<document>
<quote>
<paragraph />
<paragraph />
<image />
</quote>
</document>
</value>
)

export const output = (
<value>
<document>
<quote>
<paragraph />
<paragraph />
</quote>
</document>
</value>
)
Loading

0 comments on commit 405cef0

Please sign in to comment.