Skip to content

Commit 69ed337

Browse files
authored
Merge pull request #432 from nwalters512/pretty-format-preserve-whitespace
Preserve whitespace for pre/textarea when pretty-printing
2 parents f3bdac6 + 96dfd13 commit 69ed337

File tree

5 files changed

+55
-15
lines changed

5 files changed

+55
-15
lines changed

.changeset/rude-apes-taste.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'preact-render-to-string': patch
3+
---
4+
5+
Preserve whitespace in `<pre>`/`<textarea>` when using `pretty: true`

package-lock.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/pretty.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const UNNAMED = [];
2424

2525
const EMPTY_ARR = [];
2626
const EMPTY_STR = '';
27+
const PRESERVE_WHITESPACE_TAGS = new Set(['pre', 'textarea']);
2728

2829
/**
2930
* Render Preact JSX + Components to a pretty-printed HTML-like string.
@@ -216,6 +217,11 @@ function _renderToStringPretty(
216217
propChildren,
217218
html;
218219

220+
const shouldPreserveWhitespace =
221+
pretty &&
222+
typeof nodeName === 'string' &&
223+
PRESERVE_WHITESPACE_TAGS.has(nodeName);
224+
219225
if (props) {
220226
let attrs = Object.keys(props);
221227

@@ -349,15 +355,17 @@ function _renderToStringPretty(
349355
let children;
350356
if (html) {
351357
// if multiline, indent.
352-
if (pretty && isLargeString(html)) {
358+
if (pretty && !shouldPreserveWhitespace && isLargeString(html)) {
353359
html = '\n' + indentChar + indent(html, indentChar);
354360
}
355361
s = s + html;
356362
} else if (
357363
propChildren != null &&
358364
getChildren((children = []), propChildren).length
359365
) {
360-
let hasLarge = pretty && ~s.indexOf('\n');
366+
const shouldPrettyFormatChildren =
367+
pretty && !shouldPreserveWhitespace && typeof nodeName === 'string';
368+
let hasLarge = shouldPrettyFormatChildren && ~s.indexOf('\n');
361369
let lastWasText = false;
362370

363371
for (let i = 0; i < children.length; i++) {
@@ -379,11 +387,12 @@ function _renderToStringPretty(
379387
selectValue
380388
);
381389

382-
if (pretty && !hasLarge && isLargeString(ret)) hasLarge = true;
390+
if (shouldPrettyFormatChildren && !hasLarge && isLargeString(ret))
391+
hasLarge = true;
383392

384393
// Skip if we received an empty string
385394
if (ret) {
386-
if (pretty) {
395+
if (shouldPrettyFormatChildren) {
387396
let isText = ret.length > 0 && ret[0] != '<';
388397

389398
// We merge adjacent text nodes, otherwise each piece would be printed
@@ -401,7 +410,7 @@ function _renderToStringPretty(
401410
}
402411
}
403412
}
404-
if (pretty && hasLarge) {
413+
if (shouldPrettyFormatChildren && hasLarge) {
405414
for (let i = pieces.length; i--; ) {
406415
pieces[i] = '\n' + indentChar + indent(pieces[i], indentChar);
407416
}
@@ -419,7 +428,7 @@ function _renderToStringPretty(
419428
if (isVoid && !children && !html) {
420429
s = s.replace(/>$/, ' />');
421430
} else {
422-
if (pretty && ~s.indexOf('\n')) s = s + '\n';
431+
if (pretty && !shouldPreserveWhitespace && ~s.indexOf('\n')) s = s + '\n';
423432
s = s + `</${nodeName}>`;
424433
}
425434

test/pretty.test.jsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,25 @@ describe('pretty', () => {
215215
);
216216
});
217217

218+
it('should not add whitespace to pre tag children', () => {
219+
let rendered = prettyRender(
220+
<pre>
221+
<code>hello</code>
222+
</pre>,
223+
{ jsx: false }
224+
);
225+
226+
expect(rendered).to.equal(`<pre><code>hello</code></pre>`);
227+
});
228+
229+
it('should maintain whitespace in textarea tag', () => {
230+
let rendered = prettyRender(<textarea>{' hello\nworld '}</textarea>, {
231+
jsx: false
232+
});
233+
234+
expect(rendered).to.equal(`<textarea> hello\nworld </textarea>`);
235+
});
236+
218237
describe('Attribute casing', () => {
219238
it('should have correct SVG casing', () => {
220239
for (let name in svgAttributes) {

test/render.test.jsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,13 @@ describe('render', () => {
243243
expect(rendered).to.equal(expected);
244244
});
245245

246+
it('should serialize textarea value with leading/trailing whitespace', () => {
247+
let rendered = render(<textarea value={` a\nb `} />),
248+
expected = `<textarea> a\nb </textarea>`;
249+
250+
expect(rendered).to.equal(expected);
251+
});
252+
246253
it('should escape textarea value', () => {
247254
let rendered = render(<textarea value={`a&b"c`} />),
248255
expected = `<textarea>a&amp;b&quot;c</textarea>`;

0 commit comments

Comments
 (0)