From a6985bcd24faa8ec4a8de671b2013d98b0bc629f Mon Sep 17 00:00:00 2001 From: "jyc.dev" Date: Mon, 22 Jun 2026 13:03:18 +0200 Subject: [PATCH 1/3] fix: strip `?` from optional parameters in svelte lang ts (#18448) In `esrap@2.2.12` we fixed the missing `?` in ts files https://github.com/sveltejs/esrap/pull/139 It's good for `ts`, but bad for svelte compiler that was not removing it as it was a esrap issue not printing it :/ This issue came: https://github.com/sveltejs/esrap/issues/141 This PR is fixing the issue in the compiler stripping the `?` --- .changeset/strip-optional-param-marker.md | 5 +++++ packages/svelte/package.json | 2 +- .../phases/1-parse/remove_typescript_nodes.js | 6 +++++ .../_expected/client/index.svelte.js | 22 +++++++++++++++++++ .../_expected/server/index.svelte.js | 15 +++++++++++++ .../index.svelte | 14 ++++++++++++ pnpm-lock.yaml | 12 +++++----- 7 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 .changeset/strip-optional-param-marker.md create mode 100644 packages/svelte/tests/snapshot/samples/typescript-optional-parameter/_expected/client/index.svelte.js create mode 100644 packages/svelte/tests/snapshot/samples/typescript-optional-parameter/_expected/server/index.svelte.js create mode 100644 packages/svelte/tests/snapshot/samples/typescript-optional-parameter/index.svelte diff --git a/.changeset/strip-optional-param-marker.md b/.changeset/strip-optional-param-marker.md new file mode 100644 index 0000000000..a6b759747c --- /dev/null +++ b/.changeset/strip-optional-param-marker.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: strip `?` from optional parameters in ` + +{v} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e86c927efe..6331fd0789 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,8 +102,8 @@ importers: specifier: ^1.2.1 version: 1.2.1 esrap: - specifier: ^2.2.11 - version: 2.2.11(@typescript-eslint/types@8.59.4) + specifier: ^2.2.12 + version: 2.2.12(@typescript-eslint/types@8.59.4) is-reference: specifier: ^3.0.3 version: 3.0.3 @@ -1418,8 +1418,8 @@ packages: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} - esrap@2.2.11: - resolution: {integrity: sha512-gPdx+I+BjYEinNMQaBXFjbaJVyoPMU4ZODg5mE+M4DqVG9VusAVHHjcBX+zqyITlI0DIARwDMMzZwAWj36dRoQ==} + esrap@2.2.12: + resolution: {integrity: sha512-On0QbLyaiAkVC4eXtgnXK9Kh2opit+3rcUSOc45DqJ2s/X2eXAHsGOKRSJ6IDagQEW5vPyivANfXUiqgXC67Rw==} peerDependencies: '@typescript-eslint/types': ^8.2.0 peerDependenciesMeta: @@ -2886,7 +2886,7 @@ snapshots: '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/remapping@2.3.4': @@ -3695,7 +3695,7 @@ snapshots: dependencies: estraverse: 5.3.0 - esrap@2.2.11(@typescript-eslint/types@8.59.4): + esrap@2.2.12(@typescript-eslint/types@8.59.4): dependencies: '@jridgewell/sourcemap-codec': 1.5.5 optionalDependencies: From 36ae0622a8da4c6e60d32cde199af3d7c3121cd3 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Mon, 22 Jun 2026 20:09:04 +0200 Subject: [PATCH 2/3] fix: always unset reactivity context after restoring it (#18453) When calling `save`, we restore the context after the promise resolves. But we do not unset it after the subsequent synchronous execution. That means that until `unset_context` runs in `async_derived` we will not have the correct (nulled) context. That causes problems if the `save` isn't the last promise contributing to the `async_derived`, because it means the context is not properly unset until the promise _after_ the `save` within the `async_derived` settles. This can cause all sorts of mixups, including a wrong mutation error. fixes #18441 --- .changeset/late-geese-fix.md | 5 +++ .../src/internal/client/reactivity/async.js | 2 + .../_config.js | 44 +++++++++++++++++++ .../main.svelte | 28 ++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 .changeset/late-geese-fix.md create mode 100644 packages/svelte/tests/runtime-runes/samples/async-parallel-derived-template-mutation/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/async-parallel-derived-template-mutation/main.svelte diff --git a/.changeset/late-geese-fix.md b/.changeset/late-geese-fix.md new file mode 100644 index 0000000000..b8e83fc8cd --- /dev/null +++ b/.changeset/late-geese-fix.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: always unset reactivity context after restoring it diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js index 13b6e42b3e..2e7df92dc0 100644 --- a/packages/svelte/src/internal/client/reactivity/async.js +++ b/packages/svelte/src/internal/client/reactivity/async.js @@ -25,6 +25,7 @@ import { set_reactivity_loss_tracker } from './deriveds.js'; import { aborted } from './effects.js'; +import { queue_micro_task } from '../dom/task.js'; /** * @param {Blocker[]} blockers @@ -169,6 +170,7 @@ export async function save(promise) { return () => { restore(); + queue_micro_task(unset_context); return value; }; } diff --git a/packages/svelte/tests/runtime-runes/samples/async-parallel-derived-template-mutation/_config.js b/packages/svelte/tests/runtime-runes/samples/async-parallel-derived-template-mutation/_config.js new file mode 100644 index 0000000000..9650e88993 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-parallel-derived-template-mutation/_config.js @@ -0,0 +1,44 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client'], + + compileOptions: { + dev: true + }, + + async test({ assert, target, errors }) { + await tick(); + const [increment, update, resolve] = target.querySelectorAll('button'); + + increment.click(); + await tick(); + + resolve.click(); + await tick(); + + update.click(); + await tick(); + + resolve.click(); + await tick(); + + assert.deepEqual( + errors.filter((error) => error.includes('state_unsafe_mutation')), + [] + ); + assert.htmlEqual( + target.innerHTML, + ` + + + +

count: 1

+

submits: 1

+

pending: 0

+

2

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-parallel-derived-template-mutation/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-parallel-derived-template-mutation/main.svelte new file mode 100644 index 0000000000..d9c804b314 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-parallel-derived-template-mutation/main.svelte @@ -0,0 +1,28 @@ + + + + + + +

count: {count}

+

submits: {submits}

+

pending: {$effect.pending()}

+

{await a + await b}

From eae50dfd1c2269e37258ef5c09527003bcf61573 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:44:52 -0400 Subject: [PATCH 3/3] Version Packages (#18435) This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## svelte@5.56.4 ### Patch Changes - fix: include wrapping parentheses in `{@const}` declarator `end` position ([#18436](https://github.com/sveltejs/svelte/pull/18436)) - fix: always unset reactivity context after restoring it ([#18453](https://github.com/sveltejs/svelte/pull/18453)) - fix: don't notify `searchParams` subscribers when the URL changes without affecting the search string ([#18425](https://github.com/sveltejs/svelte/pull/18425)) - fix: strip `?` from optional parameters in `