Preserve character data and handle void elements in innerHTML parsing - #685
olavoasantos wants to merge 1 commit into
Conversation
041ee09 to
f922a66
Compare
f922a66 to
1b7881e
Compare
|
The parser and reentrancy fixes check out. I found two focused corrections when comparing native Chrome 152, the namespace base, and head 1. Classify void elements by namespace and exact local nameThe new serialization check drops children based only on a lowercased qualified name: const node = document.createElementNS('urn:widget', 'input');
node.append('must survive');
node.outerHTML;
The same introduced content loss affects HTML-namespace elements created with established local names Could we use one element-aware predicate for both parsing and serialization? function isVoidElement(element: Element) {
return (
element.namespaceURI === HTML_NAMESPACE &&
VOID_ELEMENTS.has(element.localName)
);
}Pass the created node during parsing and the element during serialization. Please add regression coverage for foreign-namespace 2. Preserve unrecognized named-entity spellingsThe decoder's const element = document.createElement('div');
element.innerHTML = '<p>&aMp; &APOS;</p>';
element.textContent;
Please match the exact supported named spellings and leave unknown ones literal. Include valid uppercase aliases such as This second issue is a gap in the new decoder, not a claim that the base handled these inputs correctly (it dropped their ampersands). Neither correction requires expanding this into a browser-grade parser. |
| } | ||
|
|
||
| export function parseHtml(html: string, contextNode: Node) { | ||
| const elementTokenizer = |
There was a problem hiding this comment.
Nit: Hoisting regexes out of hot functions is typically good for perf.
There was a problem hiding this comment.
yea, hoisted the tokenizer regexes and switched the loops to matchAll() so the global regex state remains isolated during reentrant parsing.
1b7881e to
958e38f
Compare
958e38f to
798dec7
Compare
|
Fixed both. Void classification now uses the element namespace and exact |
798dec7 to
fd4de61
Compare
Problem
The limited
innerHTMLparser discarded literal ampersands, did not decode character references, and stored encoded attribute values such that serialization could escape them again. It also treated HTML void elements as normal parents, nesting following content beneath them and emitting invented closing tags.Impact
Important. Ordinary valid HTML assigned through the exposed
innerHTMLpath could lose text data, produce a different tree, or serialize to different markup. In a worker-side Remote DOM tree, that means consumers can make decisions from content that does not match the markup they assigned.Reproduction
Before this change, the literal
&was dropped and the second paragraph was parsed beneathimg, which was serialized with a closing tag. It now retainsFish & chips, keepsimgand both paragraphs as siblings, and serializes the void element as<img src="logo.png">.Change
innerHTMLparsing from corrupting an outer parse.This is a targeted correction to the existing limited parser, not browser-grade entity coverage or malformed-markup recovery.
Tests
Adds
packages/polyfill/source/tests/inner-html-parsing.test.ts, covering literal ampersands; the supported named, decimal, and hexadecimal references; attribute round-tripping; reentrant parsing from an attribute callback; void-element sibling structure; self-closing void syntax; and closing-tag omission for every supported HTML void element.Stack
normalize-dom-namespacesValidation
Fresh GitHub CI on restacked head
1b7881epasses: