From 82daf0fbd89cb550c59c1349ddab3a7b40dbc014 Mon Sep 17 00:00:00 2001 From: Sven Tschui Date: Tue, 2 Jun 2020 15:54:47 +0200 Subject: [PATCH 1/3] Add option to preserve whitespace for certain elements Add an option to preserve whitespace/indentation for certain elements. Defaults to `['pre']` Signed-off-by: Sven Tschui --- src/index.js | 7 ++++--- test/pretty.js | 13 +++++++++++++ test/render.js | 11 +++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 31fe52fa..41025a69 100644 --- a/src/index.js +++ b/src/index.js @@ -20,6 +20,7 @@ const noop = () => {}; * @param {Boolean} [options.shallow=false] If `true`, renders nested Components as HTML elements (``). * @param {Boolean} [options.xml=false] If `true`, uses self-closing tags for elements without children. * @param {Boolean} [options.pretty=false] If `true`, adds whitespace for readability + * @param {Boolean} [options.preserveWhitespace=['pre']] Array of HTML tags for which to preserve indentation. */ renderToString.render = renderToString; @@ -51,7 +52,7 @@ function renderToString(vnode, context, opts, inner, isSvgMode, selectValue) { context = context || {}; opts = opts || {}; - let pretty = opts.pretty, + let pretty = (opts.preserveWhitespace || ['pre']).indexOf(nodeName) === -1 && opts.pretty, indentChar = pretty && typeof pretty==='string' ? pretty : '\t'; // #text nodes @@ -73,7 +74,7 @@ function renderToString(vnode, context, opts, inner, isSvgMode, selectValue) { for (let i = 0; i < children.length; i++) { rendered += (i > 0 && pretty ? '\n' : '') + renderToString(children[i], context, opts, opts.shallowHighOrder!==false, isSvgMode, selectValue); } - return rendered; + return pretty ? indent(rendered, indentChar) : rendered; } else { let rendered; @@ -269,7 +270,7 @@ function renderToString(vnode, context, opts, inner, isSvgMode, selectValue) { } if (pretty && hasLarge) { for (let i=pieces.length; i--; ) { - pieces[i] = '\n' + indentChar + indent(pieces[i], indentChar); + pieces[i] = '\n' + indentChar + pieces[i]; } } } diff --git a/test/pretty.js b/test/pretty.js index ba85c556..65e524d0 100644 --- a/test/pretty.js +++ b/test/pretty.js @@ -21,6 +21,19 @@ describe('pretty', () => { expect(rendered).to.equal(`
foobar

hello

`); }); + it('should preserve indentation of pre content', () => { + let rendered = prettyRender( +
+
+			
+ ); + + expect(rendered).to.equal(`
+
foo
+bar
+
`); + }); + it('should render whitespace when pretty=true', () => { let rendered = prettyRender(
diff --git a/test/render.js b/test/render.js index 3095d66a..2275fd06 100644 --- a/test/render.js +++ b/test/render.js @@ -712,6 +712,17 @@ describe('render', () => { expect(html).to.equal('
\n\t
foo
\n\t
bar
\n\t
\n\t\t
baz
\n\t\t
quux
\n\t
\n
'); }); + it('should preserve indentation of pre content', () => { + let rendered = render( +
+
+				
+ ); + + expect(rendered).to.equal(`
foo
+bar
`); + }); + it('should skip Fragment even if it has props', () => { let html = render(
From d86c0f443b0f88b8ab49504717c26df0ab6b8b13 Mon Sep 17 00:00:00 2001 From: Sven Tschui Date: Tue, 2 Jun 2020 16:02:22 +0200 Subject: [PATCH 2/3] Add test highlighting broken text indentation --- test/pretty.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/pretty.js b/test/pretty.js index 65e524d0..3b91da27 100644 --- a/test/pretty.js +++ b/test/pretty.js @@ -34,6 +34,21 @@ bar
`); }); + it('should indent text content', () => { + let rendered = prettyRender( +
+
+
+ ); + + expect(rendered).to.equal(`
+
+ foo + bar +
+
`); + }); + it('should render whitespace when pretty=true', () => { let rendered = prettyRender(
From a5a47d452a8f5e66638f290d59c4e52bfa5878ec Mon Sep 17 00:00:00 2001 From: Sven Tschui Date: Tue, 2 Jun 2020 19:51:44 +0200 Subject: [PATCH 3/3] Improve tests, add approach of setting pretty=false when dangerouslySetInnerHTML is in the game --- src/index.js | 10 +++++----- test/pretty.js | 13 ++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/index.js b/src/index.js index 41025a69..5c11e0bf 100644 --- a/src/index.js +++ b/src/index.js @@ -20,7 +20,6 @@ const noop = () => {}; * @param {Boolean} [options.shallow=false] If `true`, renders nested Components as HTML elements (``). * @param {Boolean} [options.xml=false] If `true`, uses self-closing tags for elements without children. * @param {Boolean} [options.pretty=false] If `true`, adds whitespace for readability - * @param {Boolean} [options.preserveWhitespace=['pre']] Array of HTML tags for which to preserve indentation. */ renderToString.render = renderToString; @@ -52,7 +51,7 @@ function renderToString(vnode, context, opts, inner, isSvgMode, selectValue) { context = context || {}; opts = opts || {}; - let pretty = (opts.preserveWhitespace || ['pre']).indexOf(nodeName) === -1 && opts.pretty, + let pretty = opts.pretty, indentChar = pretty && typeof pretty==='string' ? pretty : '\t'; // #text nodes @@ -74,7 +73,7 @@ function renderToString(vnode, context, opts, inner, isSvgMode, selectValue) { for (let i = 0; i < children.length; i++) { rendered += (i > 0 && pretty ? '\n' : '') + renderToString(children[i], context, opts, opts.shallowHighOrder!==false, isSvgMode, selectValue); } - return pretty ? indent(rendered, indentChar) : rendered; + return rendered; } else { let rendered; @@ -184,7 +183,8 @@ function renderToString(vnode, context, opts, inner, isSvgMode, selectValue) { } if (name==='dangerouslySetInnerHTML') { - html = v && v.__html; + html = v ? v.__html : null; // do not use v && v.__html to prevent dangerouslySetInnerHTML="foo" + pretty = false; } else if ((v || v===0 || v==='') && typeof v!=='function') { if (v===true || v==='') { @@ -270,7 +270,7 @@ function renderToString(vnode, context, opts, inner, isSvgMode, selectValue) { } if (pretty && hasLarge) { for (let i=pieces.length; i--; ) { - pieces[i] = '\n' + indentChar + pieces[i]; + pieces[i] = '\n' + indentChar + indent(pieces[i], indentChar); } } } diff --git a/test/pretty.js b/test/pretty.js index 3b91da27..82fb336c 100644 --- a/test/pretty.js +++ b/test/pretty.js @@ -21,7 +21,7 @@ describe('pretty', () => { expect(rendered).to.equal(`
foobar

hello

`); }); - it('should preserve indentation of pre content', () => { + it('should preserve indentation of dangerouslySetInnerHTML', () => { let rendered = prettyRender(
@@ -34,18 +34,17 @@ bar
`); }); - it('should indent text content', () => { + it('should preserve indentation of multiline string child', () => { let rendered = prettyRender(
-
+
{`
+  bar`}
); expect(rendered).to.equal(`
-
- foo - bar -
+
+  bar
`); });