fix(widget-markdown): ensure remarkToSlate result matches slate schema (#3085)

This commit is contained in:
Erez Rokah 2020-01-14 20:20:52 +02:00 committed by Shawn Erquhart
parent 0a50efda8e
commit fde0c5a9a7
4 changed files with 186 additions and 3 deletions

View File

@ -476,6 +476,10 @@ more important, there there are only so many sizes that you can use.",
"nodes": Array [
Object {
"nodes": Array [
Object {
"object": "text",
"text": "",
},
Object {
"data": Object {
"title": null,
@ -506,6 +510,10 @@ more important, there there are only so many sizes that you can use.",
"nodes": Array [
Object {
"nodes": Array [
Object {
"object": "text",
"text": "",
},
Object {
"data": Object {
"title": null,
@ -557,6 +565,12 @@ more important, there there are only so many sizes that you can use.",
"type": "paragraph",
},
Object {
"nodes": Array [
Object {
"object": "text",
"text": "",
},
],
"object": "block",
"type": "thematic-break",
},

View File

@ -279,6 +279,12 @@ Object {
"type": "heading-one",
},
Object {
"nodes": Array [
Object {
"object": "text",
"text": "",
},
],
"object": "block",
"type": "thematic-break",
},
@ -321,6 +327,12 @@ Object {
"type": "heading-one",
},
Object {
"nodes": Array [
Object {
"object": "text",
"text": "",
},
],
"object": "block",
"type": "thematic-break",
},
@ -357,6 +369,12 @@ Object {
},
Object {
"data": undefined,
"nodes": Array [
Object {
"object": "text",
"text": "",
},
],
"object": "inline",
"type": "break",
},
@ -384,15 +402,29 @@ Object {
"nodes": Array [
Object {
"nodes": Array [
Object {
"object": "text",
"text": "",
},
Object {
"data": Object {
"alt": "super",
"title": null,
"url": "duper.jpg",
},
"nodes": Array [
Object {
"object": "text",
"text": "",
},
],
"object": "inline",
"type": "image",
},
Object {
"object": "text",
"text": "",
},
],
"object": "block",
"type": "paragraph",
@ -638,15 +670,29 @@ Object {
"nodes": Array [
Object {
"nodes": Array [
Object {
"object": "text",
"text": "",
},
Object {
"data": Object {
"alt": "test",
"title": null,
"url": "test.png",
},
"nodes": Array [
Object {
"object": "text",
"text": "",
},
],
"object": "inline",
"type": "image",
},
Object {
"object": "text",
"text": "",
},
],
"object": "block",
"type": "paragraph",

View File

@ -0,0 +1,77 @@
import { wrapInlinesWithTexts } from '../remarkSlate';
describe('remarkSlate', () => {
describe('wrapInlinesWithTexts', () => {
it('should handle empty array', () => {
const children = [];
expect(wrapInlinesWithTexts(children)).toBe(children);
});
it('should wrap single inline node with texts', () => {
expect(wrapInlinesWithTexts([{ object: 'inline' }])).toEqual([
{ object: 'text', text: '' },
{ object: 'inline' },
{ object: 'text', text: '' },
]);
});
it('should insert text before inline', () => {
expect(wrapInlinesWithTexts([{ object: 'inline' }, { object: 'text', text: '' }])).toEqual([
{ object: 'text', text: '' },
{ object: 'inline' },
{ object: 'text', text: '' },
]);
});
it('should insert text after inline', () => {
expect(wrapInlinesWithTexts([{ object: 'text', text: '' }, { object: 'inline' }])).toEqual([
{ object: 'text', text: '' },
{ object: 'inline' },
{ object: 'text', text: '' },
]);
});
it('should not modify valid children array', () => {
const children = [
{ object: 'text', text: '' },
{ object: 'inline' },
{ object: 'text', text: '' },
];
expect(wrapInlinesWithTexts(children)).toBe(children);
});
it('should wrap inlines with text nodes', () => {
expect(
wrapInlinesWithTexts([
{ object: 'inline' },
{ object: 'other' },
{ object: 'inline' },
{ object: 'inline' },
{ object: 'other' },
{ object: 'text', text: 'hello' },
{ object: 'inline' },
{ object: 'inline' },
{ object: 'text', text: 'world' },
{ object: 'inline' },
]),
).toEqual([
{ object: 'text', text: '' },
{ object: 'inline' },
{ object: 'text', text: '' },
{ object: 'other' },
{ object: 'text', text: '' },
{ object: 'inline' },
{ object: 'text', text: '' },
{ object: 'inline' },
{ object: 'text', text: '' },
{ object: 'other' },
{ object: 'text', text: 'hello' },
{ object: 'inline' },
{ object: 'text', text: '' },
{ object: 'inline' },
{ object: 'text', text: 'world' },
{ object: 'inline' },
{ object: 'text', text: '' },
]);
});
});
});

View File

@ -28,6 +28,42 @@ const markMap = {
inlineCode: 'code',
};
const isInline = node => node.object === 'inline';
const isText = node => node.object === 'text';
export const wrapInlinesWithTexts = children => {
if (children.length <= 0) {
return children;
}
const insertLocations = [];
let prev = children[0];
if (isInline(prev)) {
insertLocations.push(0);
}
for (let i = 1; i < children.length; i++) {
const current = children[i];
if (isInline(prev) && !isText(current)) {
insertLocations.push(i);
} else if (!isText(prev) && isInline(current)) {
insertLocations.push(i);
}
prev = current;
}
if (isInline(prev)) {
insertLocations.push(children.length);
}
for (let i = 0; i < insertLocations.length; i++) {
children.splice(insertLocations[i] + i, 0, { object: 'text', text: '' });
}
return children;
};
/**
* A Remark plugin for converting an MDAST to Slate Raw AST. Remark plugins
* return a `transformNode` function that receives the MDAST as it's first argument.
@ -43,11 +79,16 @@ export default function remarkToSlate({ voidCodeBlock } = {}) {
* translate from MDAST to Slate, such as definitions for link/image
* references or footnotes.
*/
const children =
let children =
!['strong', 'emphasis', 'delete'].includes(node.type) &&
!isEmpty(node.children) &&
flatMap(node.children, transformNode).filter(val => val);
if (Array.isArray(children)) {
// Ensure that inline nodes are surrounded by text nodes to conform to slate schema
children = wrapInlinesWithTexts(children);
}
/**
* Run individual nodes through the conversion factory.
*/
@ -71,8 +112,10 @@ export default function remarkToSlate({ voidCodeBlock } = {}) {
nodes = undefined;
}
// Ensure block nodes have at least one text child to conform to slate schema
const children = isEmpty(nodes) ? [createText('')] : nodes;
const node = { object: 'block', type, ...props };
return addNodes(node, nodes);
return addNodes(node, children);
}
/**
@ -80,7 +123,10 @@ export default function remarkToSlate({ voidCodeBlock } = {}) {
*/
function createInline(type, props = {}, nodes) {
const node = { object: 'inline', type, ...props };
return addNodes(node, nodes);
// Ensure inline nodes have at least one text child to conform to slate schema
const children = isEmpty(nodes) ? [createText('')] : nodes;
return addNodes(node, children);
}
/**