Skip to content

Commit

Permalink
Fix non-lowercase SVG elements not closing
Browse files Browse the repository at this point in the history
Closes GH-23.
  • Loading branch information
wooorm committed May 6, 2024
1 parent 671a5a4 commit 57c9910
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 9 deletions.
21 changes: 12 additions & 9 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,8 @@ function setPoint(state, point) {
* Nothing.
*/
function startTag(node, state) {
const tagName = node.tagName.toLowerCase()

// Ignore tags if we’re in plain text.
if (state.parser.tokenizer.state === TokenizerMode.PLAINTEXT) return

Expand All @@ -531,7 +533,7 @@ function startTag(node, state) {
const current = state.parser.openElements.current
let ns = 'namespaceURI' in current ? current.namespaceURI : webNamespaces.html

if (ns === webNamespaces.html && node.tagName === 'svg') {
if (ns === webNamespaces.html && tagName === 'svg') {
ns = webNamespaces.svg
}

Expand All @@ -544,8 +546,8 @@ function startTag(node, state) {
/** @type {TagToken} */
const tag = {
type: Token.TokenType.START_TAG,
tagName: node.tagName,
tagID: html.getTagID(node.tagName),
tagName,
tagID: html.getTagID(tagName),
// We always send start and end tags.
selfClosing: false,
ackSelfClosing: false,
Expand All @@ -571,7 +573,7 @@ function startTag(node, state) {
// do, such as:

// Set a tag name, similar to how the tokenizer would do it.
state.parser.tokenizer.lastStartTagName = node.tagName
state.parser.tokenizer.lastStartTagName = tagName

// `inForeignNode` is correctly set by the parser.
}
Expand All @@ -587,10 +589,11 @@ function startTag(node, state) {
* Nothing.
*/
function endTag(node, state) {
const tagName = node.tagName.toLowerCase()
// Do not emit closing tags for HTML void elements.
if (
!state.parser.tokenizer.inForeignNode &&
htmlVoidElements.includes(node.tagName)
htmlVoidElements.includes(tagName)
) {
return
}
Expand All @@ -603,8 +606,8 @@ function endTag(node, state) {
/** @type {TagToken} */
const tag = {
type: Token.TokenType.END_TAG,
tagName: node.tagName,
tagID: html.getTagID(node.tagName),
tagName,
tagID: html.getTagID(tagName),
selfClosing: false,
ackSelfClosing: false,
attrs: [],
Expand All @@ -630,7 +633,7 @@ function endTag(node, state) {
// tags:
if (
// Current element is closed.
tag.tagName === state.parser.tokenizer.lastStartTagName &&
tagName === state.parser.tokenizer.lastStartTagName &&
// `<textarea>` and `<title>`
(state.parser.tokenizer.state === TokenizerMode.RCDATA ||
// `<iframe>`, `<noembed>`, `<style>`, `<xmp>`
Expand All @@ -655,7 +658,7 @@ function documentMode(node) {
return Boolean(
head &&
(head.type === 'doctype' ||
(head.type === 'element' && head.tagName === 'html'))
(head.type === 'element' && head.tagName.toLowerCase() === 'html'))
)
}

Expand Down
29 changes: 29 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,35 @@ test('raw', async function (t) {
)
})

await t.test('should support camelcased SVG elements', async function () {
assert.deepEqual(
raw(
s(undefined, [
s('svg', [
s('circle'),
s('rect'),
s('linearGradient'),
s('path'),
s('g')
])
])
),
{
type: 'root',
children: [
s('svg', [
s('circle'),
s('rect'),
s('linearGradient'),
s('path'),
s('g')
])
],
data: {quirksMode: false}
}
)
})

await t.test(
'should discard broken HTML when a proper element node is found',
async function () {
Expand Down

0 comments on commit 57c9910

Please sign in to comment.