From 9d0edf720ef9ad8d08294119af5a3ff534a90596 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 17 Mar 2026 18:57:53 -0400 Subject: [PATCH] fix: better error for TS annotations in snippets without lang="ts" --- .changeset/gentle-dots-dream.md | 5 +++++ .../src/compiler/phases/1-parse/index.js | 5 +++-- .../src/compiler/phases/1-parse/state/tag.js | 20 +++++++++++++++---- .../snippet-ts-annotation-no-lang/_config.js | 9 +++++++++ .../snippet-ts-annotation-no-lang/main.svelte | 3 +++ 5 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 .changeset/gentle-dots-dream.md create mode 100644 packages/svelte/tests/compiler-errors/samples/snippet-ts-annotation-no-lang/_config.js create mode 100644 packages/svelte/tests/compiler-errors/samples/snippet-ts-annotation-no-lang/main.svelte diff --git a/.changeset/gentle-dots-dream.md b/.changeset/gentle-dots-dream.md new file mode 100644 index 0000000000..d3987705ca --- /dev/null +++ b/.changeset/gentle-dots-dream.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +Improve error message when TypeScript syntax is used in snippet parameters without `lang="ts"` diff --git a/packages/svelte/src/compiler/phases/1-parse/index.js b/packages/svelte/src/compiler/phases/1-parse/index.js index 81adbbb555..5c2426fac6 100644 --- a/packages/svelte/src/compiler/phases/1-parse/index.js +++ b/packages/svelte/src/compiler/phases/1-parse/index.js @@ -177,10 +177,11 @@ export class Parser { /** * @param {any} err + * @param {string} [suffix] * @returns {never} */ - acorn_error(err) { - e.js_parse_error(err.pos, err.message.replace(regex_position_indicator, '')); + acorn_error(err, suffix = '') { + e.js_parse_error(err.pos, err.message.replace(regex_position_indicator, '') + suffix); } /** diff --git a/packages/svelte/src/compiler/phases/1-parse/state/tag.js b/packages/svelte/src/compiler/phases/1-parse/state/tag.js index d9518c726f..255e190619 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/tag.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/tag.js @@ -390,16 +390,28 @@ function open(parser) { const prelude = parser.template.slice(0, params_start).replace(/\S/g, ' '); const params = parser.template.slice(params_start, parser.index); - let function_expression = matched - ? /** @type {ArrowFunctionExpression} */ ( + let function_expression; + + if (matched) { + try { + function_expression = /** @type {ArrowFunctionExpression} */ ( parse_expression_at( prelude + `${params} => {}`, parser.root.comments, parser.ts, params_start ) - ) - : { params: [] }; + ); + } catch (/** @type {any} */ err) { + const suffix = + !parser.ts && parser.template[err.pos] === ':' + ? ` (did you forget to add \`lang="ts"\`?)` + : ''; + parser.acorn_error(err, suffix); + } + } else { + function_expression = { params: [] }; + } parser.allow_whitespace(); parser.eat('}', true); diff --git a/packages/svelte/tests/compiler-errors/samples/snippet-ts-annotation-no-lang/_config.js b/packages/svelte/tests/compiler-errors/samples/snippet-ts-annotation-no-lang/_config.js new file mode 100644 index 0000000000..b56e835f96 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/snippet-ts-annotation-no-lang/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'js_parse_error', + message: 'Unexpected token (did you forget to add `lang="ts"`?)', + position: [18, 18] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/snippet-ts-annotation-no-lang/main.svelte b/packages/svelte/tests/compiler-errors/samples/snippet-ts-annotation-no-lang/main.svelte new file mode 100644 index 0000000000..514e077bbc --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/snippet-ts-annotation-no-lang/main.svelte @@ -0,0 +1,3 @@ +{#snippet bar(text: string)} + {text} +{/snippet}