Skip to content

Commit 9034f55

Browse files
committed
feat: tag var type is continuable expression
1 parent 01ed0a4 commit 9034f55

File tree

5 files changed

+76
-25
lines changed

5 files changed

+76
-25
lines changed

.changeset/fluffy-emus-try.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"htmljs-parser": patch
3+
---
4+
5+
Parse tag variable type as an continuable expression.

src/__tests__/fixtures/tag-var-declaration/__snapshots__/tag-var-declaration.expected.txt

+52-22
Original file line numberDiff line numberDiff line change
@@ -33,51 +33,81 @@
3333
│ │ ╰─ tagVar "/foo"
3434
╰─ ╰─ tagName "let"
3535
7╭─ <let/foo + 1/>
36-
│ │ ││ │ │╰─ openTagEnd:selfClosed "/>"
37-
│ │ ││ │ ╰─ attrName
38-
│ │ ││ ╰─ attrName
39-
│ │ │╰─ tagVar.value "foo"
40-
│ │ ╰─ tagVar "/foo"
36+
│ │ ││ ╰─ openTagEnd:selfClosed "/>"
37+
│ │ │╰─ tagVar.value "foo + 1"
38+
│ │ ╰─ tagVar "/foo + 1"
4139
╰─ ╰─ tagName "let"
42-
8╭─ <let/{ x, y }/>
43-
│ │ ││ ╰─ openTagEnd:selfClosed "/>"
44-
│ │ │╰─ tagVar.value "{ x, y }"
45-
│ │ ╰─ tagVar "/{ x, y }"
40+
8╭─ <let/foo:string/>
41+
│ │ ││ ╰─ openTagEnd:selfClosed "/>"
42+
│ │ │╰─ tagVar.value "foo:string"
43+
│ │ ╰─ tagVar "/foo:string"
4644
╰─ ╰─ tagName "let"
47-
9├─
48-
10╭─ <button/loginButton>
45+
9╭─ <let/foo : string/>
46+
│ │ ││ ╰─ openTagEnd:selfClosed "/>"
47+
│ │ │╰─ tagVar.value "foo : string"
48+
│ │ ╰─ tagVar "/foo : string"
49+
╰─ ╰─ tagName "let"
50+
10╭─ <let/foo: typeof bar extends y ? a : b x=2/>
51+
│ │ ││ │││╰─ openTagEnd:selfClosed "/>"
52+
│ │ ││ ││╰─ attrValue.value
53+
│ │ ││ │╰─ attrValue "=2"
54+
│ │ ││ ╰─ attrName
55+
│ │ │╰─ tagVar.value "foo: typeof bar extends y ? a : b"
56+
│ │ ╰─ tagVar "/foo: typeof bar extends y ? a : b"
57+
╰─ ╰─ tagName "let"
58+
11╭─ <let/{ x, y }/>
59+
│ │ ││ ╰─ openTagEnd:selfClosed "/>"
60+
│ │ │╰─ tagVar.value "{ x, y }"
61+
│ │ ╰─ tagVar "/{ x, y }"
62+
╰─ ╰─ tagName "let"
63+
12├─
64+
13╭─ <const/fn:any() {
65+
│ │ ││ ││ ╰─ attrMethod.body "{\n console.log(\"hi\");\n}"
66+
│ │ ││ │╰─ attrMethod.params.value
67+
│ │ ││ ├─ attrMethod.params "()"
68+
│ │ ││ ├─ attrMethod "() {\n console.log(\"hi\");\n}"
69+
│ │ ││ ╰─ attrName
70+
│ │ │╰─ tagVar.value "fn:any"
71+
│ │ ╰─ tagVar "/fn:any"
72+
╰─ ╰─ tagName "const"
73+
14╭─ console.log("hi");
74+
╰─ ╰─ attrMethod.body.value "\n console.log(\"hi\");\n"
75+
15╭─ }/>
76+
╰─ ╰─ openTagEnd:selfClosed "/>"
77+
16├─
78+
17╭─ <button/loginButton>
4979
│ │ ││ ╰─ openTagEnd
5080
│ │ │╰─ tagVar.value "loginButton"
5181
│ │ ╰─ tagVar "/loginButton"
5282
╰─ ╰─ tagName "button"
53-
11╭─ login
83+
18╭─ login
5484
╰─ ╰─ text "\n login\n"
55-
12╭─ </>
85+
19╭─ </>
5686
│ │ ╰─ closeTag(button).value
5787
╰─ ╰─ closeTag(button) "</>"
58-
13╭─ <button/loginButton >
88+
20╭─ <button/loginButton >
5989
│ │ ││ ╰─ openTagEnd
6090
│ │ │╰─ tagVar.value "loginButton"
6191
│ │ ╰─ tagVar "/loginButton"
6292
╰─ ╰─ tagName "button"
63-
14╭─ login
93+
21╭─ login
6494
╰─ ╰─ text "\n login\n"
65-
15╭─ </>
95+
22╭─ </>
6696
│ │ ╰─ closeTag(button).value
6797
╰─ ╰─ closeTag(button) "</>"
68-
16├─
69-
17╭─ <div/ref/>
98+
23├─
99+
24╭─ <div/ref/>
70100
│ │ ││ ╰─ openTagEnd:selfClosed "/>"
71101
│ │ │╰─ tagVar.value "ref"
72102
│ │ ╰─ tagVar "/ref"
73103
╰─ ╰─ tagName "div"
74-
18╭─ <div/ref />
104+
25╭─ <div/ref />
75105
│ │ ││ ╰─ openTagEnd:selfClosed "/>"
76106
│ │ │╰─ tagVar.value "ref"
77107
│ │ ╰─ tagVar "/ref"
78108
╰─ ╰─ tagName "div"
79-
19├─
80-
20╭─ <div#ab.cd/ref/>
109+
26├─
110+
27╭─ <div#ab.cd/ref/>
81111
│ │ ││ ││ ││ ╰─ openTagEnd:selfClosed "/>"
82112
│ │ ││ ││ │╰─ tagVar.value "ref"
83113
│ │ ││ ││ ╰─ tagVar "/ref"
@@ -86,4 +116,4 @@
86116
│ │ │╰─ tagShorthandId.quasis[0] "ab"
87117
│ │ ╰─ tagShorthandId "#ab"
88118
╰─ ╰─ tagName "div"
89-
21╰─
119+
28╰─

