From 4b6e0eb4c8c9e9c6e422548d32f3e748cc0b27c6 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 4 Dec 2023 06:42:52 -0500 Subject: [PATCH] fix compiler errors around exported state --- packages/svelte/src/compiler/errors.js | 4 ++-- .../src/compiler/phases/2-analyze/validation.js | 10 ++++++++-- .../samples/export-derived-state/_config.js | 9 +++++++++ .../samples/export-derived-state/main.svelte.js | 3 +++ .../compiler-errors/samples/export-state/_config.js | 9 +++++++++ .../samples/export-state/main.svelte.js | 13 +++++++++++++ packages/svelte/tests/compiler-errors/test.ts | 8 ++++++-- 7 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 packages/svelte/tests/compiler-errors/samples/export-derived-state/_config.js create mode 100644 packages/svelte/tests/compiler-errors/samples/export-derived-state/main.svelte.js create mode 100644 packages/svelte/tests/compiler-errors/samples/export-state/_config.js create mode 100644 packages/svelte/tests/compiler-errors/samples/export-state/main.svelte.js diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 700ec21e19..805f8b6b1a 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -164,8 +164,8 @@ const runes = { 'invalid-legacy-export': () => `Cannot use \`export let\` in runes mode — use $props instead`, /** @param {string} rune */ 'invalid-rune-usage': (rune) => `Cannot use ${rune} rune in non-runes mode`, - /** @param {string} rune */ - 'invalid-rune-export': (rune) => `Cannot export value created with ${rune}`, + 'invalid-state-export': () => `Cannot export state if it is reassigned`, + 'invalid-derived-export': () => `Cannot export derived state`, 'invalid-props-id': () => `$props() can only be used with an object destructuring pattern`, 'invalid-props-pattern': () => `$props() assignment must not contain nested properties or computed keys`, diff --git a/packages/svelte/src/compiler/phases/2-analyze/validation.js b/packages/svelte/src/compiler/phases/2-analyze/validation.js index 99cc8137d6..c41b76ad69 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/validation.js +++ b/packages/svelte/src/compiler/phases/2-analyze/validation.js @@ -481,8 +481,14 @@ export const validation_legacy = merge(validation, a11y_validators, { */ function validate_export(node, scope, name) { const binding = scope.get(name); - if (binding && (binding.kind === 'derived' || binding.kind === 'state')) { - error(node, 'invalid-rune-export', `$${binding.kind}`); + if (!binding) return; + + if (binding.kind === 'derived') { + error(node, 'invalid-derived-export'); + } + + if (binding.kind === 'state' && binding.reassigned) { + error(node, 'invalid-state-export'); } } diff --git a/packages/svelte/tests/compiler-errors/samples/export-derived-state/_config.js b/packages/svelte/tests/compiler-errors/samples/export-derived-state/_config.js new file mode 100644 index 0000000000..1c171d19c0 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/export-derived-state/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'invalid-derived-export', + message: 'Cannot export derived state', + position: [24, 66] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/export-derived-state/main.svelte.js b/packages/svelte/tests/compiler-errors/samples/export-derived-state/main.svelte.js new file mode 100644 index 0000000000..0906cedf74 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/export-derived-state/main.svelte.js @@ -0,0 +1,3 @@ +let count = $state(0); + +export const double = $derived(count * 2); diff --git a/packages/svelte/tests/compiler-errors/samples/export-state/_config.js b/packages/svelte/tests/compiler-errors/samples/export-state/_config.js new file mode 100644 index 0000000000..5ddb2a859a --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/export-state/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'invalid-state-export', + message: 'Cannot export state if it is reassigned', + position: [46, 86] + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/export-state/main.svelte.js b/packages/svelte/tests/compiler-errors/samples/export-state/main.svelte.js new file mode 100644 index 0000000000..39d9920f7d --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/export-state/main.svelte.js @@ -0,0 +1,13 @@ +export const object = $state({ + ok: true +}); + +export const primitive = $state('nope'); + +export function update_object() { + object.ok = !object.ok; +} + +export function update_primitive() { + primitive = 'yep'; +} diff --git a/packages/svelte/tests/compiler-errors/test.ts b/packages/svelte/tests/compiler-errors/test.ts index b7a76c896f..376e790db6 100644 --- a/packages/svelte/tests/compiler-errors/test.ts +++ b/packages/svelte/tests/compiler-errors/test.ts @@ -37,11 +37,11 @@ const { test, run } = suite((config, cwd) => { } } - if (fs.existsSync(`${cwd}/main.js`)) { + if (fs.existsSync(`${cwd}/main.svelte.js`)) { let caught_error = false; try { - compileModule(fs.readFileSync(`${cwd}/main.js`, 'utf-8'), { + compileModule(fs.readFileSync(`${cwd}/main.svelte.js`, 'utf-8'), { generate: 'client' }); } catch (e) { @@ -51,6 +51,10 @@ const { test, run } = suite((config, cwd) => { expect(error.code).toMatch(config.error.code); expect(error.message).toMatch(config.error.message); + + if (config.error.position) { + expect(error.position).toEqual(config.error.position); + } } if (!caught_error) {