From 0bba84cc203c7cab945527cc3928597d3612a37d Mon Sep 17 00:00:00 2001 From: Bladesheng Date: Fri, 25 Jul 2025 14:43:41 +0200 Subject: [PATCH 1/4] fix: add types for `part` attribute to svg attributes (#16499) --- .changeset/seven-colts-obey.md | 5 +++++ packages/svelte/elements.d.ts | 1 + 2 files changed, 6 insertions(+) create mode 100644 .changeset/seven-colts-obey.md diff --git a/.changeset/seven-colts-obey.md b/.changeset/seven-colts-obey.md new file mode 100644 index 000000000000..b41216f64908 --- /dev/null +++ b/.changeset/seven-colts-obey.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: add types for `part` attribute to svg attributes diff --git a/packages/svelte/elements.d.ts b/packages/svelte/elements.d.ts index 604241592aff..2e1042dfd6b8 100644 --- a/packages/svelte/elements.d.ts +++ b/packages/svelte/elements.d.ts @@ -1553,6 +1553,7 @@ export interface SVGAttributes extends AriaAttributes, DO height?: number | string | undefined | null; id?: string | undefined | null; lang?: string | undefined | null; + part?: string | undefined | null; max?: number | string | undefined | null; media?: string | undefined | null; // On the `textPath` element From b0f9ea3ae62cfb9eb4437898bf8a6b90e0531657 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 25 Jul 2025 15:57:32 -0700 Subject: [PATCH 2/4] fix: throw on duplicate class field declarations (#16502) * fix: throw on duplicate class field declarations * doh * handle assignment in constructor * fix * apply suggestion from review * fix * fix failing test --- .changeset/odd-phones-taste.md | 5 ++ .../98-reference/.generated/compile-errors.md | 6 +++ .../svelte/messages/compile-errors/script.md | 4 ++ packages/svelte/src/compiler/errors.js | 10 ++++ .../phases/2-analyze/visitors/ClassBody.js | 53 ++++++++++++++++++- .../class-state-constructor-9/errors.json | 12 ++--- 6 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 .changeset/odd-phones-taste.md diff --git a/.changeset/odd-phones-taste.md b/.changeset/odd-phones-taste.md new file mode 100644 index 000000000000..ec9534b74157 --- /dev/null +++ b/.changeset/odd-phones-taste.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: throw on duplicate class field declarations diff --git a/documentation/docs/98-reference/.generated/compile-errors.md b/documentation/docs/98-reference/.generated/compile-errors.md index 20f57770d122..957a9f67c7b0 100644 --- a/documentation/docs/98-reference/.generated/compile-errors.md +++ b/documentation/docs/98-reference/.generated/compile-errors.md @@ -364,6 +364,12 @@ The $ name is reserved, and cannot be used for variables and imports The $ prefix is reserved, and cannot be used for variables and imports ``` +### duplicate_class_field + +``` +`%name%` has already been declared +``` + ### each_item_invalid_assignment ``` diff --git a/packages/svelte/messages/compile-errors/script.md b/packages/svelte/messages/compile-errors/script.md index 2b0c5eafdf86..5c1080acedfe 100644 --- a/packages/svelte/messages/compile-errors/script.md +++ b/packages/svelte/messages/compile-errors/script.md @@ -30,6 +30,10 @@ > The $ prefix is reserved, and cannot be used for variables and imports +## duplicate_class_field + +> `%name%` has already been declared + ## each_item_invalid_assignment > Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`, or `bind:value={array[i]}` instead of `bind:value={entry}`) diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 599d3e8248b0..e763a6e0733a 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -152,6 +152,16 @@ export function dollar_prefix_invalid(node) { e(node, 'dollar_prefix_invalid', `The $ prefix is reserved, and cannot be used for variables and imports\nhttps://svelte.dev/e/dollar_prefix_invalid`); } +/** + * `%name%` has already been declared + * @param {null | number | NodeLike} node + * @param {string} name + * @returns {never} + */ +export function duplicate_class_field(node, name) { + e(node, 'duplicate_class_field', `\`${name}\` has already been declared\nhttps://svelte.dev/e/duplicate_class_field`); +} + /** * Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`, or `bind:value={array[i]}` instead of `bind:value={entry}`) * @param {null | number | NodeLike} node diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/ClassBody.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/ClassBody.js index ffc39ac00de1..2bfc1dbce36c 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/ClassBody.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/ClassBody.js @@ -33,6 +33,9 @@ export function ClassBody(node, context) { /** @type {Map} */ const state_fields = new Map(); + /** @type {Map>} */ + const fields = new Map(); + context.state.analysis.classes.set(node, state_fields); /** @type {MethodDefinition | null} */ @@ -54,6 +57,14 @@ export function ClassBody(node, context) { e.state_field_duplicate(node, name); } + const _key = (key.type === 'PrivateIdentifier' ? '#' : '') + name; + const field = fields.get(_key); + + // if there's already a method or assigned field, error + if (field && !(field.length === 1 && field[0] === 'prop')) { + e.duplicate_class_field(node, _key); + } + state_fields.set(name, { node, type: rune, @@ -67,10 +78,48 @@ export function ClassBody(node, context) { for (const child of node.body) { if (child.type === 'PropertyDefinition' && !child.computed && !child.static) { handle(child, child.key, child.value); + const key = (child.key.type === 'PrivateIdentifier' ? '#' : '') + get_name(child.key); + const field = fields.get(key); + if (!field) { + fields.set(key, [child.value ? 'assigned_prop' : 'prop']); + continue; + } + e.duplicate_class_field(child, key); } - if (child.type === 'MethodDefinition' && child.kind === 'constructor') { - constructor = child; + if (child.type === 'MethodDefinition') { + if (child.kind === 'constructor') { + constructor = child; + } else if (!child.computed) { + const key = (child.key.type === 'PrivateIdentifier' ? '#' : '') + get_name(child.key); + const field = fields.get(key); + if (!field) { + fields.set(key, [child.kind]); + continue; + } + if ( + field.includes(child.kind) || + field.includes('prop') || + field.includes('assigned_prop') + ) { + e.duplicate_class_field(child, key); + } + if (child.kind === 'get') { + if (field.length === 1 && field[0] === 'set') { + field.push('get'); + continue; + } + } else if (child.kind === 'set') { + if (field.length === 1 && field[0] === 'get') { + field.push('set'); + continue; + } + } else { + field.push(child.kind); + continue; + } + e.duplicate_class_field(child, key); + } } } diff --git a/packages/svelte/tests/validator/samples/class-state-constructor-9/errors.json b/packages/svelte/tests/validator/samples/class-state-constructor-9/errors.json index b7dd4c8ed457..94b5f191c2f7 100644 --- a/packages/svelte/tests/validator/samples/class-state-constructor-9/errors.json +++ b/packages/svelte/tests/validator/samples/class-state-constructor-9/errors.json @@ -1,14 +1,14 @@ [ { - "code": "state_field_invalid_assignment", - "message": "Cannot assign to a state field before its declaration", + "code": "duplicate_class_field", + "message": "`count` has already been declared", "start": { - "line": 2, - "column": 1 + "line": 5, + "column": 2 }, "end": { - "line": 2, - "column": 12 + "line": 5, + "column": 24 } } ] From d0ebd42986c4d3e4db0420f1aaebd337afdb230f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 16:46:12 -0700 Subject: [PATCH 3/4] Version Packages (#16500) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/odd-phones-taste.md | 5 ----- .changeset/seven-colts-obey.md | 5 ----- packages/svelte/CHANGELOG.md | 8 ++++++++ packages/svelte/package.json | 2 +- packages/svelte/src/version.js | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) delete mode 100644 .changeset/odd-phones-taste.md delete mode 100644 .changeset/seven-colts-obey.md diff --git a/.changeset/odd-phones-taste.md b/.changeset/odd-phones-taste.md deleted file mode 100644 index ec9534b74157..000000000000 --- a/.changeset/odd-phones-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: throw on duplicate class field declarations diff --git a/.changeset/seven-colts-obey.md b/.changeset/seven-colts-obey.md deleted file mode 100644 index b41216f64908..000000000000 --- a/.changeset/seven-colts-obey.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: add types for `part` attribute to svg attributes diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 450ecde53b1e..766c83763acc 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,13 @@ # svelte +## 5.36.17 + +### Patch Changes + +- fix: throw on duplicate class field declarations ([#16502](https://github.com/sveltejs/svelte/pull/16502)) + +- fix: add types for `part` attribute to svg attributes ([#16499](https://github.com/sveltejs/svelte/pull/16499)) + ## 5.36.16 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 07954026b550..22bc8cc8fac6 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.36.16", + "version": "5.36.17", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index 5d76fc3f2963..d2992a3dcd8c 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.36.16'; +export const VERSION = '5.36.17'; export const PUBLIC_VERSION = '5'; From c7851789d71cc3d0b5d89ce9c759a39be6caa51a Mon Sep 17 00:00:00 2001 From: 7nik Date: Sat, 26 Jul 2025 21:27:22 +0300 Subject: [PATCH 4/4] fix: always mark props as stateful (#16504) --- .changeset/gorgeous-jeans-begin.md | 5 +++++ .../phases/2-analyze/visitors/Identifier.js | 5 ++++- .../props-default-value-function/_config.js | 15 +++++++++++++++ .../props-default-value-function/inner.svelte | 4 ++++ .../props-default-value-function/main.svelte | 14 ++++++++++++++ .../props-default-value-function/wrapper.svelte | 7 +++++++ .../props-default-value-function/wrapper2.svelte | 7 +++++++ 7 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 .changeset/gorgeous-jeans-begin.md create mode 100644 packages/svelte/tests/runtime-runes/samples/props-default-value-function/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/props-default-value-function/inner.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/props-default-value-function/main.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper2.svelte diff --git a/.changeset/gorgeous-jeans-begin.md b/.changeset/gorgeous-jeans-begin.md new file mode 100644 index 000000000000..586c4d8a57a3 --- /dev/null +++ b/.changeset/gorgeous-jeans-begin.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: always mark props as stateful diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js index cced326f9baa..4dfdfe5af1a1 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js @@ -93,7 +93,10 @@ export function Identifier(node, context) { context.state.expression.references.add(binding); context.state.expression.has_state ||= binding.kind !== 'static' && - !binding.is_function() && + (binding.kind === 'prop' || + binding.kind === 'bindable_prop' || + binding.kind === 'rest_prop' || + !binding.is_function()) && !context.state.scope.evaluate(node).is_known; } diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-value-function/_config.js b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/_config.js new file mode 100644 index 000000000000..6b281f04f0ee --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/_config.js @@ -0,0 +1,15 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client'], + + test({ assert, target }) { + const btn = target.querySelector('button'); + + assert.htmlEqual(target.innerHTML, ` Inner: 0 Inner: 0`); + btn?.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, ` Inner: 1 Inner: 1`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-value-function/inner.svelte b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/inner.svelte new file mode 100644 index 000000000000..6bde0a15a87c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/inner.svelte @@ -0,0 +1,4 @@ + +Inner: {getter()} diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-value-function/main.svelte b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/main.svelte new file mode 100644 index 000000000000..2cb2f67b82f7 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/main.svelte @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper.svelte b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper.svelte new file mode 100644 index 000000000000..525494ddfbf1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper2.svelte b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper2.svelte new file mode 100644 index 000000000000..9498f432d8ce --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper2.svelte @@ -0,0 +1,7 @@ + + + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy