From 20823518ecdea3a502eed69348fb6719d72af594 Mon Sep 17 00:00:00 2001 From: Ryan Waskiewicz Date: Tue, 30 Apr 2024 16:51:23 -0400 Subject: [PATCH] fix(hydrate): output track elements as void elms (#5720) * fix(hydrate): output track elements as void elms add `track` to the list of "EMPTY" elements (void elements) that is referenced when we serialize nodes. prior to this fix, the output of running `renderToString` as such: ```js const hydrate = require('./hydrate/index.js'); const src = ``; hydrate.renderToString(src, { prettyHtml: true }) .then(result => console.log(result.html)); ``` would result in the following being printed: ```html ``` With this fix applied, we print `track` as a void element: ```html ``` Fixes: #2994 STENCIL-94: Using hydrate.renderToString produces "invalid" HTML with * review(cb): unit tests --- src/mock-doc/serialize-node.ts | 8 +++++++- src/mock-doc/test/serialize-node.spec.ts | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/mock-doc/serialize-node.ts b/src/mock-doc/serialize-node.ts index c77c019a835..ee75ed901cb 100644 --- a/src/mock-doc/serialize-node.ts +++ b/src/mock-doc/serialize-node.ts @@ -474,6 +474,7 @@ function isWithinWhitespaceSensitive(node: Node) { return false; } +// TODO(STENCIL-1299): Audit this list, remove unsupported/deprecated elements /*@__PURE__*/ export const NON_ESCAPABLE_CONTENT = new Set([ 'STYLE', 'SCRIPT', @@ -485,6 +486,7 @@ function isWithinWhitespaceSensitive(node: Node) { 'PLAINTEXT', ]); +// TODO(STENCIL-1299): Audit this list, remove unsupported/deprecated elements /** * A list of whitespace sensitive tag names, such as `code`, `pre`, etc. */ @@ -498,7 +500,8 @@ function isWithinWhitespaceSensitive(node: Node) { 'TEXTAREA', ]); -/*@__PURE__*/ const EMPTY_ELEMENTS = new Set([ +// TODO(STENCIL-1299): Audit this list, remove unsupported/deprecated elements +/*@__PURE__*/ export const EMPTY_ELEMENTS = new Set([ 'area', 'base', 'basefont', @@ -516,11 +519,14 @@ function isWithinWhitespaceSensitive(node: Node) { 'param', 'source', 'trace', + 'track', 'wbr', ]); +// TODO(STENCIL-1299): Audit this list, remove unsupported/deprecated attr /*@__PURE__*/ const REMOVE_EMPTY_ATTR = new Set(['class', 'dir', 'id', 'lang', 'name', 'title']); +// TODO(STENCIL-1299): Audit this list, remove unsupported/deprecated attr /*@__PURE__*/ const BOOLEAN_ATTR = new Set([ 'allowfullscreen', 'async', diff --git a/src/mock-doc/test/serialize-node.spec.ts b/src/mock-doc/test/serialize-node.spec.ts index 32008092fdb..e04efdb3817 100644 --- a/src/mock-doc/test/serialize-node.spec.ts +++ b/src/mock-doc/test/serialize-node.spec.ts @@ -1,5 +1,5 @@ import { MockDocument } from '../document'; -import { serializeNodeToHtml } from '../serialize-node'; +import { EMPTY_ELEMENTS, serializeNodeToHtml } from '../serialize-node'; describe('serializeNodeToHtml', () => { let doc: MockDocument; @@ -278,4 +278,19 @@ describe('serializeNodeToHtml', () => { scriptElm.innerHTML = input; expect(scriptElm.innerHTML).toBe(input); }); + + it.each([...EMPTY_ELEMENTS])("does not add a closing tag for '%s'", (voidElm) => { + if (voidElm === 'frame') { + // 'frame' is a non-HTML5 compatible/deprecated element. + // Stencil technically still supports it, but it doesn't get rendered as a child element, so let's just skip it + return; + } + + const elm = doc.createElement('div'); + + elm.innerHTML = `<${voidElm}>`; + + const html = serializeNodeToHtml(elm, { prettyHtml: true }); + expect(html).toBe(`<${voidElm}>`); + }); });