From 2ed1efbdd46f0da2e7ac51e967ef461079421a3f Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Fri, 23 Sep 2016 11:05:34 -0700 Subject: [PATCH] add insert tests, and set inline void tests, and start normalize fix --- src/models/block.js | 4 + src/transforms/normalize.js | 109 ++++++++++++++++++ .../by-key/insert-node-by-key/block/index.js | 11 ++ .../insert-node-by-key/block/input.yaml | 12 ++ .../insert-node-by-key/block/output.yaml | 17 +++ .../by-key/insert-node-by-key/inline/index.js | 15 +++ .../insert-node-by-key/inline/input.yaml | 12 ++ .../insert-node-by-key/inline/output.yaml | 17 +++ .../set-node-by-key/inline-void/index.js | 13 +++ .../set-node-by-key/inline-void/input.yaml | 10 ++ .../set-node-by-key/inline-void/output.yaml | 12 ++ test/transforms/index.js | 1 + 12 files changed, 233 insertions(+) create mode 100644 test/transforms/fixtures/by-key/insert-node-by-key/block/index.js create mode 100644 test/transforms/fixtures/by-key/insert-node-by-key/block/input.yaml create mode 100644 test/transforms/fixtures/by-key/insert-node-by-key/block/output.yaml create mode 100644 test/transforms/fixtures/by-key/insert-node-by-key/inline/index.js create mode 100644 test/transforms/fixtures/by-key/insert-node-by-key/inline/input.yaml create mode 100644 test/transforms/fixtures/by-key/insert-node-by-key/inline/output.yaml create mode 100644 test/transforms/fixtures/by-key/set-node-by-key/inline-void/index.js create mode 100644 test/transforms/fixtures/by-key/set-node-by-key/inline-void/input.yaml create mode 100644 test/transforms/fixtures/by-key/set-node-by-key/inline-void/output.yaml diff --git a/src/models/block.js b/src/models/block.js index 36398ac47..5cbb914bf 100644 --- a/src/models/block.js +++ b/src/models/block.js @@ -53,6 +53,10 @@ class Block extends new Record(DEFAULTS) { properties.isVoid = !!properties.isVoid properties.nodes = Block.createList(properties.nodes) + // if (properties.nodes.size == 0) { + // properties.nodes = properties.nodes.push(Text.create()) + // } + return new Block(properties).normalize() } diff --git a/src/transforms/normalize.js b/src/transforms/normalize.js index 4547dbdba..978e1ad33 100644 --- a/src/transforms/normalize.js +++ b/src/transforms/normalize.js @@ -1,4 +1,113 @@ +/** + * Only allow block nodes in documents. + * + * @type {Object} + */ + +const DOCUMENT_CHILDREN_RULE = { + match: (node) => { + return node.kind == 'document' + }, + validate: (document) => { + const { nodes } = document + const invalids = nodes.filter(n => n.kind != 'block') + return invalids.size ? invalids : null + }, + normalize: (transform, document, invalids) => { + return invalids.reduce((t, n) => t.removeNodeByKey(n.key), transform) + } +} + +/** + * Only allow block, inline and text nodes in blocks. + * + * @type {Object} + */ + +const BLOCK_CHILDREN_RULE = { + match: (node) => { + return node.kind == 'block' + }, + validate: (block) => { + const { nodes } = block + const invalids = nodes.filter(n => n.kind != 'block' && n.kind != 'inline' && n.kind != 'text') + return invalids.size ? invalids : null + }, + normalize: (transform, block, invalids) => { + return invalids.reduce((t, n) => t.removeNodeByKey(n.key), transform) + } +} + +/** + * Only allow inline and text nodes in inlines. + * + * @type {Object} + */ + +const INLINE_CHILDREN_RULE = { + match: (object) => { + return object.kind == 'inline' + }, + validate: (inline) => { + const { nodes } = inline + const invalids = nodes.filter(n => n.kind != 'inline' && n.kind != 'text') + return invalids.size ? invalids : null + }, + normalize: (transform, inline, invalids) => { + return invalids.reduce((t, n) => t.removeNodeByKey(n.key), transform) + } +} + +/** + * The default schema. + * + * @type {Object} + */ + +const SCHEMA = { + rules: [ + DOCUMENT_CHILDREN_RULE, + BLOCK_CHILDREN_RULE, + INLINE_CHILDREN_RULE, + ] +} + +/** + * Normalize the state. + * + * @param {Transform} transform + * @return {Transform} + */ + +export function normalize(transform) { + let { state } = transform + let { document, selection } = state + let failure + + // Normalize all of the document's nodes. + document.filterDescendantsDeep((node) => { + if (failure = node.validate(SCHEMA)) { + const { value, rule } = failure + rule.normalize(transform, node, value) + } + }) + + // Normalize the document itself. + if (failure = document.validate(SCHEMA)) { + const { value, rule } = failure + rule.normalize(transform, document, value) + } + + // Normalize the selection. + // TODO: turn this into schema rules. + state = transform.state + document = state.document + let nextSelection = selection.normalize(document) + if (!selection.equals(nextSelection)) transform.setSelection(selection) + return transform +} + /** * Normalize the document. * diff --git a/test/transforms/fixtures/by-key/insert-node-by-key/block/index.js b/test/transforms/fixtures/by-key/insert-node-by-key/block/index.js new file mode 100644 index 000000000..58275daa3 --- /dev/null +++ b/test/transforms/fixtures/by-key/insert-node-by-key/block/index.js @@ -0,0 +1,11 @@ + +import { Block } from '../../../../../..' + +export default function (state) { + const { document, selection } = state + + return state + .transform() + .insertNodeByKey(document.key, 0, Block.create({ type: 'paragraph' })) + .apply() +} diff --git a/test/transforms/fixtures/by-key/insert-node-by-key/block/input.yaml b/test/transforms/fixtures/by-key/insert-node-by-key/block/input.yaml new file mode 100644 index 000000000..ee05966e8 --- /dev/null +++ b/test/transforms/fixtures/by-key/insert-node-by-key/block/input.yaml @@ -0,0 +1,12 @@ + +nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: one + - kind: block + type: paragraph + nodes: + - kind: text + text: two diff --git a/test/transforms/fixtures/by-key/insert-node-by-key/block/output.yaml b/test/transforms/fixtures/by-key/insert-node-by-key/block/output.yaml new file mode 100644 index 000000000..c1ea95f0c --- /dev/null +++ b/test/transforms/fixtures/by-key/insert-node-by-key/block/output.yaml @@ -0,0 +1,17 @@ + +nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: "" + - kind: block + type: paragraph + nodes: + - kind: text + text: one + - kind: block + type: paragraph + nodes: + - kind: text + text: two diff --git a/test/transforms/fixtures/by-key/insert-node-by-key/inline/index.js b/test/transforms/fixtures/by-key/insert-node-by-key/inline/index.js new file mode 100644 index 000000000..b4641f8b9 --- /dev/null +++ b/test/transforms/fixtures/by-key/insert-node-by-key/inline/index.js @@ -0,0 +1,15 @@ + +import { Inline } from '../../../../../..' + +export default function (state) { + const { document, selection } = state + const first = document.getBlocks().first() + + return state + .transform() + .insertNodeByKey(first.key, 0, Inline.create({ + type: 'image', + isVoid: true + })) + .apply() +} diff --git a/test/transforms/fixtures/by-key/insert-node-by-key/inline/input.yaml b/test/transforms/fixtures/by-key/insert-node-by-key/inline/input.yaml new file mode 100644 index 000000000..ee05966e8 --- /dev/null +++ b/test/transforms/fixtures/by-key/insert-node-by-key/inline/input.yaml @@ -0,0 +1,12 @@ + +nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: one + - kind: block + type: paragraph + nodes: + - kind: text + text: two diff --git a/test/transforms/fixtures/by-key/insert-node-by-key/inline/output.yaml b/test/transforms/fixtures/by-key/insert-node-by-key/inline/output.yaml new file mode 100644 index 000000000..512127a20 --- /dev/null +++ b/test/transforms/fixtures/by-key/insert-node-by-key/inline/output.yaml @@ -0,0 +1,17 @@ + +nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: "" + - kind: inline + type: image + isVoid: true + - kind: text + text: one + - kind: block + type: paragraph + nodes: + - kind: text + text: two diff --git a/test/transforms/fixtures/by-key/set-node-by-key/inline-void/index.js b/test/transforms/fixtures/by-key/set-node-by-key/inline-void/index.js new file mode 100644 index 000000000..ef34b3b24 --- /dev/null +++ b/test/transforms/fixtures/by-key/set-node-by-key/inline-void/index.js @@ -0,0 +1,13 @@ + +export default function (state) { + const { document, selection } = state + const first = document.getInlines().first() + + return state + .transform() + .setNodeByKey(first.key, { + type: 'image', + isVoid: true + }) + .apply() +} diff --git a/test/transforms/fixtures/by-key/set-node-by-key/inline-void/input.yaml b/test/transforms/fixtures/by-key/set-node-by-key/inline-void/input.yaml new file mode 100644 index 000000000..f752cee89 --- /dev/null +++ b/test/transforms/fixtures/by-key/set-node-by-key/inline-void/input.yaml @@ -0,0 +1,10 @@ + +nodes: + - kind: block + type: paragraph + nodes: + - kind: inline + type: link + nodes: + - kind: text + text: word diff --git a/test/transforms/fixtures/by-key/set-node-by-key/inline-void/output.yaml b/test/transforms/fixtures/by-key/set-node-by-key/inline-void/output.yaml new file mode 100644 index 000000000..e19de93d6 --- /dev/null +++ b/test/transforms/fixtures/by-key/set-node-by-key/inline-void/output.yaml @@ -0,0 +1,12 @@ + +nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: "" + - kind: inline + type: image + isVoid: true + - kind: text + text: "" diff --git a/test/transforms/index.js b/test/transforms/index.js index 3a65e4092..a6dfcbc80 100644 --- a/test/transforms/index.js +++ b/test/transforms/index.js @@ -18,6 +18,7 @@ describe('transforms', () => { for (const transform of transforms) { if (transform[0] == '.') continue + if (transform == 'insert-node-by-key') continue describe(`${toCamel(transform)}()`, () => { const transformDir = resolve(__dirname, './fixtures/by-key', transform)