Skip to content

Commit 973b51d

Browse files
fix: correctly parse leading comments in function binding (#15020)
* fix: correctly parse leading comments in function binding * chore: fix lint
1 parent 1d3c439 commit 973b51d

File tree

7 files changed

+368
-1
lines changed

7 files changed

+368
-1
lines changed

.changeset/violet-apes-punch.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: correctly parse leading comments in function binding

packages/svelte/src/compiler/phases/1-parse/read/expression.js

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ export default function read_expression(parser, opening_token, disallow_loose) {
3838

3939
let num_parens = 0;
4040

41+
if (node.leadingComments !== undefined && node.leadingComments.length > 0) {
42+
parser.index = node.leadingComments.at(-1).end;
43+
}
44+
4145
for (let i = parser.index; i < /** @type {number} */ (node.start); i += 1) {
4246
if (parser.template[i] === '(') num_parens += 1;
4347
}

packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,19 @@ export function BindDirective(node, context) {
132132
}
133133

134134
let i = /** @type {number} */ (node.expression.start);
135+
let leading_comments_start = /**@type {any}*/ (node.expression.leadingComments?.at(0))?.start;
136+
let leading_comments_end = /**@type {any}*/ (node.expression.leadingComments?.at(-1))?.end;
135137
while (context.state.analysis.source[--i] !== '{') {
136-
if (context.state.analysis.source[i] === '(') {
138+
if (
139+
context.state.analysis.source[i] === '(' &&
140+
// if the parenthesis is in a leading comment we don't need to throw the error
141+
!(
142+
leading_comments_start &&
143+
leading_comments_end &&
144+
i <= leading_comments_end &&
145+
i >= leading_comments_start
146+
)
147+
) {
137148
e.bind_invalid_parens(node, node.name);
138149
}
139150
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
let value = '';
3+
</script>
4+
5+
<input bind:value={
6+
/** ( */
7+
() => value,
8+
(v) => value = v.toLowerCase()
9+
}
10+
/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
{
2+
"css": null,
3+
"js": [],
4+
"start": 37,
5+
"end": 117,
6+
"type": "Root",
7+
"fragment": {
8+
"type": "Fragment",
9+
"nodes": [
10+
{
11+
"type": "Text",
12+
"start": 35,
13+
"end": 37,
14+
"raw": "\n\n",
15+
"data": "\n\n"
16+
},
17+
{
18+
"type": "RegularElement",
19+
"start": 37,
20+
"end": 117,
21+
"name": "input",
22+
"attributes": [
23+
{
24+
"start": 44,
25+
"end": 114,
26+
"type": "BindDirective",
27+
"name": "value",
28+
"expression": {
29+
"type": "SequenceExpression",
30+
"start": 68,
31+
"end": 112,
32+
"loc": {
33+
"start": {
34+
"line": 7,
35+
"column": 1
36+
},
37+
"end": {
38+
"line": 8,
39+
"column": 31
40+
}
41+
},
42+
"expressions": [
43+
{
44+
"type": "ArrowFunctionExpression",
45+
"start": 68,
46+
"end": 79,
47+
"loc": {
48+
"start": {
49+
"line": 7,
50+
"column": 1
51+
},
52+
"end": {
53+
"line": 7,
54+
"column": 12
55+
}
56+
},
57+
"id": null,
58+
"expression": true,
59+
"generator": false,
60+
"async": false,
61+
"params": [],
62+
"body": {
63+
"type": "Identifier",
64+
"start": 74,
65+
"end": 79,
66+
"loc": {
67+
"start": {
68+
"line": 7,
69+
"column": 7
70+
},
71+
"end": {
72+
"line": 7,
73+
"column": 12
74+
}
75+
},
76+
"name": "value"
77+
}
78+
},
79+
{
80+
"type": "ArrowFunctionExpression",
81+
"start": 82,
82+
"end": 112,
83+
"loc": {
84+
"start": {
85+
"line": 8,
86+
"column": 1
87+
},
88+
"end": {
89+
"line": 8,
90+
"column": 31
91+
}
92+
},
93+
"id": null,
94+
"expression": true,
95+
"generator": false,
96+
"async": false,
97+
"params": [
98+
{
99+
"type": "Identifier",
100+
"start": 83,
101+
"end": 84,
102+
"loc": {
103+
"start": {
104+
"line": 8,
105+
"column": 2
106+
},
107+
"end": {
108+
"line": 8,
109+
"column": 3
110+
}
111+
},
112+
"name": "v"
113+
}
114+
],
115+
"body": {
116+
"type": "AssignmentExpression",
117+
"start": 89,
118+
"end": 112,
119+
"loc": {
120+
"start": {
121+
"line": 8,
122+
"column": 8
123+
},
124+
"end": {
125+
"line": 8,
126+
"column": 31
127+
}
128+
},
129+
"operator": "=",
130+
"left": {
131+
"type": "Identifier",
132+
"start": 89,
133+
"end": 94,
134+
"loc": {
135+
"start": {
136+
"line": 8,
137+
"column": 8
138+
},
139+
"end": {
140+
"line": 8,
141+
"column": 13
142+
}
143+
},
144+
"name": "value"
145+
},
146+
"right": {
147+
"type": "CallExpression",
148+
"start": 97,
149+
"end": 112,
150+
"loc": {
151+
"start": {
152+
"line": 8,
153+
"column": 16
154+
},
155+
"end": {
156+
"line": 8,
157+
"column": 31
158+
}
159+
},
160+
"callee": {
161+
"type": "MemberExpression",
162+
"start": 97,
163+
"end": 110,
164+
"loc": {
165+
"start": {
166+
"line": 8,
167+
"column": 16
168+
},
169+
"end": {
170+
"line": 8,
171+
"column": 29
172+
}
173+
},
174+
"object": {
175+
"type": "Identifier",
176+
"start": 97,
177+
"end": 98,
178+
"loc": {
179+
"start": {
180+
"line": 8,
181+
"column": 16
182+
},
183+
"end": {
184+
"line": 8,
185+
"column": 17
186+
}
187+
},
188+
"name": "v"
189+
},
190+
"property": {
191+
"type": "Identifier",
192+
"start": 99,
193+
"end": 110,
194+
"loc": {
195+
"start": {
196+
"line": 8,
197+
"column": 18
198+
},
199+
"end": {
200+
"line": 8,
201+
"column": 29
202+
}
203+
},
204+
"name": "toLowerCase"
205+
},
206+
"computed": false,
207+
"optional": false
208+
},
209+
"arguments": [],
210+
"optional": false
211+
}
212+
}
213+
}
214+
],
215+
"leadingComments": [
216+
{
217+
"type": "Block",
218+
"value": "* ( ",
219+
"start": 58,
220+
"end": 66
221+
}
222+
]
223+
},
224+
"modifiers": []
225+
}
226+
],
227+
"fragment": {
228+
"type": "Fragment",
229+
"nodes": []
230+
}
231+
}
232+
]
233+
},
234+
"options": null,
235+
"instance": {
236+
"type": "Script",
237+
"start": 0,
238+
"end": 35,
239+
"context": "default",
240+
"content": {
241+
"type": "Program",
242+
"start": 8,
243+
"end": 26,
244+
"loc": {
245+
"start": {
246+
"line": 1,
247+
"column": 0
248+
},
249+
"end": {
250+
"line": 3,
251+
"column": 0
252+
}
253+
},
254+
"body": [
255+
{
256+
"type": "VariableDeclaration",
257+
"start": 10,
258+
"end": 25,
259+
"loc": {
260+
"start": {
261+
"line": 2,
262+
"column": 1
263+
},
264+
"end": {
265+
"line": 2,
266+
"column": 16
267+
}
268+
},
269+
"declarations": [
270+
{
271+
"type": "VariableDeclarator",
272+
"start": 14,
273+
"end": 24,
274+
"loc": {
275+
"start": {
276+
"line": 2,
277+
"column": 5
278+
},
279+
"end": {
280+
"line": 2,
281+
"column": 15
282+
}
283+
},
284+
"id": {
285+
"type": "Identifier",
286+
"start": 14,
287+
"end": 19,
288+
"loc": {
289+
"start": {
290+
"line": 2,
291+
"column": 5
292+
},
293+
"end": {
294+
"line": 2,
295+
"column": 10
296+
}
297+
},
298+
"name": "value"
299+
},
300+
"init": {
301+
"type": "Literal",
302+
"start": 22,
303+
"end": 24,
304+
"loc": {
305+
"start": {
306+
"line": 2,
307+
"column": 13
308+
},
309+
"end": {
310+
"line": 2,
311+
"column": 15
312+
}
313+
},
314+
"value": "",
315+
"raw": "''"
316+
}
317+
}
318+
],
319+
"kind": "let"
320+
}
321+
],
322+
"sourceType": "module"
323+
},
324+
"attributes": []
325+
}
326+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
let value = '';
3+
</script>
4+
5+
<input bind:value={
6+
/** ( */
7+
() => value,
8+
(v) => value = v.toLowerCase()
9+
}
10+
/>

0 commit comments

Comments
 (0)