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/acorn.js b/packages/svelte/src/compiler/phases/1-parse/acorn.js index fb60c228c5..a6ec9e9ac5 100644 --- a/packages/svelte/src/compiler/phases/1-parse/acorn.js +++ b/packages/svelte/src/compiler/phases/1-parse/acorn.js @@ -94,7 +94,7 @@ export function parse_expression_at(parser, source, index) { return ast; } catch (e) { - handle_parse_error(e); + handle_parse_error(e, source, parser.ts); } } @@ -132,10 +132,19 @@ const regex_position_indicator = / \(\d+:\d+\)$/; /** * @param {any} err + * @param {string} [source] + * @param {boolean} [typescript] * @returns {never} */ -function handle_parse_error(err) { - e.js_parse_error(err.pos, err.message.replace(regex_position_indicator, '')); +function handle_parse_error(err, source, typescript) { + let message = /** @type {string} */ (err.message).replace(regex_position_indicator, ''); + let pos = /** @type {number} */ (err.pos); + + if (!typescript && source && source[pos] === ':') { + message += ` (did you forget to add \`lang="ts"\`?)`; + } + + e.js_parse_error(pos, message); } /** diff --git a/packages/svelte/src/compiler/phases/1-parse/read/expression.js b/packages/svelte/src/compiler/phases/1-parse/read/expression.js index 1c8f097c2f..736639e1f4 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/expression.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/expression.js @@ -43,6 +43,22 @@ export default function read_expression(parser, opening_token, disallow_loose) { parser.index = index; + if (!parser.ts) { + let j = parser.index; + while (j < parser.template.length && regex_whitespace.test(parser.template[j])) j++; + + const remaining = parser.template.slice(j); + + if ( + remaining[0] === ':' || + /^satisfies[\s(]/.test(remaining) || + (remaining[0] === '!' && remaining[1] !== '=') || + (/^as[\s(]/.test(remaining) && !disallow_loose) + ) { + e.js_parse_error(j, `Unexpected token (did you forget to add \`lang="ts"\`?)`); + } + } + return /** @type {Expression} */ (remove_parens(node)); } catch (err) { // If we are in an each loop we need the error to be thrown in cases like 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} diff --git a/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-as/_config.js b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-as/_config.js new file mode 100644 index 0000000000..a6eca38f13 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-as/_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: [3, 3] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-as/main.svelte b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-as/main.svelte new file mode 100644 index 0000000000..b04bd39332 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-as/main.svelte @@ -0,0 +1 @@ +{x as number} \ No newline at end of file diff --git a/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-attribute/_config.js b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-attribute/_config.js new file mode 100644 index 0000000000..0ae7494b60 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-attribute/_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: [14, 14] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-attribute/main.svelte b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-attribute/main.svelte new file mode 100644 index 0000000000..86351fb664 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-attribute/main.svelte @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-colon/_config.js b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-colon/_config.js new file mode 100644 index 0000000000..fe9f0c2e62 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-colon/_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: [2, 2] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-colon/main.svelte b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-colon/main.svelte new file mode 100644 index 0000000000..70c0f4c13b --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-colon/main.svelte @@ -0,0 +1 @@ +{x: number} \ No newline at end of file diff --git a/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-non-null/_config.js b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-non-null/_config.js new file mode 100644 index 0000000000..fe9f0c2e62 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-non-null/_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: [2, 2] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-non-null/main.svelte b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-non-null/main.svelte new file mode 100644 index 0000000000..6c2f391078 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-non-null/main.svelte @@ -0,0 +1 @@ +{x!} \ No newline at end of file diff --git a/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-satisfies/_config.js b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-satisfies/_config.js new file mode 100644 index 0000000000..a6eca38f13 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-satisfies/_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: [3, 3] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-satisfies/main.svelte b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-satisfies/main.svelte new file mode 100644 index 0000000000..4417664603 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/ts-annotation-no-lang-satisfies/main.svelte @@ -0,0 +1 @@ +{x satisfies Foo} \ No newline at end of file