Skip to content

Commit 57c9910

Browse files
committedMay 6, 2024
Fix non-lowercase SVG elements not closing
Closes GH-23.
1 parent 671a5a4 commit 57c9910

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed
 

‎lib/index.js

+12-9
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@ function setPoint(state, point) {
523523
* Nothing.
524524
*/
525525
function startTag(node, state) {
526+
const tagName = node.tagName.toLowerCase()
527+
526528
// Ignore tags if we’re in plain text.
527529
if (state.parser.tokenizer.state === TokenizerMode.PLAINTEXT) return
528530

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

534-
if (ns === webNamespaces.html && node.tagName === 'svg') {
536+
if (ns === webNamespaces.html && tagName === 'svg') {
535537
ns = webNamespaces.svg
536538
}
537539

@@ -544,8 +546,8 @@ function startTag(node, state) {
544546
/** @type {TagToken} */
545547
const tag = {
546548
type: Token.TokenType.START_TAG,
547-
tagName: node.tagName,
548-
tagID: html.getTagID(node.tagName),
549+
tagName,
550+
tagID: html.getTagID(tagName),
549551
// We always send start and end tags.
550552
selfClosing: false,
551553
ackSelfClosing: false,
@@ -571,7 +573,7 @@ function startTag(node, state) {
571573
// do, such as:
572574

573575
// Set a tag name, similar to how the tokenizer would do it.
574-
state.parser.tokenizer.lastStartTagName = node.tagName
576+
state.parser.tokenizer.lastStartTagName = tagName
575577

576578
// `inForeignNode` is correctly set by the parser.
577579
}
@@ -587,10 +589,11 @@ function startTag(node, state) {
587589
* Nothing.
588590
*/
589591
function endTag(node, state) {
592+
const tagName = node.tagName.toLowerCase()
590593
// Do not emit closing tags for HTML void elements.
591594
if (
592595
!state.parser.tokenizer.inForeignNode &&
593-
htmlVoidElements.includes(node.tagName)
596+
htmlVoidElements.includes(tagName)
594597
) {
595598
return
596599
}
@@ -603,8 +606,8 @@ function endTag(node, state) {
603606
/** @type {TagToken} */
604607
const tag = {
605608
type: Token.TokenType.END_TAG,
606-
tagName: node.tagName,
607-
tagID: html.getTagID(node.tagName),
609+
tagName,
610+
tagID: html.getTagID(tagName),
608611
selfClosing: false,
609612
ackSelfClosing: false,
610613
attrs: [],
@@ -630,7 +633,7 @@ function endTag(node, state) {
630633
// tags:
631634
if (
632635
// Current element is closed.
633-
tag.tagName === state.parser.tokenizer.lastStartTagName &&
636+
tagName === state.parser.tokenizer.lastStartTagName &&
634637
// `<textarea>` and `<title>`
635638
(state.parser.tokenizer.state === TokenizerMode.RCDATA ||
636639
// `<iframe>`, `<noembed>`, `<style>`, `<xmp>`
@@ -655,7 +658,7 @@ function documentMode(node) {
655658
return Boolean(
656659
head &&
657660
(head.type === 'doctype' ||
658-
(head.type === 'element' && head.tagName === 'html'))
661+
(head.type === 'element' && head.tagName.toLowerCase() === 'html'))
659662
)
660663
}
661664

‎test.js

+29
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,35 @@ test('raw', async function (t) {
237237
)
238238
})
239239

240+
await t.test('should support camelcased SVG elements', async function () {
241+
assert.deepEqual(
242+
raw(
243+
s(undefined, [
244+
s('svg', [
245+
s('circle'),
246+
s('rect'),
247+
s('linearGradient'),
248+
s('path'),
249+
s('g')
250+
])
251+
])
252+
),
253+
{
254+
type: 'root',
255+
children: [
256+
s('svg', [
257+
s('circle'),
258+
s('rect'),
259+
s('linearGradient'),
260+
s('path'),
261+
s('g')
262+
])
263+
],
264+
data: {quirksMode: false}
265+
}
266+
)
267+
})
268+
240269
await t.test(
241270
'should discard broken HTML when a proper element node is found',
242271
async function () {

0 commit comments

Comments
 (0)
Please sign in to comment.