File tree Expand file tree Collapse file tree 6 files changed +478
-2
lines changed
src/compiler/phases/1-parse
parser-legacy/samples/loose-invalid-expression
parser-modern/samples/loose-invalid-expression Expand file tree Collapse file tree 6 files changed +478
-2
lines changed Original file line number Diff line number Diff line change @@ -39,6 +39,38 @@ export default function read_expression(parser) {
3939
4040 return /** @type {Expression } */ ( node ) ;
4141 } catch ( err ) {
42+ if ( parser . loose ) {
43+ // Find the next } and treat it as the end of the expression
44+ let index = parser . index ;
45+ let num_braces = 0 ;
46+ while ( index < parser . template . length ) {
47+ const char = parser . template [ index ] ;
48+ if ( char === '{' ) num_braces += 1 ;
49+ if ( char === '}' ) {
50+ if ( num_braces === 0 ) {
51+ // We assume that there's some kind of whitespace or the start of the closing tag after the closing brace,
52+ // else this hints at a wrong counting of braces (e.g. in the case of foo={'hi}' })
53+ if ( ! / [ \s > / ] / . test ( parser . template [ index + 1 ] ) ) {
54+ num_braces += 1 ;
55+ continue ;
56+ }
57+
58+ const start = parser . index ;
59+ parser . index = index ;
60+ // We don't know what the expression is and signal this by returning an empty identifier
61+ return {
62+ type : 'Identifier' ,
63+ start,
64+ end : index ,
65+ name : ''
66+ } ;
67+ }
68+ num_braces -= 1 ;
69+ }
70+ index += 1 ;
71+ }
72+ }
73+
4274 parser . acorn_error ( err ) ;
4375 }
4476}
Original file line number Diff line number Diff line change @@ -481,7 +481,7 @@ function read_attribute(parser) {
481481 return spread ;
482482 } else {
483483 const value_start = parser . index ;
484- const name = parser . read_identifier ( ) ;
484+ let name = parser . read_identifier ( ) ;
485485
486486 if ( name === null ) {
487487 if (
@@ -491,8 +491,12 @@ function read_attribute(parser) {
491491 // We're likely in an unclosed opening tag and did read part of a block.
492492 // Return null to not crash the parser so it can continue with closing the tag.
493493 return null ;
494+ } else if ( parser . loose && parser . match ( '}' ) ) {
495+ // Likely in the middle of typing, just created the shorthand
496+ name = '' ;
497+ } else {
498+ e . attribute_empty_shorthand ( start ) ;
494499 }
495- e . attribute_empty_shorthand ( start ) ;
496500 }
497501
498502 parser . allow_whitespace ( ) ;
Original file line number Diff line number Diff line change 1+ <div {}></div >
2+ <div foo ={}></div >
3+
4+ <div foo ={a .}></div >
5+ <div foo ={' hi}' .}></div >
6+ <Component onclick ={() => x .} />
7+
8+ <input bind:value ={a .} />
Original file line number Diff line number Diff line change 1+ {
2+ "html" : {
3+ "type" : " Fragment" ,
4+ "start" : 0 ,
5+ "end" : 140 ,
6+ "children" : [
7+ {
8+ "type" : " Element" ,
9+ "start" : 0 ,
10+ "end" : 14 ,
11+ "name" : " div" ,
12+ "attributes" : [
13+ {
14+ "type" : " Attribute" ,
15+ "start" : 5 ,
16+ "end" : 7 ,
17+ "name" : " " ,
18+ "value" : [
19+ {
20+ "type" : " AttributeShorthand" ,
21+ "start" : 6 ,
22+ "end" : 6 ,
23+ "expression" : {
24+ "start" : 6 ,
25+ "end" : 6 ,
26+ "type" : " Identifier" ,
27+ "name" : " "
28+ }
29+ }
30+ ]
31+ }
32+ ],
33+ "children" : []
34+ },
35+ {
36+ "type" : " Text" ,
37+ "start" : 14 ,
38+ "end" : 15 ,
39+ "raw" : " \n " ,
40+ "data" : " \n "
41+ },
42+ {
43+ "type" : " Element" ,
44+ "start" : 15 ,
45+ "end" : 33 ,
46+ "name" : " div" ,
47+ "attributes" : [
48+ {
49+ "type" : " Attribute" ,
50+ "start" : 20 ,
51+ "end" : 26 ,
52+ "name" : " foo" ,
53+ "value" : [
54+ {
55+ "type" : " MustacheTag" ,
56+ "start" : 24 ,
57+ "end" : 26 ,
58+ "expression" : {
59+ "type" : " Identifier" ,
60+ "start" : 25 ,
61+ "end" : 25 ,
62+ "name" : " "
63+ }
64+ }
65+ ]
66+ }
67+ ],
68+ "children" : []
69+ },
70+ {
71+ "type" : " Text" ,
72+ "start" : 33 ,
73+ "end" : 35 ,
74+ "raw" : " \n\n " ,
75+ "data" : " \n\n "
76+ },
77+ {
78+ "type" : " Element" ,
79+ "start" : 35 ,
80+ "end" : 55 ,
81+ "name" : " div" ,
82+ "attributes" : [
83+ {
84+ "type" : " Attribute" ,
85+ "start" : 40 ,
86+ "end" : 48 ,
87+ "name" : " foo" ,
88+ "value" : [
89+ {
90+ "type" : " MustacheTag" ,
91+ "start" : 44 ,
92+ "end" : 48 ,
93+ "expression" : {
94+ "type" : " Identifier" ,
95+ "start" : 45 ,
96+ "end" : 47 ,
97+ "name" : " "
98+ }
99+ }
100+ ]
101+ }
102+ ],
103+ "children" : []
104+ },
105+ {
106+ "type" : " Text" ,
107+ "start" : 55 ,
108+ "end" : 56 ,
109+ "raw" : " \n " ,
110+ "data" : " \n "
111+ },
112+ {
113+ "type" : " Element" ,
114+ "start" : 56 ,
115+ "end" : 80 ,
116+ "name" : " div" ,
117+ "attributes" : [
118+ {
119+ "type" : " Attribute" ,
120+ "start" : 61 ,
121+ "end" : 73 ,
122+ "name" : " foo" ,
123+ "value" : [
124+ {
125+ "type" : " MustacheTag" ,
126+ "start" : 65 ,
127+ "end" : 73 ,
128+ "expression" : {
129+ "type" : " Identifier" ,
130+ "start" : 66 ,
131+ "end" : 72 ,
132+ "name" : " "
133+ }
134+ }
135+ ]
136+ }
137+ ],
138+ "children" : []
139+ },
140+ {
141+ "type" : " Text" ,
142+ "start" : 80 ,
143+ "end" : 81 ,
144+ "raw" : " \n " ,
145+ "data" : " \n "
146+ },
147+ {
148+ "type" : " InlineComponent" ,
149+ "start" : 81 ,
150+ "end" : 113 ,
151+ "name" : " Component" ,
152+ "attributes" : [
153+ {
154+ "type" : " Attribute" ,
155+ "start" : 92 ,
156+ "end" : 110 ,
157+ "name" : " onclick" ,
158+ "value" : [
159+ {
160+ "type" : " MustacheTag" ,
161+ "start" : 100 ,
162+ "end" : 110 ,
163+ "expression" : {
164+ "type" : " Identifier" ,
165+ "start" : 101 ,
166+ "end" : 109 ,
167+ "name" : " "
168+ }
169+ }
170+ ]
171+ }
172+ ],
173+ "children" : []
174+ },
175+ {
176+ "type" : " Text" ,
177+ "start" : 113 ,
178+ "end" : 115 ,
179+ "raw" : " \n\n " ,
180+ "data" : " \n\n "
181+ },
182+ {
183+ "type" : " Element" ,
184+ "start" : 115 ,
185+ "end" : 140 ,
186+ "name" : " input" ,
187+ "attributes" : [
188+ {
189+ "start" : 122 ,
190+ "end" : 137 ,
191+ "type" : " Binding" ,
192+ "name" : " value" ,
193+ "expression" : {
194+ "type" : " Identifier" ,
195+ "start" : 134 ,
196+ "end" : 136 ,
197+ "name" : " "
198+ },
199+ "modifiers" : []
200+ }
201+ ],
202+ "children" : []
203+ }
204+ ]
205+ }
206+ }
Original file line number Diff line number Diff line change 1+ <div {}></div >
2+ <div foo ={}></div >
3+
4+ <div foo ={a .}></div >
5+ <div foo ={' hi}' .}></div >
6+ <Component onclick ={() => x .} />
7+
8+ <input bind:value ={a .} />
You can’t perform that action at this time.
0 commit comments