Skip to content

Commit 88c9d6d

Browse files
authored
fix(unhead): parse HTML attribute values without backslash escaping (#774)
1 parent 90e7545 commit 88c9d6d

2 files changed

Lines changed: 29 additions & 4 deletions

File tree

packages/unhead/src/parser/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,10 @@ export function parseAttributes(attrStr: string): Record<string, string> {
195195
break
196196

197197
case QUOTED_VALUE:
198-
if (charCode === BACKSLASH_CHAR && i + 1 < len) {
199-
i++
200-
}
201-
else if (charCode === quoteChar) {
198+
// HTML attribute values have no backslash escaping; the quote char
199+
// always terminates the value (matches browser parsing and the
200+
// tag-boundary scanner above).
201+
if (charCode === quoteChar) {
202202
result[name] = attrStr.substring(valueStart, i)
203203
state = WHITESPACE
204204
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { parseAttributes } from '../../../src/parser'
3+
4+
describe('parseAttributes', () => {
5+
it('treats backslash as a literal char in quoted values', () => {
6+
// HTML has no backslash escaping in attribute values, so a trailing
7+
// backslash must not consume the closing quote.
8+
expect(parseAttributes('href="C:\\"')).toEqual({ href: 'C:\\' })
9+
})
10+
11+
it('does not let a backslash swallow the closing quote of an attribute', () => {
12+
expect(parseAttributes('content="a\\" name="description"')).toEqual({
13+
content: 'a\\',
14+
name: 'description',
15+
})
16+
})
17+
18+
it('parses basic quoted and unquoted attributes', () => {
19+
expect(parseAttributes('name="description" content=hello disabled')).toEqual({
20+
name: 'description',
21+
content: 'hello',
22+
disabled: '',
23+
})
24+
})
25+
})

0 commit comments

Comments
 (0)