Skip to content

Commit 965c12f

Browse files
fix: allow multiple optional parameters with defaults (#12070)
* fix: allow multiple optional parameters with defaults * Apply suggestions from code review * partial fix * feat: parse as a whole function * couple of fixes * work around acorn-typescript quirks * add the harder test * Update .changeset/ten-geese-share.md --------- Co-authored-by: Rich Harris <[email protected]> Co-authored-by: Rich Harris <[email protected]>
1 parent 5581216 commit 965c12f

File tree

7 files changed

+65
-35
lines changed

7 files changed

+65
-35
lines changed

.changeset/ten-geese-share.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: allow multiple optional parameters with defaults in snippets

packages/svelte/src/compiler/phases/1-parse/acorn.js

+11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as acorn from 'acorn';
22
import { walk } from 'zimmerframe';
33
import { tsPlugin } from 'acorn-typescript';
4+
import { locator } from '../../state.js';
45

56
const ParserWithTS = acorn.Parser.extend(tsPlugin({ allowSatisfies: true }));
67

@@ -127,6 +128,16 @@ function amend(source, node) {
127128
// @ts-expect-error
128129
delete node.loc.end.index;
129130

131+
if (typeof node.loc?.end === 'number') {
132+
const loc = locator(node.loc.end);
133+
if (loc) {
134+
node.loc.end = {
135+
line: loc.line,
136+
column: loc.column
137+
};
138+
}
139+
}
140+
130141
if (/** @type {any} */ (node).typeAnnotation && node.end === undefined) {
131142
// i think there might be a bug in acorn-typescript that prevents
132143
// `end` from being assigned when there's a type annotation

packages/svelte/src/compiler/phases/1-parse/state/tag.js

+18-29
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import read_expression from '../read/expression.js';
33
import * as e from '../../../errors.js';
44
import { create_fragment } from '../utils/create.js';
55
import { walk } from 'zimmerframe';
6+
import { parse_expression_at } from '../acorn.js';
67

78
const regex_whitespace_with_closing_curly_brace = /^\s*}/;
89

@@ -268,39 +269,28 @@ function open(parser) {
268269
e.expected_identifier(parser.index);
269270
}
270271

271-
parser.eat('(', true);
272-
273-
parser.allow_whitespace();
274-
275-
/** @type {import('estree').Pattern[]} */
276-
const parameters = [];
272+
let slice_end = parser.index;
277273

278-
while (!parser.match(')')) {
279-
let pattern = read_pattern(parser, true);
280-
281-
parser.allow_whitespace();
282-
if (parser.eat('=')) {
283-
parser.allow_whitespace();
284-
const right = read_expression(parser);
285-
pattern = {
286-
type: 'AssignmentPattern',
287-
left: pattern,
288-
right: right,
289-
start: pattern.start,
290-
end: right.end
291-
};
292-
}
274+
parser.eat('(', true);
293275

294-
parameters.push(pattern);
276+
let parentheses = 1;
277+
let params = '';
295278

296-
if (!parser.eat(',')) break;
297-
parser.allow_whitespace();
279+
while (!parser.match(')') || parentheses !== 1) {
280+
if (parser.match('(')) parentheses++;
281+
if (parser.match(')')) parentheses--;
282+
params += parser.read(/^./);
298283
}
299284

300-
parser.eat(')', true);
285+
let function_expression = /** @type {import('estree').ArrowFunctionExpression} */ (
286+
parse_expression_at(
287+
parser.template.slice(0, slice_end).replace(/\S/g, ' ') + `(${params}) => {}`,
288+
parser.ts,
289+
0
290+
)
291+
);
301292

302-
parser.allow_whitespace();
303-
parser.eat('}', true);
293+
parser.index += 2;
304294

305295
/** @type {ReturnType<typeof parser.append<import('#compiler').SnippetBlock>>} */
306296
const block = parser.append({
@@ -313,10 +303,9 @@ function open(parser) {
313303
end: name_end,
314304
name
315305
},
316-
parameters,
306+
parameters: function_expression.params,
317307
body: create_fragment()
318308
});
319-
320309
parser.stack.push(block);
321310
parser.fragments.push(block.body);
322311

packages/svelte/tests/parser-modern/samples/snippets/output.json

+13-5
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,28 @@
3232
"loc": {
3333
"start": {
3434
"line": 3,
35-
"column": 14,
36-
"character": 43
35+
"column": 14
3736
},
3837
"end": {
3938
"line": 3,
40-
"column": 25,
41-
"character": 54
39+
"column": 25
4240
}
4341
},
44-
"end": 54,
42+
"end": 46,
4543
"typeAnnotation": {
4644
"type": "TSTypeAnnotation",
4745
"start": 46,
4846
"end": 54,
47+
"loc": {
48+
"start": {
49+
"line": 3,
50+
"column": 17
51+
},
52+
"end": {
53+
"line": 3,
54+
"column": 25
55+
}
56+
},
4957
"typeAnnotation": {
5058
"type": "TSStringKeyword",
5159
"start": 48,

packages/svelte/tests/parser-modern/samples/typescript-in-event-handler/output.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@
5454
"line": 6,
5555
"column": 12
5656
},
57-
"end": 87
57+
"end": {
58+
"line": 6,
59+
"column": 25
60+
}
5861
},
5962
"name": "e",
6063
"typeAnnotation": {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
html: '013/023'
5+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{#snippet one(a, b = 1, c = (2, 3))}
2+
{a}{b}{c}
3+
{/snippet}
4+
5+
{#snippet two(a, b = (1, 2), c = 3)}
6+
{a}{b}{c}
7+
{/snippet}
8+
9+
{@render one(0)}/{@render two(0)}

0 commit comments

Comments
 (0)