From c42bb04276af0024b49aa46918eec69ad56570a5 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Fri, 28 Jun 2024 13:25:09 +0200 Subject: [PATCH] fix: disallow accessing internal Svelte props (#12207) closes #12184 --- .changeset/olive-cobras-wonder.md | 5 +++++ packages/svelte/messages/compile-errors/script.md | 4 ++++ packages/svelte/src/compiler/errors.js | 9 +++++++++ .../src/compiler/phases/2-analyze/validation.js | 12 ++++++++++++ .../samples/runes-props-illegal-name-1/_config.js | 9 +++++++++ .../samples/runes-props-illegal-name-1/main.svelte | 3 +++ .../samples/runes-props-illegal-name-2/_config.js | 9 +++++++++ .../samples/runes-props-illegal-name-2/main.svelte | 4 ++++ 8 files changed, 55 insertions(+) create mode 100644 .changeset/olive-cobras-wonder.md create mode 100644 packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-1/_config.js create mode 100644 packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-1/main.svelte create mode 100644 packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-2/_config.js create mode 100644 packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-2/main.svelte diff --git a/.changeset/olive-cobras-wonder.md b/.changeset/olive-cobras-wonder.md new file mode 100644 index 0000000000..331d61a404 --- /dev/null +++ b/.changeset/olive-cobras-wonder.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: disallow accessing internal Svelte props diff --git a/packages/svelte/messages/compile-errors/script.md b/packages/svelte/messages/compile-errors/script.md index 57fa1ed700..d31c04b99c 100644 --- a/packages/svelte/messages/compile-errors/script.md +++ b/packages/svelte/messages/compile-errors/script.md @@ -78,6 +78,10 @@ > Cannot use `$props()` more than once +## props_illegal_name + +> Declaring or accessing a prop starting with `$$` is illegal (they are reserved for Svelte internals) + ## props_invalid_identifier > `$props()` can only be used with an object destructuring pattern diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index d6d3d51d7c..1a60f99000 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -276,6 +276,15 @@ export function props_duplicate(node) { e(node, "props_duplicate", "Cannot use `$props()` more than once"); } +/** + * Declaring or accessing a prop starting with `$$` is illegal (they are reserved for Svelte internals) + * @param {null | number | NodeLike} node + * @returns {never} + */ +export function props_illegal_name(node) { + e(node, "props_illegal_name", "Declaring or accessing a prop starting with `$$` is illegal (they are reserved for Svelte internals)"); +} + /** * `$props()` can only be used with an object destructuring pattern * @param {null | number | NodeLike} node diff --git a/packages/svelte/src/compiler/phases/2-analyze/validation.js b/packages/svelte/src/compiler/phases/2-analyze/validation.js index 45f87935e1..93d12bfeda 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/validation.js +++ b/packages/svelte/src/compiler/phases/2-analyze/validation.js @@ -341,6 +341,14 @@ function validate_block_not_empty(node, context) { * @type {import('zimmerframe').Visitors} */ const validation = { + MemberExpression(node, context) { + if (node.object.type === 'Identifier' && node.property.type === 'Identifier') { + const binding = context.state.scope.get(node.object.name); + if (binding?.kind === 'rest_prop' && node.property.name.startsWith('$$')) { + e.props_illegal_name(node.property); + } + } + }, AssignmentExpression(node, context) { validate_assignment(node, node.left, context.state); }, @@ -1255,6 +1263,10 @@ export const validation_runes = merge(validation, a11y_validators, { e.props_invalid_pattern(property); } + if (property.key.type === 'Identifier' && property.key.name.startsWith('$$')) { + e.props_illegal_name(property); + } + const value = property.value.type === 'AssignmentPattern' ? property.value.left : property.value; diff --git a/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-1/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-1/_config.js new file mode 100644 index 0000000000..b205e0de38 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-1/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'props_illegal_name', + message: + 'Declaring or accessing a prop starting with `$$` is illegal (they are reserved for Svelte internals)' + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-1/main.svelte b/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-1/main.svelte new file mode 100644 index 0000000000..dd581833fd --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-1/main.svelte @@ -0,0 +1,3 @@ + diff --git a/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-2/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-2/_config.js new file mode 100644 index 0000000000..b205e0de38 --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-2/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + error: { + code: 'props_illegal_name', + message: + 'Declaring or accessing a prop starting with `$$` is illegal (they are reserved for Svelte internals)' + } +}); diff --git a/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-2/main.svelte b/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-2/main.svelte new file mode 100644 index 0000000000..3b287f829e --- /dev/null +++ b/packages/svelte/tests/compiler-errors/samples/runes-props-illegal-name-2/main.svelte @@ -0,0 +1,4 @@ +