Skip to content

Commit

Permalink
fix(serializer): Serialize void elements as "" (inikulin#442)
Browse files Browse the repository at this point in the history
Co-authored-by: Titus <tituswormer@gmail.com>
  • Loading branch information
2 people authored and jmbpwtw committed Feb 16, 2023
1 parent 5096027 commit f2b0779
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 3 deletions.
16 changes: 16 additions & 0 deletions packages/parse5/lib/serializer/index.test.ts
Expand Up @@ -3,6 +3,7 @@ import * as parse5 from 'parse5';
import { generateSerializerTests } from 'parse5-test-utils/utils/generate-serializer-tests.js';
import { treeAdapters } from 'parse5-test-utils/utils/common.js';
import { type Element, isElementNode } from 'parse5/dist/tree-adapters/default';
import { NAMESPACES } from 'parse5/dist/common/html.js';

generateSerializerTests('serializer', 'Serializer', parse5.serialize);

Expand Down Expand Up @@ -42,4 +43,19 @@ describe('serializer', () => {

assert.equal(html, '<button>Hello</button>');
});

it('serializes the children of void elements as the empty string (GH-289)', () => {
const br = treeAdapters.default.createElement('br', NAMESPACES.HTML, []);

// Add child node to `br`, to make sure they are skipped.
treeAdapters.default.appendChild(br, treeAdapters.default.createElement('div', NAMESPACES.HTML, []));

assert.equal(parse5.serialize(br), '');

// If the namespace is not HTML, the serializer should not skip the children.
const svgBr = treeAdapters.default.createElement('br', NAMESPACES.SVG, []);
treeAdapters.default.appendChild(svgBr, treeAdapters.default.createElement('div', NAMESPACES.HTML, []));

assert.equal(parse5.serialize(svgBr), '<div></div>');
});
});
18 changes: 15 additions & 3 deletions packages/parse5/lib/serializer/index.ts
Expand Up @@ -30,6 +30,15 @@ const VOID_ELEMENTS = new Set<string>([
$.TRACK,
$.WBR,
]);

function isVoidElement<T extends TreeAdapterTypeMap>(node: T['node'], options: InternalOptions<T>): boolean {
return (
options.treeAdapter.isElementNode(node) &&
options.treeAdapter.getNamespaceURI(node) === NS.HTML &&
VOID_ELEMENTS.has(options.treeAdapter.getTagName(node))
);
}

const UNESCAPED_TEXT = new Set<string>([$.STYLE, $.SCRIPT, $.XMP, $.IFRAME, $.NOEMBED, $.NOFRAMES, $.PLAINTEXT]);

export function hasUnescapedText(tn: string, scriptingEnabled: boolean): boolean {
Expand Down Expand Up @@ -83,6 +92,11 @@ export function serialize<T extends TreeAdapterTypeMap = DefaultTreeAdapter.Defa
options?: SerializerOptions<T>
): string {
const opts = { ...defaultOpts, ...options };

if (isVoidElement(node, opts)) {
return '';
}

return serializeChildNodes(node, opts);
}

Expand Down Expand Up @@ -157,9 +171,7 @@ function serializeElement<T extends TreeAdapterTypeMap>(node: T['element'], opti
const tn = options.treeAdapter.getTagName(node);

return `<${tn}${serializeAttributes(node, options)}>${
options.treeAdapter.getNamespaceURI(node) === NS.HTML && VOID_ELEMENTS.has(tn)
? ''
: `${serializeChildNodes(node, options)}</${tn}>`
isVoidElement(node, options) ? '' : `${serializeChildNodes(node, options)}</${tn}>`
}`;
}

Expand Down

0 comments on commit f2b0779

Please sign in to comment.