Skip to content

Commit 72b3379

Browse files
committed
fix: ensure unary expression continuation is a word boundary
1 parent 785a593 commit 72b3379

File tree

4 files changed

+104
-1
lines changed

4 files changed

+104
-1
lines changed

.changeset/stale-impalas-visit.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"htmljs-parser": patch
3+
---
4+
5+
Fix regression where the parser would continue unary keyword expressions even if the keyword was inside a word boundary. Eg `<div class=thing_new x>` would cause the parser to see the expression as `thing_` and `new x`.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
1╭─ tag a = class b {}
2+
│ │ │ │ ╰─ attrValue.value "class b {}"
3+
│ │ │ ╰─ attrValue "= class b {}"
4+
│ │ ╰─ attrName
5+
╰─ ╰─ tagName "tag"
6+
2╭─
7+
╰─ ╰─ openTagEnd
8+
3╭─ tag a = class, b
9+
│ │ │ │ │ ╰─ attrName
10+
│ │ │ │ ╰─ attrValue.value "class"
11+
│ │ │ ╰─ attrValue "= class"
12+
│ │ ╰─ attrName
13+
│ ├─ closeTagEnd(tag)
14+
╰─ ╰─ tagName "tag"
15+
4╭─
16+
╰─ ╰─ openTagEnd
17+
5╭─ <tag a = class></tag>
18+
│ ││ │ │ │ ││ │ ╰─ closeTagEnd(tag)
19+
│ ││ │ │ │ ││ ╰─ closeTagName "tag"
20+
│ ││ │ │ │ │╰─ closeTagStart "</"
21+
│ ││ │ │ │ ╰─ openTagEnd
22+
│ ││ │ │ ╰─ attrValue.value "class"
23+
│ ││ │ ╰─ attrValue "= class"
24+
│ ││ ╰─ attrName
25+
│ │╰─ tagName "tag"
26+
│ ├─ closeTagEnd(tag)
27+
╰─ ╰─ openTagStart
28+
6├─
29+
7╭─ <tag a = class/>
30+
│ ││ │ │ │ ╰─ openTagEnd:selfClosed "/>"
31+
│ ││ │ │ ╰─ attrValue.value "class"
32+
│ ││ │ ╰─ attrValue "= class"
33+
│ ││ ╰─ attrName
34+
│ │╰─ tagName "tag"
35+
╰─ ╰─ openTagStart
36+
8├─
37+
9╭─ tag a = classthing b
38+
│ │ │ │ │ ╰─ attrName
39+
│ │ │ │ ╰─ attrValue.value "classthing"
40+
│ │ │ ╰─ attrValue "= classthing"
41+
│ │ ╰─ attrName
42+
╰─ ╰─ tagName "tag"
43+
10╭─
44+
╰─ ╰─ openTagEnd
45+
11╭─ tag a = testclass b
46+
│ │ │ │ │ ╰─ attrName
47+
│ │ │ │ ╰─ attrValue.value "testclass"
48+
│ │ │ ╰─ attrValue "= testclass"
49+
│ │ ╰─ attrName
50+
│ ├─ closeTagEnd(tag)
51+
╰─ ╰─ tagName "tag"
52+
12╭─
53+
╰─ ╰─ openTagEnd
54+
13╭─ tag a = test_class b
55+
│ │ │ │ │ ╰─ attrName
56+
│ │ │ │ ╰─ attrValue.value "test_class"
57+
│ │ │ ╰─ attrValue "= test_class"
58+
│ │ ╰─ attrName
59+
│ ├─ closeTagEnd(tag)
60+
╰─ ╰─ tagName "tag"
61+
14╭─
62+
╰─ ╰─ openTagEnd
63+
15╭─ tag a = test$class b
64+
│ │ │ │ │ ╰─ attrName
65+
│ │ │ │ ╰─ attrValue.value "test$class"
66+
│ │ │ ╰─ attrValue "= test$class"
67+
│ │ ╰─ attrName
68+
│ ├─ closeTagEnd(tag)
69+
╰─ ╰─ tagName "tag"
70+
16╭─
71+
╰─ ╰─ openTagEnd
72+
17╭─ tag a = test+class b
73+
│ │ │ │ ╰─ attrValue.value "test+class b"
74+
│ │ │ ╰─ attrValue "= test+class b"
75+
│ │ ╰─ attrName
76+
│ ├─ closeTagEnd(tag)
77+
╰─ ╰─ tagName "tag"
78+
18╭─
79+
│ ├─ openTagEnd
80+
╰─ ╰─ closeTagEnd(tag)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tag a = class b {}
2+
3+
tag a = class, b
4+
5+
<tag a = class></tag>
6+
7+
<tag a = class/>
8+
9+
tag a = classthing b
10+
11+
tag a = testclass b
12+
13+
tag a = test_class b
14+
15+
tag a = test$class b
16+
17+
tag a = test+class b

src/states/EXPRESSION.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ function lookBehindForOperator(data: string, pos: number): number {
296296
for (const keyword of unaryKeywords) {
297297
const keywordPos = lookBehindFor(data, curPos, keyword);
298298
if (keywordPos !== -1) {
299-
return data.charCodeAt(keywordPos - 1) === CODE.PERIOD
299+
const prevCode = data.charCodeAt(keywordPos - 1);
300+
return prevCode === CODE.PERIOD || isWordCode(prevCode)
300301
? -1
301302
: keywordPos;
302303
}

0 commit comments

Comments
 (0)