Skip to content

Commit c677df6

Browse files
committed
handle invalid expression inside await block
1 parent 2ba4b95 commit c677df6

File tree

5 files changed

+331
-14
lines changed

5 files changed

+331
-14
lines changed

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

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -182,17 +182,21 @@ function open(parser) {
182182

183183
const matches = parser.eat('}', true, false);
184184

185-
// Parser may have read the `as` as part of the expression (e.g. in `{#each foo. as x}`)
186-
if (!matches && parser.template.slice(parser.index - 4, parser.index) === ' as ') {
187-
const prev_index = parser.index;
188-
context = read_pattern(parser);
189-
parser.eat('}', true);
190-
expression = {
191-
type: 'Identifier',
192-
name: '',
193-
start: expression.start,
194-
end: prev_index - 4
195-
};
185+
if (!matches) {
186+
// Parser may have read the `as` as part of the expression (e.g. in `{#each foo. as x}`)
187+
if (parser.template.slice(parser.index - 4, parser.index) === ' as ') {
188+
const prev_index = parser.index;
189+
context = read_pattern(parser);
190+
parser.eat('}', true);
191+
expression = {
192+
type: 'Identifier',
193+
name: '',
194+
start: expression.start,
195+
end: prev_index - 4
196+
};
197+
} else {
198+
parser.eat('}', true); // rerun to produce the parser error
199+
}
196200
}
197201

198202
/** @type {AST.EachBlock} */
@@ -259,7 +263,39 @@ function open(parser) {
259263
parser.fragments.push(block.pending);
260264
}
261265

262-
parser.eat('}', true);
266+
const matches = parser.eat('}', true, false);
267+
268+
// Parser may have read the `then/catch` as part of the expression (e.g. in `{#await foo. then x}`)
269+
if (!matches) {
270+
if (parser.template.slice(parser.index - 6, parser.index) === ' then ') {
271+
const prev_index = parser.index;
272+
block.value = read_pattern(parser);
273+
parser.eat('}', true);
274+
block.expression = {
275+
type: 'Identifier',
276+
name: '',
277+
start: expression.start,
278+
end: prev_index - 6
279+
};
280+
block.then = block.pending;
281+
block.pending = null;
282+
} else if (parser.template.slice(parser.index - 7, parser.index) === ' catch ') {
283+
const prev_index = parser.index;
284+
block.error = read_pattern(parser);
285+
parser.eat('}', true);
286+
block.expression = {
287+
type: 'Identifier',
288+
name: '',
289+
start: expression.start,
290+
end: prev_index - 7
291+
};
292+
block.catch = block.pending;
293+
block.pending = null;
294+
} else {
295+
parser.eat('}', true); // rerun to produce the parser error
296+
}
297+
}
298+
263299
parser.stack.push(block);
264300

265301
return;

packages/svelte/tests/parser-legacy/samples/loose-invalid-expression/input.svelte

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ asd{a.}asd
1515
{#each array as item (item.)}{/each}
1616

1717
{#each obj. as item}{/each}
18+
19+
{#await x.}{/await}
20+
21+
{#await x. then y}{/await}
22+
23+
{#await x. catch y}{/await}

packages/svelte/tests/parser-legacy/samples/loose-invalid-expression/output.json

Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"html": {
33
"type": "Fragment",
44
"start": 0,
5-
"end": 246,
5+
"end": 324,
66
"children": [
77
{
88
"type": "Element",
@@ -345,6 +345,163 @@
345345
"start": 226,
346346
"end": 230
347347
}
348+
},
349+
{
350+
"type": "Text",
351+
"start": 246,
352+
"end": 248,
353+
"raw": "\n\n",
354+
"data": "\n\n"
355+
},
356+
{
357+
"type": "AwaitBlock",
358+
"start": 248,
359+
"end": 267,
360+
"expression": {
361+
"type": "Identifier",
362+
"start": 256,
363+
"end": 258,
364+
"name": ""
365+
},
366+
"value": null,
367+
"error": null,
368+
"pending": {
369+
"type": "PendingBlock",
370+
"start": 259,
371+
"end": 259,
372+
"children": [],
373+
"skip": false
374+
},
375+
"then": {
376+
"type": "ThenBlock",
377+
"start": null,
378+
"end": null,
379+
"children": [],
380+
"skip": true
381+
},
382+
"catch": {
383+
"type": "CatchBlock",
384+
"start": null,
385+
"end": null,
386+
"children": [],
387+
"skip": true
388+
}
389+
},
390+
{
391+
"type": "Text",
392+
"start": 267,
393+
"end": 269,
394+
"raw": "\n\n",
395+
"data": "\n\n"
396+
},
397+
{
398+
"type": "AwaitBlock",
399+
"start": 269,
400+
"end": 295,
401+
"expression": {
402+
"type": "Identifier",
403+
"name": "",
404+
"start": 277,
405+
"end": 279
406+
},
407+
"value": {
408+
"type": "Identifier",
409+
"name": "y",
410+
"start": 285,
411+
"loc": {
412+
"start": {
413+
"line": 21,
414+
"column": 16,
415+
"character": 285
416+
},
417+
"end": {
418+
"line": 21,
419+
"column": 17,
420+
"character": 286
421+
}
422+
},
423+
"end": 286
424+
},
425+
"error": null,
426+
"pending": {
427+
"type": "PendingBlock",
428+
"start": null,
429+
"end": null,
430+
"children": [],
431+
"skip": true
432+
},
433+
"then": {
434+
"type": "ThenBlock",
435+
"start": 287,
436+
"end": 267,
437+
"children": [],
438+
"skip": false
439+
},
440+
"catch": {
441+
"type": "CatchBlock",
442+
"start": null,
443+
"end": null,
444+
"children": [],
445+
"skip": true
446+
}
447+
},
448+
{
449+
"type": "Text",
450+
"start": 295,
451+
"end": 297,
452+
"raw": "\n\n",
453+
"data": "\n\n"
454+
},
455+
{
456+
"type": "AwaitBlock",
457+
"start": 297,
458+
"end": 324,
459+
"expression": {
460+
"type": "Identifier",
461+
"name": "",
462+
"start": 305,
463+
"end": 307
464+
},
465+
"value": null,
466+
"error": {
467+
"type": "Identifier",
468+
"name": "y",
469+
"start": 314,
470+
"loc": {
471+
"start": {
472+
"line": 23,
473+
"column": 17,
474+
"character": 314
475+
},
476+
"end": {
477+
"line": 23,
478+
"column": 18,
479+
"character": 315
480+
}
481+
},
482+
"end": 315
483+
},
484+
"pending": {
485+
"type": "PendingBlock",
486+
"start": null,
487+
"end": null,
488+
"children": [],
489+
"skip": true
490+
},
491+
"then": {
492+
"type": "ThenBlock",
493+
"start": null,
494+
"end": null,
495+
"children": [],
496+
"skip": true
497+
},
498+
"catch": {
499+
"type": "CatchBlock",
500+
"start": 316,
501+
"end": 295,
502+
"children": [],
503+
"skip": false
504+
}
348505
}
349506
]
350507
}

packages/svelte/tests/parser-modern/samples/loose-invalid-expression/input.svelte

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ asd{a.}asd
1515
{#each array as item (item.)}{/each}
1616

1717
{#each obj. as item}{/each}
18+
19+
{#await x.}{/await}
20+
21+
{#await x. then y}{/await}
22+
23+
{#await x. catch y}{/await}

packages/svelte/tests/parser-modern/samples/loose-invalid-expression/output.json

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"css": null,
33
"js": [],
44
"start": 0,
5-
"end": 246,
5+
"end": 324,
66
"type": "Root",
77
"fragment": {
88
"type": "Fragment",
@@ -367,6 +367,118 @@
367367
},
368368
"end": 238
369369
}
370+
},
371+
{
372+
"type": "Text",
373+
"start": 246,
374+
"end": 248,
375+
"raw": "\n\n",
376+
"data": "\n\n"
377+
},
378+
{
379+
"type": "AwaitBlock",
380+
"start": 248,
381+
"end": 267,
382+
"expression": {
383+
"type": "Identifier",
384+
"start": 256,
385+
"end": 258,
386+
"name": ""
387+
},
388+
"value": null,
389+
"error": null,
390+
"pending": {
391+
"type": "Fragment",
392+
"nodes": []
393+
},
394+
"then": null,
395+
"catch": null
396+
},
397+
{
398+
"type": "Text",
399+
"start": 267,
400+
"end": 269,
401+
"raw": "\n\n",
402+
"data": "\n\n"
403+
},
404+
{
405+
"type": "AwaitBlock",
406+
"start": 269,
407+
"end": 295,
408+
"expression": {
409+
"type": "Identifier",
410+
"name": "",
411+
"start": 277,
412+
"end": 279
413+
},
414+
"value": {
415+
"type": "Identifier",
416+
"name": "y",
417+
"start": 285,
418+
"loc": {
419+
"start": {
420+
"line": 21,
421+
"column": 16,
422+
"character": 285
423+
},
424+
"end": {
425+
"line": 21,
426+
"column": 17,
427+
"character": 286
428+
}
429+
},
430+
"end": 286
431+
},
432+
"error": null,
433+
"pending": null,
434+
"then": {
435+
"type": "Fragment",
436+
"nodes": []
437+
},
438+
"catch": null
439+
},
440+
{
441+
"type": "Text",
442+
"start": 295,
443+
"end": 297,
444+
"raw": "\n\n",
445+
"data": "\n\n"
446+
},
447+
{
448+
"type": "AwaitBlock",
449+
"start": 297,
450+
"end": 324,
451+
"expression": {
452+
"type": "Identifier",
453+
"name": "",
454+
"start": 305,
455+
"end": 307
456+
},
457+
"value": null,
458+
"error": {
459+
"type": "Identifier",
460+
"name": "y",
461+
"start": 314,
462+
"loc": {
463+
"start": {
464+
"line": 23,
465+
"column": 17,
466+
"character": 314
467+
},
468+
"end": {
469+
"line": 23,
470+
"column": 18,
471+
"character": 315
472+
}
473+
},
474+
"end": 315
475+
},
476+
"pending": null,
477+
"then": null,
478+
"catch": {
479+
"type": "Fragment",
480+
"nodes": []
481+
}
370482
}
371483
]
372484
},

0 commit comments

Comments
 (0)