fix(parser): recognize CDATA directly inside SVG and MathML integration points
Follow-up to #2458. Greptile flagged this case on that PR before it was merged (comment), and it is right.
That PR uses isInForeignContext() to decide whether <![CDATA[ starts a CDATA section. Directly inside an HTML integration point such as foreignObject, title or mi, that is false, because opening one pushes ForeignContext.None. So <svg><foreignObject><![CDATA[x><b>]]> now gives a [CDATA[x comment followed by a live <b>. Before #2458 it gave a single [CDATA[x><b>]] comment.
The markup declaration open state switches to the CDATA section state when the adjusted current node is not an element in the HTML namespace. foreignObject is an SVG element, so this is a CDATA section and its content is text. whatwg/html#4016 was closed on this in July ("Gecko, WebKit, and tests match the standard"), and web-platform-tests/wpt#61253 added the tests. Chromium and parse5 still produce a comment here, so parse5 is not a usable oracle for these inputs.
This adds Parser#isCurrentNodeForeign(), which treats an integration point as being in the namespace it was opened in, and uses it for the CDATA decision in the tokenizer and in oncdata. A tokenizer whose callbacks only implement isInForeignContext gets the same events as before, except for unclosed CDATA at the end of input (see below). The open PR #2492 adds a similar check for the element being opened, for the self-closing flag; this one is about the current node, and the two branches merge without conflicts.
A second commit handles the end of input: unclosed CDATA now goes to oncdata when the current node is SVG or MathML, so <svg><![CDATA[x><b> and <svg><foreignObject><![CDATA[x><b> end with the text x><b> instead of a [CDATA[ comment, as in Firefox and WebKit. The first of those already gave a comment before #2458; Codex flagged the second one below. For a tokenizer with only isInForeignContext, unclosed CDATA now goes to oncdata when that returns true, as closed CDATA already did.
| input | Firefox 155, WebKit 26.6 | Chromium 153, parse5 8.0.1 | master | this PR |
|---|---|---|---|---|
<svg><foreignObject><![CDATA[x><b>]]></foreignObject></svg> | text x><b> | comment, live <b> | comment, live <b> | text x><b> |
<svg><title><![CDATA[x><b>]]></title></svg> | text x><b> | comment, live <b> | comment, live <b> | text x><b> |
<math><mi><![CDATA[x><b>]]></mi></math> | text x><b> | comment, live <b> | comment, live <b> | text x><b> |
<math><annotation-xml><![CDATA[x><b>]]></annotation-xml></math> | text x><b> | text x><b> | comment, live <b> | text x><b> |
<svg><foreignObject><div><![CDATA[x><b>]]></div></foreignObject></svg> | comment, live <b> | comment, live <b> | comment, live <b> | comment, live <b> |
The six cases from wpt#61253, run through parseDocument and compared with the trees in that file: master matches 3, this PR matches 6.
Tests: five event tests next to the existing foreign CDATA ones. Four fail on master: foreignObject, mtext and the two unclosed-at-EOF cases. The fifth puts a <p> inside foreignObject and passes on both, as a check that HTML content there still gets a bogus comment. npm run test:vi: 205 passed, and npm run lint passes, after merging the current master.
Summary by CodeRabbit
- Bug Fixes
- Corrected CDATA handling in SVG and MathML integration points: CDATA in foreign content is treated as text, while CDATA in the associated HTML context remains an HTML comment.
- Improved handling of CDATA in HTML paragraphs nested within SVG integration points.
- Corrected handling of unclosed CDATA at the end of input in SVG and SVG integration-point content.