From 3e222fca39f4c0ba84dfe3130176dc38149a2bf1 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Mon, 9 Dec 2024 22:46:05 +0000 Subject: [PATCH 01/12] feat: add state.opqaue rune --- .changeset/large-papayas-serve.md | 5 +++ .../98-reference/.generated/compile-errors.md | 6 +++ .../svelte/messages/compile-errors/script.md | 4 ++ packages/svelte/src/ambient.d.ts | 29 ++++++++++++++ packages/svelte/src/compiler/errors.js | 9 +++++ .../2-analyze/visitors/CallExpression.js | 15 +++++++- .../2-analyze/visitors/VariableDeclarator.js | 18 ++++++--- .../client/visitors/VariableDeclaration.js | 16 +++++++- .../client/visitors/shared/declarations.js | 12 +++++- .../server/visitors/VariableDeclaration.js | 13 ++++++- packages/svelte/src/compiler/types/index.d.ts | 1 + packages/svelte/src/internal/client/index.js | 2 +- .../internal/client/reactivity/equality.js | 4 ++ .../src/internal/client/reactivity/sources.js | 13 ++++++- packages/svelte/src/utils.js | 1 + .../samples/opaque-state/_config.js | 38 +++++++++++++++++++ .../samples/opaque-state/main.svelte | 19 ++++++++++ packages/svelte/types/index.d.ts | 29 ++++++++++++++ 18 files changed, 222 insertions(+), 12 deletions(-) create mode 100644 .changeset/large-papayas-serve.md create mode 100644 packages/svelte/tests/runtime-runes/samples/opaque-state/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/opaque-state/main.svelte diff --git a/.changeset/large-papayas-serve.md b/.changeset/large-papayas-serve.md new file mode 100644 index 000000000000..383c649c6238 --- /dev/null +++ b/.changeset/large-papayas-serve.md @@ -0,0 +1,5 @@ +--- +'svelte': minor +--- + +feat: add $state.opqaue rune diff --git a/documentation/docs/98-reference/.generated/compile-errors.md b/documentation/docs/98-reference/.generated/compile-errors.md index 3bd162d8d74d..180579db450e 100644 --- a/documentation/docs/98-reference/.generated/compile-errors.md +++ b/documentation/docs/98-reference/.generated/compile-errors.md @@ -748,6 +748,12 @@ This snippet is shadowing the prop `%prop%` with the same name Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties ``` +### state_invalid_opaque_declaration + +``` +`$state.opaque` must be declared with an array destructuring pattern (e.g. `let [state, invalidate] = $state.opaque(data);`) +``` + ### state_invalid_placement ``` diff --git a/packages/svelte/messages/compile-errors/script.md b/packages/svelte/messages/compile-errors/script.md index 69007bfb5919..f616918c9f7a 100644 --- a/packages/svelte/messages/compile-errors/script.md +++ b/packages/svelte/messages/compile-errors/script.md @@ -168,6 +168,10 @@ It's possible to export a snippet from a ` + * + * + * ``` + * + * https://svelte.dev/docs/svelte/$state#$state.opaque + * + * @param initial The initial value + */ + export function opaque(initial: T): [T, () => void]; + export function opaque(): [T | undefined, () => void]; + /** * To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: * diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 901ea1983ea7..5f2a77a40eac 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -432,6 +432,15 @@ export function state_invalid_export(node) { e(node, "state_invalid_export", "Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties"); } +/** + * `$state.opaque` must be declared with an array destructuring pattern (e.g. `let [state, invalidate] = $state.opaque(data);`) + * @param {null | number | NodeLike} node + * @returns {never} + */ +export function state_invalid_opaque_declaration(node) { + e(node, "state_invalid_opaque_declaration", "`$state.opaque` must be declared with an array destructuring pattern (e.g. `let [state, invalidate] = $state.opaque(data);`)"); +} + /** * `%rune%(...)` can only be used as a variable declaration initializer or a class field * @param {null | number | NodeLike} node diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js index c7ade4856bcb..b669441cb587 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js @@ -75,6 +75,7 @@ export function CallExpression(node, context) { case '$state': case '$state.raw': + case '$state.opaque': case '$derived': case '$derived.by': if ( @@ -86,9 +87,21 @@ export function CallExpression(node, context) { if ((rune === '$derived' || rune === '$derived.by') && node.arguments.length !== 1) { e.rune_invalid_arguments_length(node, rune, 'exactly one argument'); - } else if (rune === '$state' && node.arguments.length > 1) { + } else if ( + (rune === '$state' || rune === '$state.raw' || rune === '$state.opaque') && + node.arguments.length > 1 + ) { e.rune_invalid_arguments_length(node, rune, 'zero or one arguments'); } + if ( + rune === '$state.opaque' && + (parent.type !== 'VariableDeclarator' || + parent.id.type !== 'ArrayPattern' || + parent.id.elements.length !== 2 || + parent.id.elements[0]?.type !== 'Identifier') + ) { + e.state_invalid_opaque_declaration(node); + } break; diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js index a7d08d315d8f..e2d8bd8986fa 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js @@ -27,11 +27,15 @@ export function VariableDeclarator(node, context) { if ( rune === '$state' || rune === '$state.raw' || + rune === '$state.opaque' || rune === '$derived' || rune === '$derived.by' || rune === '$props' ) { - for (const path of paths) { + for (let i = 0; i < paths.length; i++) { + if (rune === '$state.opaque' && i === 1) continue; + + const path = paths[i]; // @ts-ignore this fails in CI for some insane reason const binding = /** @type {Binding} */ (context.state.scope.get(path.node.name)); binding.kind = @@ -39,11 +43,13 @@ export function VariableDeclarator(node, context) { ? 'state' : rune === '$state.raw' ? 'raw_state' - : rune === '$derived' || rune === '$derived.by' - ? 'derived' - : path.is_rest - ? 'rest_prop' - : 'prop'; + : rune === '$state.opaque' + ? 'opaque_state' + : rune === '$derived' || rune === '$derived.by' + ? 'derived' + : path.is_rest + ? 'rest_prop' + : 'prop'; } } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 04685b66bd0c..331dff952e6e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -1,4 +1,4 @@ -/** @import { CallExpression, Expression, Identifier, Literal, VariableDeclaration, VariableDeclarator } from 'estree' */ +/** @import { ArrayPattern, CallExpression, Expression, Identifier, Literal, VariableDeclaration, VariableDeclarator } from 'estree' */ /** @import { Binding } from '#compiler' */ /** @import { ComponentClientTransformState, ComponentContext } from '../types' */ import { dev } from '../../../../state.js'; @@ -156,6 +156,20 @@ export function VariableDeclaration(node, context) { continue; } + if (rune === '$state.opaque') { + const pattern = /** @type {ArrayPattern} */ (declarator.id); + const state_id = /** @type {Identifier} */ (pattern.elements[0]); + const invalidation_id = /** @type {Identifier} */ (pattern.elements[1]); + declarations.push( + b.declarator(state_id, b.call('$.opaque_state', value)), + b.declarator( + invalidation_id, + b.thunk(b.call('$.set', state_id, b.member(state_id, b.id('v')))) + ) + ); + continue; + } + if (rune === '$derived' || rune === '$derived.by') { if (declarator.id.type === 'Identifier') { declarations.push( diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/declarations.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/declarations.js index 0bd8c352f6a9..759c2fa91c5e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/declarations.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/declarations.js @@ -1,4 +1,4 @@ -/** @import { Identifier } from 'estree' */ +/** @import { Expression, Identifier } from 'estree' */ /** @import { ComponentContext, Context } from '../../types' */ import { is_state_source } from '../../utils.js'; import * as b from '../../../../../utils/builders.js'; @@ -48,6 +48,16 @@ export function add_state_transformers(context) { ); } }; + } else if (binding.kind === 'opaque_state') { + context.state.transform[name] = { + read: binding.declaration_kind === 'var' ? (node) => b.call('$.safe_get', node) : get_value, + assign: (node, value) => { + return b.assignment('=', b.member(node, b.id('v')), /** @type {Expression} */ (value)); + }, + update: (node) => { + return b.update(node.operator, b.member(node.argument, b.id('v')), node.prefix); + } + }; } } } diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js index 31de811ac76f..889fffd31a97 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js @@ -1,4 +1,4 @@ -/** @import { VariableDeclaration, VariableDeclarator, Expression, CallExpression, Pattern, Identifier } from 'estree' */ +/** @import { ArrayPattern, VariableDeclaration, VariableDeclarator, Expression, CallExpression, Pattern, Identifier } from 'estree' */ /** @import { Binding } from '#compiler' */ /** @import { Context } from '../types.js' */ /** @import { Scope } from '../../../scope.js' */ @@ -92,6 +92,17 @@ export function VariableDeclaration(node, context) { continue; } + if (rune === '$state.opaque') { + const pattern = /** @type {ArrayPattern} */ (declarator.id); + const state_id = /** @type {Identifier} */ (pattern.elements[0]); + const invalidation_id = /** @type {Identifier} */ (pattern.elements[1]); + declarations.push( + b.declarator(state_id, value), + b.declarator(invalidation_id, b.thunk(b.block([]))) + ); + continue; + } + declarations.push(...create_state_declarators(declarator, context.state.scope, value)); } } else { diff --git a/packages/svelte/src/compiler/types/index.d.ts b/packages/svelte/src/compiler/types/index.d.ts index fe306bd020e1..89359eb3414d 100644 --- a/packages/svelte/src/compiler/types/index.d.ts +++ b/packages/svelte/src/compiler/types/index.d.ts @@ -274,6 +274,7 @@ export interface Binding { | 'rest_prop' | 'state' | 'raw_state' + | 'opaque_state' | 'derived' | 'each' | 'snippet' diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index b706e52a5378..e5be80d50801 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -108,7 +108,7 @@ export { user_effect, user_pre_effect } from './reactivity/effects.js'; -export { mutable_state, mutate, set, state } from './reactivity/sources.js'; +export { mutable_state, mutate, set, state, opaque_state } from './reactivity/sources.js'; export { prop, rest_props, diff --git a/packages/svelte/src/internal/client/reactivity/equality.js b/packages/svelte/src/internal/client/reactivity/equality.js index 37a9994ab8cc..929d4cbc54b7 100644 --- a/packages/svelte/src/internal/client/reactivity/equality.js +++ b/packages/svelte/src/internal/client/reactivity/equality.js @@ -28,3 +28,7 @@ export function not_equal(a, b) { export function safe_equals(value) { return !safe_not_equal(value, this.v); } + +export function opaque_equals() { + return false; +} diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index 4bbd470d08c8..f9b54853ec04 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -20,7 +20,7 @@ import { set_is_flushing_effect, is_flushing_effect } from '../runtime.js'; -import { equals, safe_equals } from './equality.js'; +import { equals, opaque_equals, safe_equals } from './equality.js'; import { CLEAN, DERIVED, @@ -88,6 +88,17 @@ export function mutable_source(initial_value, immutable = false) { return s; } +/** + * @template V + * @param {V} v + * @returns {Source} + */ +export function opaque_state(v) { + var s = source(v); + s.equals = opaque_equals; + return push_derived_source(s); +} + /** * @template V * @param {V} v diff --git a/packages/svelte/src/utils.js b/packages/svelte/src/utils.js index 75171c17865a..1144717b3dee 100644 --- a/packages/svelte/src/utils.js +++ b/packages/svelte/src/utils.js @@ -420,6 +420,7 @@ export function is_mathml(name) { const RUNES = /** @type {const} */ ([ '$state', '$state.raw', + '$state.opaque', '$state.snapshot', '$props', '$bindable', diff --git a/packages/svelte/tests/runtime-runes/samples/opaque-state/_config.js b/packages/svelte/tests/runtime-runes/samples/opaque-state/_config.js new file mode 100644 index 000000000000..77c0fd0aa8ec --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/opaque-state/_config.js @@ -0,0 +1,38 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { assert_ok } from '../../../suite'; + +export default test({ + html: `
0
0
`, + ssrHtml: `
0
0
`, + + test({ assert, target }) { + const [b1, b2] = target.querySelectorAll('button'); + const input = target.querySelector('input'); + assert_ok(input); + + b1?.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + `
0
0
` + ); + assert.equal(input.value, '0'); + + b2?.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + `
1
1
` + ); + assert.equal(input.value, '1'); + + input.value = '2'; + input.dispatchEvent(new window.Event('input')); + flushSync(); + assert.htmlEqual( + target.innerHTML, + `
1
1
` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/opaque-state/main.svelte b/packages/svelte/tests/runtime-runes/samples/opaque-state/main.svelte new file mode 100644 index 000000000000..54016cefce3b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/opaque-state/main.svelte @@ -0,0 +1,19 @@ + + + + + + +
{count}
+
{value.count}
+ + diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 0d761919a8e0..c1c8f5654ddf 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -2665,6 +2665,35 @@ declare namespace $state { */ export function raw(initial: T): T; export function raw(): T | undefined; + + /** + * Declares state that is _not_ known to Svelte and thus is completely opaque to + * reassignments and mutations. To let Svelte know that the value has changed, + * you must invoke its invalidate function manually. + * + * Example: + * ```ts + * + * + * + * ``` + * + * https://svelte.dev/docs/svelte/$state#$state.opaque + * + * @param initial The initial value + */ + export function opaque(initial: T): [T, () => void]; + export function opaque(): [T | undefined, () => void]; + /** * To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: * From 9a8b448899c2e9f0c4b2b5af1c0ad6528a37ce53 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Mon, 9 Dec 2024 22:53:31 +0000 Subject: [PATCH 02/12] typo --- .changeset/large-papayas-serve.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/large-papayas-serve.md b/.changeset/large-papayas-serve.md index 383c649c6238..f4885eda88d9 100644 --- a/.changeset/large-papayas-serve.md +++ b/.changeset/large-papayas-serve.md @@ -2,4 +2,4 @@ 'svelte': minor --- -feat: add $state.opqaue rune +feat: adds $state.opaque rune From 409bebc1b5dc4a5864bb48c2bbc89a31409d33b1 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Mon, 9 Dec 2024 23:01:16 +0000 Subject: [PATCH 03/12] lint --- .../docs/98-reference/.generated/compile-errors.md | 2 +- packages/svelte/messages/compile-errors/script.md | 2 +- packages/svelte/src/compiler/errors.js | 7 ++++--- .../compiler/phases/2-analyze/visitors/CallExpression.js | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/documentation/docs/98-reference/.generated/compile-errors.md b/documentation/docs/98-reference/.generated/compile-errors.md index 180579db450e..7509f0db632a 100644 --- a/documentation/docs/98-reference/.generated/compile-errors.md +++ b/documentation/docs/98-reference/.generated/compile-errors.md @@ -751,7 +751,7 @@ Cannot export state from a module if it is reassigned. Either export a function ### state_invalid_opaque_declaration ``` -`$state.opaque` must be declared with an array destructuring pattern (e.g. `let [state, invalidate] = $state.opaque(data);`) +`%rune%(...)` must be declared with an array destructuring pattern (e.g. `let [state, invalidate] = $state.opaque(data);`) ``` ### state_invalid_placement diff --git a/packages/svelte/messages/compile-errors/script.md b/packages/svelte/messages/compile-errors/script.md index f616918c9f7a..e5f59612acff 100644 --- a/packages/svelte/messages/compile-errors/script.md +++ b/packages/svelte/messages/compile-errors/script.md @@ -170,7 +170,7 @@ It's possible to export a snippet from a ` + +

