Skip to content

Commit 81cff30

Browse files
authored
feat: support parsing type parameters (#141)
1 parent 9788f6e commit 81cff30

File tree

31 files changed

+1094
-106
lines changed

31 files changed

+1094
-106
lines changed

.changeset/long-yaks-smell.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"htmljs-parser": minor
3+
---
4+
5+
Add support for type parameter/argument parsing.
6+
This adds a new `onTagTypeParams`, `onTagTypeArgs` events and a `.typeParams` property on the `AttrMethod` range.

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,18 @@ const parser = createParser({
249249
range.expressions; // A list of placeholder ranges (similar to whats emitted via onPlaceholder).
250250
},
251251

252+
/**
253+
* Called after the type arguments for a tag have been parsed.
254+
*
255+
* @example
256+
* 1╭─ <foo<string>>
257+
* │ │╰─ tagTypeArgs.value "string"
258+
* ╰─ ╰─ tagTypeArgs "<string>"
259+
*/
260+
onTagTypeArgs(range) {
261+
range.value; // Another range that includes only the type arguments themselves and not the angle brackets.
262+
},
263+
252264
/**
253265
* Called after a tag variable has been parsed.
254266
*
@@ -273,6 +285,18 @@ const parser = createParser({
273285
range.value; // Another range that includes only the args themselves and not the outer parenthesis.
274286
},
275287

288+
/**
289+
* Called after type parameters for the tag parameters have been parsed.
290+
*
291+
* @example
292+
* 1╭─ <tag<T>|input: { name: T }|>
293+
* │ │╰─ tagTypeParams.value
294+
* ╰─ ╰─ tagTypeParams "<T>"
295+
*/
296+
onTagTypeParams(range) {
297+
range.value; // Another range that includes only the type params themselves and not the angle brackets.
298+
},
299+
276300
/**
277301
* Called after tag parameters have been parsed.
278302
*
@@ -334,6 +358,9 @@ const parser = createParser({
334358
* ╰─ ╰─ attrMethod "(ev) { foo(); }"
335359
*/
336360
onAttrMethod(range) {
361+
range.typeParams; // Another range which includes the type params for the method.
362+
range.typeParams.value; // Another range which includes the type params without outer angle brackets.
363+
337364
range.params; // Another range which includes the params for the method.
338365
range.params.value; // Another range which includes the method params without outer parenthesis.
339366

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
1╭─ <foo<A>(event: A){
2+
│ ││ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
3+
│ ││ ││ │╰─ attrMethod.params.value "event: A"
4+
│ ││ ││ ╰─ attrMethod.params "(event: A)"
5+
│ ││ │╰─ attrMethod.typeParams.value
6+
│ ││ ├─ attrMethod.typeParams "<A>"
7+
│ ││ ├─ attrMethod "<A>(event: A){\n console.log(event.type)\n}"
8+
│ ││ ╰─ attrName
9+
│ │╰─ tagName "foo"
10+
╰─ ╰─ openTagStart
11+
2╭─ console.log(event.type)
12+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
13+
3╭─ }/>
14+
╰─ ╰─ openTagEnd:selfClosed "/>"
15+
4├─
16+
5╭─ <foo<A> (event: A){
17+
│ ││ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
18+
│ ││ ││ │╰─ attrMethod.params.value "event: A"
19+
│ ││ ││ ╰─ attrMethod.params "(event: A)"
20+
│ ││ │╰─ attrMethod.typeParams.value
21+
│ ││ ├─ attrMethod.typeParams "<A>"
22+
│ ││ ├─ attrMethod "<A> (event: A){\n console.log(event.type)\n}"
23+
│ ││ ╰─ attrName
24+
│ │╰─ tagName "foo"
25+
╰─ ╰─ openTagStart
26+
6╭─ console.log(event.type)
27+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
28+
7╭─ }/>
29+
╰─ ╰─ openTagEnd:selfClosed "/>"
30+
8├─
31+
9╭─ <foo <A>(event: A){
32+
│ ││ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
33+
│ ││ ││ │╰─ attrMethod.params.value "event: A"
34+
│ ││ ││ ╰─ attrMethod.params "(event: A)"
35+
│ ││ │╰─ attrMethod.typeParams.value
36+
│ ││ ├─ attrMethod.typeParams "<A>"
37+
│ ││ ├─ attrMethod "<A>(event: A){\n console.log(event.type)\n}"
38+
│ ││ ╰─ attrName
39+
│ │╰─ tagName "foo"
40+
╰─ ╰─ openTagStart
41+
10╭─ console.log(event.type)
42+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
43+
11╭─ }/>
44+
╰─ ╰─ openTagEnd:selfClosed "/>"
45+
12├─
46+
13╭─ <foo <A> (event: A){
47+
│ ││ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
48+
│ ││ ││ │╰─ attrMethod.params.value "event: A"
49+
│ ││ ││ ╰─ attrMethod.params "(event: A)"
50+
│ ││ │╰─ attrMethod.typeParams.value
51+
│ ││ ├─ attrMethod.typeParams "<A>"
52+
│ ││ ├─ attrMethod "<A> (event: A){\n console.log(event.type)\n}"
53+
│ ││ ╰─ attrName
54+
│ │╰─ tagName "foo"
55+
╰─ ╰─ openTagStart
56+
14╭─ console.log(event.type)
57+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
58+
15╭─ }/>
59+
╰─ ╰─ openTagEnd:selfClosed "/>"
60+
16├─
61+
17╭─ <foo<A, B = string>(event: A & B){
62+
│ ││ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
63+
│ ││ ││ │╰─ attrMethod.params.value "event: A & B"
64+
│ ││ ││ ╰─ attrMethod.params "(event: A & B)"
65+
│ ││ │╰─ attrMethod.typeParams.value "A, B = string"
66+
│ ││ ├─ attrMethod.typeParams "<A, B = string>"
67+
│ ││ ├─ attrMethod "<A, B = string>(event: A & B){\n console.log(event.type)\n}"
68+
│ ││ ╰─ attrName
69+
│ │╰─ tagName "foo"
70+
╰─ ╰─ openTagStart
71+
18╭─ console.log(event.type)
72+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
73+
19╭─ }/>
74+
╰─ ╰─ openTagEnd:selfClosed "/>"
75+
20├─
76+
21╭─ <foo<A, B = string> (event: A & B){
77+
│ ││ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
78+
│ ││ ││ │╰─ attrMethod.params.value "event: A & B"
79+
│ ││ ││ ╰─ attrMethod.params "(event: A & B)"
80+
│ ││ │╰─ attrMethod.typeParams.value "A, B = string"
81+
│ ││ ├─ attrMethod.typeParams "<A, B = string>"
82+
│ ││ ├─ attrMethod "<A, B = string> (event: A & B){\n console.log(event.type)\n}"
83+
│ ││ ╰─ attrName
84+
│ │╰─ tagName "foo"
85+
╰─ ╰─ openTagStart
86+
22╭─ console.log(event.type)
87+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
88+
23╭─ }/>
89+
╰─ ╰─ openTagEnd:selfClosed "/>"
90+
24├─
91+
25╭─ <foo <A, B = string>(event: A & B){
92+
│ ││ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
93+
│ ││ ││ │╰─ attrMethod.params.value "event: A & B"
94+
│ ││ ││ ╰─ attrMethod.params "(event: A & B)"
95+
│ ││ │╰─ attrMethod.typeParams.value "A, B = string"
96+
│ ││ ├─ attrMethod.typeParams "<A, B = string>"
97+
│ ││ ├─ attrMethod "<A, B = string>(event: A & B){\n console.log(event.type)\n}"
98+
│ ││ ╰─ attrName
99+
│ │╰─ tagName "foo"
100+
╰─ ╰─ openTagStart
101+
26╭─ console.log(event.type)
102+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
103+
27╭─ }/>
104+
╰─ ╰─ openTagEnd:selfClosed "/>"
105+
28├─
106+
29╭─ <foo <A, B = string> (event: A & B){
107+
│ ││ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
108+
│ ││ ││ │╰─ attrMethod.params.value "event: A & B"
109+
│ ││ ││ ╰─ attrMethod.params "(event: A & B)"
110+
│ ││ │╰─ attrMethod.typeParams.value "A, B = string"
111+
│ ││ ├─ attrMethod.typeParams "<A, B = string>"
112+
│ ││ ├─ attrMethod "<A, B = string> (event: A & B){\n console.log(event.type)\n}"
113+
│ ││ ╰─ attrName
114+
│ │╰─ tagName "foo"
115+
╰─ ╰─ openTagStart
116+
30╭─ console.log(event.type)
117+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
118+
31╭─ }/>
119+
╰─ ╰─ openTagEnd:selfClosed "/>"
120+
32╰─
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<foo<A>(event: A){
2+
console.log(event.type)
3+
}/>
4+
5+
<foo<A> (event: A){
6+
console.log(event.type)
7+
}/>
8+
9+
<foo <A>(event: A){
10+
console.log(event.type)
11+
}/>
12+
13+
<foo <A> (event: A){
14+
console.log(event.type)
15+
}/>
16+
17+
<foo<A, B = string>(event: A & B){
18+
console.log(event.type)
19+
}/>
20+
21+
<foo<A, B = string> (event: A & B){
22+
console.log(event.type)
23+
}/>
24+
25+
<foo <A, B = string>(event: A & B){
26+
console.log(event.type)
27+
}/>
28+
29+
<foo <A, B = string> (event: A & B){
30+
console.log(event.type)
31+
}/>
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
1╭─ <foo onclick<A>(event: A){
2+
│ ││ │ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
3+
│ ││ │ ││ │╰─ attrMethod.params.value "event: A"
4+
│ ││ │ ││ ╰─ attrMethod.params "(event: A)"
5+
│ ││ │ │╰─ attrMethod.typeParams.value
6+
│ ││ │ ├─ attrMethod.typeParams "<A>"
7+
│ ││ │ ╰─ attrMethod "<A>(event: A){\n console.log(event.type)\n}"
8+
│ ││ ╰─ attrName "onclick"
9+
│ │╰─ tagName "foo"
10+
╰─ ╰─ openTagStart
11+
2╭─ console.log(event.type)
12+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
13+
3╭─ }/>
14+
╰─ ╰─ openTagEnd:selfClosed "/>"
15+
4├─
16+
5╭─ <foo onclick<A> (event: A){
17+
│ ││ │ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
18+
│ ││ │ ││ │╰─ attrMethod.params.value "event: A"
19+
│ ││ │ ││ ╰─ attrMethod.params "(event: A)"
20+
│ ││ │ │╰─ attrMethod.typeParams.value
21+
│ ││ │ ├─ attrMethod.typeParams "<A>"
22+
│ ││ │ ╰─ attrMethod "<A> (event: A){\n console.log(event.type)\n}"
23+
│ ││ ╰─ attrName "onclick"
24+
│ │╰─ tagName "foo"
25+
╰─ ╰─ openTagStart
26+
6╭─ console.log(event.type)
27+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
28+
7╭─ }/>
29+
╰─ ╰─ openTagEnd:selfClosed "/>"
30+
8├─
31+
9╭─ <foo onclick <A>(event: A){
32+
│ ││ │ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
33+
│ ││ │ ││ │╰─ attrMethod.params.value "event: A"
34+
│ ││ │ ││ ╰─ attrMethod.params "(event: A)"
35+
│ ││ │ │╰─ attrMethod.typeParams.value
36+
│ ││ │ ├─ attrMethod.typeParams "<A>"
37+
│ ││ │ ╰─ attrMethod "<A>(event: A){\n console.log(event.type)\n}"
38+
│ ││ ╰─ attrName "onclick"
39+
│ │╰─ tagName "foo"
40+
╰─ ╰─ openTagStart
41+
10╭─ console.log(event.type)
42+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
43+
11╭─ }/>
44+
╰─ ╰─ openTagEnd:selfClosed "/>"
45+
12├─
46+
13╭─ <foo onclick <A> (event: A){
47+
│ ││ │ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
48+
│ ││ │ ││ │╰─ attrMethod.params.value "event: A"
49+
│ ││ │ ││ ╰─ attrMethod.params "(event: A)"
50+
│ ││ │ │╰─ attrMethod.typeParams.value
51+
│ ││ │ ├─ attrMethod.typeParams "<A>"
52+
│ ││ │ ╰─ attrMethod "<A> (event: A){\n console.log(event.type)\n}"
53+
│ ││ ╰─ attrName "onclick"
54+
│ │╰─ tagName "foo"
55+
╰─ ╰─ openTagStart
56+
14╭─ console.log(event.type)
57+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
58+
15╭─ }/>
59+
╰─ ╰─ openTagEnd:selfClosed "/>"
60+
16├─
61+
17╭─ <foo onclick<A, B = string>(event: A & B){
62+
│ ││ │ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
63+
│ ││ │ ││ │╰─ attrMethod.params.value "event: A & B"
64+
│ ││ │ ││ ╰─ attrMethod.params "(event: A & B)"
65+
│ ││ │ │╰─ attrMethod.typeParams.value "A, B = string"
66+
│ ││ │ ├─ attrMethod.typeParams "<A, B = string>"
67+
│ ││ │ ╰─ attrMethod "<A, B = string>(event: A & B){\n console.log(event.type)\n}"
68+
│ ││ ╰─ attrName "onclick"
69+
│ │╰─ tagName "foo"
70+
╰─ ╰─ openTagStart
71+
18╭─ console.log(event.type)
72+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
73+
19╭─ }/>
74+
╰─ ╰─ openTagEnd:selfClosed "/>"
75+
20├─
76+
21╭─ <foo onclick<A, B = string> (event: A & B){
77+
│ ││ │ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
78+
│ ││ │ ││ │╰─ attrMethod.params.value "event: A & B"
79+
│ ││ │ ││ ╰─ attrMethod.params "(event: A & B)"
80+
│ ││ │ │╰─ attrMethod.typeParams.value "A, B = string"
81+
│ ││ │ ├─ attrMethod.typeParams "<A, B = string>"
82+
│ ││ │ ╰─ attrMethod "<A, B = string> (event: A & B){\n console.log(event.type)\n}"
83+
│ ││ ╰─ attrName "onclick"
84+
│ │╰─ tagName "foo"
85+
╰─ ╰─ openTagStart
86+
22╭─ console.log(event.type)
87+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
88+
23╭─ }/>
89+
╰─ ╰─ openTagEnd:selfClosed "/>"
90+
24├─
91+
25╭─ <foo onclick <A, B = string>(event: A & B){
92+
│ ││ │ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
93+
│ ││ │ ││ │╰─ attrMethod.params.value "event: A & B"
94+
│ ││ │ ││ ╰─ attrMethod.params "(event: A & B)"
95+
│ ││ │ │╰─ attrMethod.typeParams.value "A, B = string"
96+
│ ││ │ ├─ attrMethod.typeParams "<A, B = string>"
97+
│ ││ │ ╰─ attrMethod "<A, B = string>(event: A & B){\n console.log(event.type)\n}"
98+
│ ││ ╰─ attrName "onclick"
99+
│ │╰─ tagName "foo"
100+
╰─ ╰─ openTagStart
101+
26╭─ console.log(event.type)
102+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
103+
27╭─ }/>
104+
╰─ ╰─ openTagEnd:selfClosed "/>"
105+
28├─
106+
29╭─ <foo onclick <A, B = string> (event: A & B){
107+
│ ││ │ ││ ││ ╰─ attrMethod.body "{\n console.log(event.type)\n}"
108+
│ ││ │ ││ │╰─ attrMethod.params.value "event: A & B"
109+
│ ││ │ ││ ╰─ attrMethod.params "(event: A & B)"
110+
│ ││ │ │╰─ attrMethod.typeParams.value "A, B = string"
111+
│ ││ │ ├─ attrMethod.typeParams "<A, B = string>"
112+
│ ││ │ ╰─ attrMethod "<A, B = string> (event: A & B){\n console.log(event.type)\n}"
113+
│ ││ ╰─ attrName "onclick"
114+
│ │╰─ tagName "foo"
115+
╰─ ╰─ openTagStart
116+
30╭─ console.log(event.type)
117+
╰─ ╰─ attrMethod.body.value "\n console.log(event.type)\n"
118+
31╭─ }/>
119+
╰─ ╰─ openTagEnd:selfClosed "/>"
120+
32╰─
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<foo onclick<A>(event: A){
2+
console.log(event.type)
3+
}/>
4+
5+
<foo onclick<A> (event: A){
6+
console.log(event.type)
7+
}/>
8+
9+
<foo onclick <A>(event: A){
10+
console.log(event.type)
11+
}/>
12+
13+
<foo onclick <A> (event: A){
14+
console.log(event.type)
15+
}/>
16+
17+
<foo onclick<A, B = string>(event: A & B){
18+
console.log(event.type)
19+
}/>
20+
21+
<foo onclick<A, B = string> (event: A & B){
22+
console.log(event.type)
23+
}/>
24+
25+
<foo onclick <A, B = string>(event: A & B){
26+
console.log(event.type)
27+
}/>
28+
29+
<foo onclick <A, B = string> (event: A & B){
30+
console.log(event.type)
31+
}/>
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
1╭─ tagname <span>hello frank</span>
2-
│ │ ╰─ error(INVALID_ATTRIBUTE_NAME:Invalid attribute name. Attribute name cannot begin with the "<" character.)
2+
│ │ ││ │ │ ╰─ error(INVALID_ATTR_TYPE_PARAMS:Attribute cannot contain type parameters unless it is a shorthand method) "/span"
3+
│ │ ││ │ ╰─ attrName "frank"
4+
│ │ ││ ╰─ attrName "hello"
5+
│ │ │╰─ tagTypeArgs.value "span"
6+
│ │ ╰─ tagTypeArgs "<span>"
37
╰─ ╰─ tagName "tagname"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
1╭─ <foo/, x=1/>
2+
│ ││ ╰─ error(MISSING_TAG_VARIABLE:A slash was found that was not followed by a variable name or lhs expression)
3+
│ │╰─ tagName "foo"
4+
╰─ ╰─ openTagStart
5+
2╰─
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<foo/, x=1/>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
1╭─ <foo|a||b|>
2+
│ ││ ││ ╰─ error(INVALID_TAG_PARAMS:A tag can only specify parameters once)
3+
│ ││ │╰─ tagParams.value
4+
│ ││ ╰─ tagParams "|a|"
5+
│ │╰─ tagName "foo"
6+
╰─ ╰─ openTagStart
7+
2├─
8+
3├─ </foo>
9+
4╰─

0 commit comments

Comments
 (0)