src/__tests__/fixtures/tag-var-declaration/input.marko

+7
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@
55
<let/foo=1/>
66
<let/foo = 1/>
77
<let/foo + 1/>
8+
<let/foo:string/>
9+
<let/foo : string/>
10+
<let/foo: typeof bar extends y ? a : b x=2/>
811
<let/{ x, y }/>
912

13+
<const/fn:any() {
14+
console.log("hi");
15+
}/>
16+
1017
<button/loginButton>
1118
login
1219
</>

src/states/EXPRESSION.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,9 @@ export const EXPRESSION: StateDefinition<ExpressionMeta> = {
203203

204204
function buildOperatorPattern(isConcise: boolean) {
205205
const binary =
206-
"(?:[!~*%&^|?:<]+=*)+" + // Any of these characters can always continue an expression
207-
"|[>/+-=]+=|=>" + // Match equality and multi char assignment operators w/o matching equals by itself
206+
"(?:[!~*%&^|?<]+=*)+" + // Any of these characters can always continue an expression
207+
"|:+(?!=)" + // Match a colon without matching a bound attribute
208+
"|[>/+=-]+=|=>" + // Match equality and multi char assignment operators w/o matching equals by itself
208209
"|(?<!\\+)[ \\t]*\\+(?:[ \\t]*\\+[ \\t]*\\+)*[ \\t]*(?!\\+)" + // We only match an odd number of plus's
209210
`|(?<!-)-${isConcise ? "" : "(?:[ \\t]*-[ \\t]*-)*[ \\t]*"}(?!-)` + // In concise mode we can't match multiple hyphens otherwise we can match an even number of hyphens
210211
`|(?<![/*])/(?![/*${isConcise ? "" : ">"}])` + // We only continue after a forward slash if it isn't //, /* (or /> in html mode)

src/states/OPEN_TAG.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,16 @@ export const OPEN_TAG: StateDefinition<OpenTagMeta> = {
292292
} else if (code === CODE.FORWARD_SLASH && !tag.hasAttrs) {
293293
tag.stage = TAG_STAGE.VAR;
294294
this.pos++; // skip /
295+
296+
if (isWhitespaceCode(this.lookAtCharCodeAhead(0))) {
297+
return this.emitError(
298+
this.pos,
299+
ErrorCode.MISSING_TAG_VARIABLE,
300+
"A slash was found that was not followed by a variable name or lhs expression"
301+
);
302+
}
303+
295304
const expr = this.enterState(STATE.EXPRESSION);
296-
expr.skipOperators = true;
297305
expr.terminatedByWhitespace = true;
298306
expr.terminator = this.isConcise
299307
? CONCISE_TAG_VAR_TERMINATORS

0 commit comments

Comments
 (0)