From be1ce2e099aa72d95644cfe5cd8e1efbc262b541 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Thu, 5 Dec 2019 15:16:49 -0500 Subject: [PATCH] fix schema properties to be exhaustive, add leaves (#3251) --- packages/slate-schema/src/checkers.ts | 35 +++++++++++++++++++ packages/slate-schema/src/errors.ts | 8 +++++ packages/slate-schema/src/rules.ts | 1 + packages/slate-schema/src/with-schema.ts | 1 + .../validations/leaves/invalid-unknown.js | 31 ++++++++++++++++ .../test/validations/leaves/invalid-value.js | 31 ++++++++++++++++ .../test/validations/leaves/valid.js | 31 ++++++++++++++++ .../validations/properties/invalid-unknown.js | 25 +++++++++++++ .../{invalid.js => invalid-value.js} | 1 + .../test/validations/properties/valid.js | 1 + 10 files changed, 165 insertions(+) create mode 100644 packages/slate-schema/test/validations/leaves/invalid-unknown.js create mode 100644 packages/slate-schema/test/validations/leaves/invalid-value.js create mode 100644 packages/slate-schema/test/validations/leaves/valid.js create mode 100644 packages/slate-schema/test/validations/properties/invalid-unknown.js rename packages/slate-schema/test/validations/properties/{invalid.js => invalid-value.js} (95%) diff --git a/packages/slate-schema/src/checkers.ts b/packages/slate-schema/src/checkers.ts index e0e34c456..c7f1b625b 100644 --- a/packages/slate-schema/src/checkers.ts +++ b/packages/slate-schema/src/checkers.ts @@ -26,6 +26,8 @@ export const checkNode = ( if (Editor.isMatch(editor, entry, m)) { if ('properties' in v) { + const { children, text, ...existing } = node + for (const k in v.properties) { const p = v.properties[k] const value = node[k] @@ -34,6 +36,12 @@ export const checkNode = ( if (isInvalid) { return { code: 'node_property_invalid', node, path, property: k } } + + delete existing[k] + } + + for (const k in existing) { + return { code: 'node_property_invalid', node, path, property: k } } } @@ -64,6 +72,33 @@ export const checkNode = ( return { code: 'last_child_invalid', node: n, path: p, index: i } } } + + if ('leaves' in v && v.leaves != null) { + for (const [n, p] of Editor.texts(editor, { at: path })) { + const { text, ...existing } = n + + for (const k in v.leaves) { + const l = v.leaves[k] + const value = n[k] + const isInvalid = typeof l === 'function' ? !l(value) : l !== value + + if (isInvalid) { + return { + code: 'node_leaf_invalid', + node: n, + path: p, + property: k, + } + } + + delete existing[k] + } + + for (const k in existing) { + return { code: 'node_leaf_invalid', node: n, path: p, property: k } + } + } + } } } } diff --git a/packages/slate-schema/src/errors.ts b/packages/slate-schema/src/errors.ts index 1a81dd829..892b7301c 100644 --- a/packages/slate-schema/src/errors.ts +++ b/packages/slate-schema/src/errors.ts @@ -42,6 +42,13 @@ export interface NextSiblingInvalidError { path: Path } +export interface NodeLeafInvalidError { + code: 'node_leaf_invalid' + node: Node + path: Path + property: string +} + export interface NodePropertyInvalidError { code: 'node_property_invalid' node: Node @@ -76,6 +83,7 @@ export type NodeError = | FirstChildInvalidError | LastChildInvalidError | NextSiblingInvalidError + | NodeLeafInvalidError | NodePropertyInvalidError | NodeTextInvalidError | ParentInvalidError diff --git a/packages/slate-schema/src/rules.ts b/packages/slate-schema/src/rules.ts index 665a192f1..29e227c2b 100644 --- a/packages/slate-schema/src/rules.ts +++ b/packages/slate-schema/src/rules.ts @@ -11,6 +11,7 @@ export interface NodeValidation { children?: ChildValidation[] first?: NodeMatch last?: NodeMatch + leaves?: Record next?: NodeMatch parent?: NodeMatch previous?: NodeMatch diff --git a/packages/slate-schema/src/with-schema.ts b/packages/slate-schema/src/with-schema.ts index 37f4e683c..af5a56ba3 100644 --- a/packages/slate-schema/src/with-schema.ts +++ b/packages/slate-schema/src/with-schema.ts @@ -121,6 +121,7 @@ export const withSchema = ( case 'child_invalid': case 'next_sibling_invalid': + case 'node_leaf_invalid': case 'node_property_invalid': case 'node_text_invalid': case 'previous_sibling_invalid': { diff --git a/packages/slate-schema/test/validations/leaves/invalid-unknown.js b/packages/slate-schema/test/validations/leaves/invalid-unknown.js new file mode 100644 index 000000000..53acc54f1 --- /dev/null +++ b/packages/slate-schema/test/validations/leaves/invalid-unknown.js @@ -0,0 +1,31 @@ +/** @jsx jsx */ + +import { jsx } from 'slate-hyperscript' + +export const schema = [ + { + for: 'node', + match: { a: true }, + validate: { + leaves: { + bold: v => v === true || v === undefined, + }, + }, + }, +] + +export const input = ( + + + word + + +) + +export const output = ( + + + + + +) diff --git a/packages/slate-schema/test/validations/leaves/invalid-value.js b/packages/slate-schema/test/validations/leaves/invalid-value.js new file mode 100644 index 000000000..d9395e018 --- /dev/null +++ b/packages/slate-schema/test/validations/leaves/invalid-value.js @@ -0,0 +1,31 @@ +/** @jsx jsx */ + +import { jsx } from 'slate-hyperscript' + +export const schema = [ + { + for: 'node', + match: { a: true }, + validate: { + leaves: { + bold: v => v === true || v === undefined, + }, + }, + }, +] + +export const input = ( + + + word + + +) + +export const output = ( + + + + + +) diff --git a/packages/slate-schema/test/validations/leaves/valid.js b/packages/slate-schema/test/validations/leaves/valid.js new file mode 100644 index 000000000..699d82431 --- /dev/null +++ b/packages/slate-schema/test/validations/leaves/valid.js @@ -0,0 +1,31 @@ +/** @jsx jsx */ + +import { jsx } from 'slate-hyperscript' + +export const schema = [ + { + for: 'node', + match: { a: true }, + validate: { + leaves: { + bold: v => v === true || v === undefined, + }, + }, + }, +] + +export const input = ( + + + word + + +) + +export const output = ( + + + word + + +) diff --git a/packages/slate-schema/test/validations/properties/invalid-unknown.js b/packages/slate-schema/test/validations/properties/invalid-unknown.js new file mode 100644 index 000000000..4c774356a --- /dev/null +++ b/packages/slate-schema/test/validations/properties/invalid-unknown.js @@ -0,0 +1,25 @@ +/** @jsx jsx */ + +import { jsx } from 'slate-hyperscript' + +export const schema = [ + { + for: 'node', + match: { a: true }, + validate: { + properties: { + a: true, + }, + }, + }, +] + +export const input = ( + + + word + + +) + +export const output = diff --git a/packages/slate-schema/test/validations/properties/invalid.js b/packages/slate-schema/test/validations/properties/invalid-value.js similarity index 95% rename from packages/slate-schema/test/validations/properties/invalid.js rename to packages/slate-schema/test/validations/properties/invalid-value.js index 67e8736be..c980cfa1c 100644 --- a/packages/slate-schema/test/validations/properties/invalid.js +++ b/packages/slate-schema/test/validations/properties/invalid-value.js @@ -8,6 +8,7 @@ export const schema = [ match: { a: true }, validate: { properties: { + a: true, thing: v => v == null || v === 'valid', }, }, diff --git a/packages/slate-schema/test/validations/properties/valid.js b/packages/slate-schema/test/validations/properties/valid.js index 3e5575d01..88ac077d2 100644 --- a/packages/slate-schema/test/validations/properties/valid.js +++ b/packages/slate-schema/test/validations/properties/valid.js @@ -8,6 +8,7 @@ export const schema = [ match: { a: true }, validate: { properties: { + a: true, thing: v => v == null || v === 'valid', }, },