From 96c309d97238f9486f5d7796aaaf37d8891b8ffe Mon Sep 17 00:00:00 2001 From: Evan Scott Date: Thu, 27 Apr 2017 02:43:52 -0400 Subject: [PATCH] fix: handle self-closing HTML inside inline HTML Also made a change to avoid interim wrappers where possible in situations where dangerouslySetInnerHTML is unavoidable. --- index.js | 27 ++++++++++++++++----------- index.spec.js | 9 +++++++++ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index efb22402..6ad8255c 100644 --- a/index.js +++ b/index.js @@ -323,16 +323,16 @@ function attributeValueToJSXPropValue(key, value) { return value; } +function isCoalesceableHTML(html) { + // ignore block-level elements + // ignore self-closing or non-content-bearing elements + return html.match(BLOCK_ELEMENT_REGEX) || html.match(SELF_CLOSING_ELEMENT_REGEX) ? false : true; +} + function coalesceInlineHTML(ast) { function coalescer(node, index, siblings) { if (node.type === 'html') { - // ignore block-level elements - if (BLOCK_ELEMENT_REGEX.test(node.value)) { - return; - } - - // ignore self-closing or non-content-bearing elements - if (SELF_CLOSING_ELEMENT_REGEX.test(node.value)) { + if (!isCoalesceableHTML(node.value)) { return; } @@ -347,7 +347,8 @@ function coalesceInlineHTML(ast) { // where's the end tag? while (end === undefined && i < siblings.length) { - if (siblings[i].type !== 'html') { + if ( siblings[i].type !== 'html' + || (siblings[i].type === 'html' && !isCoalesceableHTML(siblings[i].value))) { i += 1; continue; } @@ -398,7 +399,7 @@ function coalesceInlineHTML(ast) { } }; - return ast.children.forEach(coalescer); + ast.children.forEach(coalescer); } export function compiler(markdown, {overrides = {}} = {}) { @@ -543,6 +544,11 @@ export function compiler(markdown, {overrides = {}} = {}) { let props = {key, ...ast.props}; + if (Array.isArray(ast.children) && ast.children.length === 1 && ast.children[0].type === 'html') { + props.dangerouslySetInnerHTML = {__html: ast.children[0].value}; + ast.children = null; + } + const override = overrides[htmlNodeType]; if (override) { if (override.component) { @@ -607,8 +613,7 @@ export function compiler(markdown, {overrides = {}} = {}) { let jsx = astToJSX(remarkAST); // discard the root
node if there is only one valid initial child - // generally this is a paragraph - if (jsx.props.children.length === 1) { + if (jsx.props.children && jsx.props.children.length === 1) { jsx = jsx.props.children[0]; } diff --git a/index.spec.js b/index.spec.js index ef81b794..d7f94ab2 100644 --- a/index.spec.js +++ b/index.spec.js @@ -554,6 +554,15 @@ describe('markdown-to-jsx', () => { expect($element.children[0].children[0].tagName).toBe('STRONG'); expect($element.children[0].children[0].textContent).toBe('code'); }); + + it('handles self-closing html inside parsable html (regression)', () => { + const element = render(compiler('')); + const $element = dom(element); + + expect($element.tagName).toBe('P'); + expect($element.children[0].tagName).toBe('A'); + expect($element.children[0].children[0].tagName).toBe('IMG'); + }); }); describe('horizontal rules', () => {