{obj.count}

diff --git a/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/_config.js b/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/_config.js new file mode 100644 index 000000000000..b5f7e8815459 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/_config.js @@ -0,0 +1,18 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: `

0

`, + + test({ assert, target }) { + const button = target.querySelector('button'); + + button?.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, `

1

`); + + button?.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, `

2

`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/main.svelte b/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/main.svelte new file mode 100644 index 000000000000..8efd150aece4 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/opaque-state-fn/main.svelte @@ -0,0 +1,8 @@ + + + + diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 82a20ff9c524..f39299a08af3 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -2691,8 +2691,8 @@ declare namespace $state { * * @param initial The initial value */ - export function opaque(initial: T): [T, () => void]; - export function opaque(): [T | undefined, () => void]; + export function opaque(initial: T): [T, (mutate?: (value: T) => void) => void]; + export function opaque(): [T | undefined, (mutate?: (value: T) => void) => void]; /** * To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: From 13ca61e33ed2ac04500bd63572ab33c85a881be3 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Fri, 13 Dec 2024 16:14:54 +0000 Subject: [PATCH 11/12] fix --- .../client/visitors/VariableDeclaration.js | 2 +- .../server/visitors/VariableDeclaration.js | 2 +- packages/svelte/src/compiler/utils/builders.js | 11 +++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index c88db8b6d997..6e9bcb00094c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -167,7 +167,7 @@ export function VariableDeclaration(node, context) { b.arrow( [b.id('$$fn')], b.sequence([ - b.call(b.id('$$fn'), b.member(state_id, b.id('v'))), + b.chain_call(b.id('$$fn'), b.member(state_id, b.id('v'))), b.call('$.set', state_id, b.member(state_id, b.id('v'))) ]) ) diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js index a70f2852b855..122e664f4bb2 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js @@ -98,7 +98,7 @@ export function VariableDeclaration(node, context) { const invalidation_id = /** @type {Identifier} */ (pattern.elements[1]); declarations.push( b.declarator(state_id, value), - b.declarator(invalidation_id, b.arrow([b.id('$$fn')], b.call(b.id('$$fn'), state_id))) + b.declarator(invalidation_id, b.arrow([b.id('$$fn')], b.chain_call(b.id('$$fn'), state_id))) ); continue; } diff --git a/packages/svelte/src/compiler/utils/builders.js b/packages/svelte/src/compiler/utils/builders.js index ecb595d74dbd..c1e68363a050 100644 --- a/packages/svelte/src/compiler/utils/builders.js +++ b/packages/svelte/src/compiler/utils/builders.js @@ -130,6 +130,17 @@ export function call(callee, ...args) { }; } +/** + * @param {string | ESTree.Expression} callee + * @param {...(ESTree.Expression | ESTree.SpreadElement | false | undefined)} args + * @returns {ESTree.ChainExpression} + */ +export function chain_call(callee, ...args) { + const expression = /** @type {ESTree.SimpleCallExpression} */ (call(callee, ...args)); + expression.optional = true; + return { type: 'ChainExpression', expression }; +} + /** * @param {string | ESTree.Expression} callee * @param {...ESTree.Expression} args From 21b08650a6775b45e6186d9014b58abb2a282ebf Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Fri, 13 Dec 2024 16:18:31 +0000 Subject: [PATCH 12/12] fix --- .../3-transform/server/visitors/VariableDeclaration.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js index 122e664f4bb2..a522310203c9 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js @@ -98,7 +98,10 @@ export function VariableDeclaration(node, context) { const invalidation_id = /** @type {Identifier} */ (pattern.elements[1]); declarations.push( b.declarator(state_id, value), - b.declarator(invalidation_id, b.arrow([b.id('$$fn')], b.chain_call(b.id('$$fn'), state_id))) + b.declarator( + invalidation_id, + b.arrow([b.id('$$fn')], b.chain_call(b.id('$$fn'), state_id)) + ) ); continue; }