From 23e080371165cc75f890c60980731e1139a75b30 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Thu, 22 Aug 2024 18:13:20 +0100 Subject: [PATCH] add test --- .../2-analyze/visitors/BindDirective.js | 10 ++++++++-- .../phases/2-analyze/visitors/shared/utils.js | 15 +++------------ .../phases/3-transform/client/utils.js | 1 - packages/svelte/src/compiler/utils/ast.js | 17 +++++++++++++++++ .../_config.js | 2 +- .../main.svelte | 2 +- .../samples/derived-update-class/_config.js | 19 +++++++++++++++++++ .../samples/derived-update-class/main.svelte | 10 ++++++++++ .../samples/derived-update/_config.js | 19 +++++++++++++++++++ .../samples/derived-update/main.svelte | 7 +++++++ 10 files changed, 85 insertions(+), 17 deletions(-) rename packages/svelte/tests/compiler-errors/samples/{runes-no-derived-binding => runes-no-destructured-derived-binding}/_config.js (65%) rename packages/svelte/tests/compiler-errors/samples/{runes-no-derived-binding => runes-no-destructured-derived-binding}/main.svelte (73%) create mode 100644 packages/svelte/tests/runtime-runes/samples/derived-update-class/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/derived-update-class/main.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/derived-update/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/derived-update/main.svelte diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js index e116b0fb5c..28c95e61f4 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js @@ -2,6 +2,7 @@ /** @import { Context } from '../types' */ import { extract_all_identifiers_from_expression, + is_binding_pattern_declaration, is_text_attribute, object } from '../../../utils/ast.js'; @@ -45,8 +46,13 @@ export function BindDirective(node, context) { e.bind_invalid_value(node.expression); } - if (binding?.kind === 'derived' && binding.declaration_kind === 'const') { - e.constant_binding(node.expression, 'derived state'); + if (binding?.kind === 'derived') { + if (binding.declaration_kind === 'const') { + e.constant_binding(node.expression, 'constant derived state'); + } + if (is_binding_pattern_declaration(binding)) { + e.constant_binding(node.expression, 'destructured derived state'); + } } if (context.state.analysis.runes && binding?.kind === 'each') { diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js index dd3e05d57e..c24201c157 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js @@ -4,7 +4,7 @@ /** @import { Scope } from '../../../scope' */ /** @import { NodeLike } from '../../../../errors.js' */ import * as e from '../../../../errors.js'; -import { extract_identifiers, object } from '../../../../utils/ast.js'; +import { extract_identifiers, is_binding_pattern_declaration, object } from '../../../../utils/ast.js'; import * as w from '../../../../warnings.js'; /** @@ -23,17 +23,8 @@ export function validate_assignment(node, argument, state) { if (binding.declaration_kind === 'const') { e.constant_assignment(node, 'constant derived state'); } - const binding_path = binding.references.find((r) => r.node === binding.node); - - if (binding_path) { - let declarator_path = binding_path.path.findLast((n) => n.type === 'VariableDeclarator'); - if ( - declarator_path && - (declarator_path.id.type === 'ObjectPattern' || - declarator_path.id.type === 'ArrayPattern') - ) { - e.constant_assignment(node, 'destructured derived state'); - } + if (is_binding_pattern_declaration(binding)) { + e.constant_assignment(node, 'destructured derived state'); } } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index 0f3f450a46..7d662629da 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -50,7 +50,6 @@ export function build_getter(node, state) { * @param {PrivateIdentifier | string} proxy_reference */ export function build_proxy_reassignment(value, proxy_reference) { - debugger return dev ? b.call( '$.proxy', diff --git a/packages/svelte/src/compiler/utils/ast.js b/packages/svelte/src/compiler/utils/ast.js index 273701a0d1..671105b811 100644 --- a/packages/svelte/src/compiler/utils/ast.js +++ b/packages/svelte/src/compiler/utils/ast.js @@ -20,6 +20,23 @@ export function object(expression) { return expression; } +/** + * @param {import("#compiler").Binding} binding + * @returns {boolean} + */ +export function is_binding_pattern_declaration(binding) { + const binding_path = binding.references.find((r) => r.node === binding.node); + + if (binding_path) { + let declarator_path = binding_path.path.findLast((n) => n.type === 'VariableDeclarator'); + + return ( + declarator_path?.id.type === 'ObjectPattern' || declarator_path?.id.type === 'ArrayPattern' + ); + } + return false; +} + /** * Returns true if the attribute contains a single static text node. * @param {Attribute} attribute diff --git a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-binding/_config.js b/packages/svelte/tests/compiler-errors/samples/runes-no-destructured-derived-binding/_config.js similarity index 65% rename from packages/svelte/tests/compiler-errors/samples/runes-no-derived-binding/_config.js rename to packages/svelte/tests/compiler-errors/samples/runes-no-destructured-derived-binding/_config.js index 87b88d79cc..819f044d20 100644 --- a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-binding/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/runes-no-destructured-derived-binding/_config.js @@ -3,6 +3,6 @@ import { test } from '../../test'; export default test({ error: { code: 'constant_binding', - message: 'Cannot bind to derived state' + message: 'Cannot bind to destructured derived state' } }); diff --git a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-binding/main.svelte b/packages/svelte/tests/compiler-errors/samples/runes-no-destructured-derived-binding/main.svelte similarity index 73% rename from packages/svelte/tests/compiler-errors/samples/runes-no-derived-binding/main.svelte rename to packages/svelte/tests/compiler-errors/samples/runes-no-destructured-derived-binding/main.svelte index 6c198dc068..5a1ce987aa 100644 --- a/packages/svelte/tests/compiler-errors/samples/runes-no-derived-binding/main.svelte +++ b/packages/svelte/tests/compiler-errors/samples/runes-no-destructured-derived-binding/main.svelte @@ -1,6 +1,6 @@ diff --git a/packages/svelte/tests/runtime-runes/samples/derived-update-class/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-update-class/_config.js new file mode 100644 index 0000000000..4628d4f5b4 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-update-class/_config.js @@ -0,0 +1,19 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ``, + + test({ assert, target }) { + const [btn1, btn2] = target.querySelectorAll('button'); + + flushSync(() => btn1.click()); + assert.htmlEqual(target.innerHTML, ``); + + flushSync(() => btn2.click()); + assert.htmlEqual(target.innerHTML, ``); + + flushSync(() => btn1.click()); + assert.htmlEqual(target.innerHTML, ``); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/derived-update-class/main.svelte b/packages/svelte/tests/runtime-runes/samples/derived-update-class/main.svelte new file mode 100644 index 0000000000..42a1e7f34d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-update-class/main.svelte @@ -0,0 +1,10 @@ + + + + diff --git a/packages/svelte/tests/runtime-runes/samples/derived-update/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-update/_config.js new file mode 100644 index 0000000000..4628d4f5b4 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-update/_config.js @@ -0,0 +1,19 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ``, + + test({ assert, target }) { + const [btn1, btn2] = target.querySelectorAll('button'); + + flushSync(() => btn1.click()); + assert.htmlEqual(target.innerHTML, ``); + + flushSync(() => btn2.click()); + assert.htmlEqual(target.innerHTML, ``); + + flushSync(() => btn1.click()); + assert.htmlEqual(target.innerHTML, ``); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/derived-update/main.svelte b/packages/svelte/tests/runtime-runes/samples/derived-update/main.svelte new file mode 100644 index 0000000000..894c2adce1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-update/main.svelte @@ -0,0 +1,7 @@ + + + +