From 9f2b5afdf777b2144d7e48feb3b264ed16b6d8de Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Fri, 7 Jan 2022 04:28:53 +0800 Subject: [PATCH] [fix] binding member expression should only invalidate the object, not the member property (#7008) --- .../render_dom/wrappers/Element/Binding.ts | 24 +++++++++++++++++++ .../render_dom/wrappers/Element/index.ts | 2 +- .../render_dom/wrappers/shared/bind_this.ts | 2 +- .../_config.js | 18 ++++++++++++++ .../main.svelte | 9 +++++++ .../samples/binding-this-each-key/_config.js | 10 ++++++++ .../samples/binding-this-each-key/main.svelte | 15 ++++++++++++ .../_config.js | 8 +++++++ .../main.svelte | 9 +++++++ 9 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 test/runtime/samples/binding-input-member-expression-update/_config.js create mode 100644 test/runtime/samples/binding-input-member-expression-update/main.svelte create mode 100644 test/runtime/samples/binding-this-each-key/_config.js create mode 100644 test/runtime/samples/binding-this-each-key/main.svelte create mode 100644 test/runtime/samples/binding-this-member-expression-update/_config.js create mode 100644 test/runtime/samples/binding-this-member-expression-update/main.svelte diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index 7c8a339d0086..bc218a510bc1 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -70,6 +70,30 @@ export default class BindingWrapper { return dependencies; } + get_update_dependencies() { + const object = this.object; + const dependencies = new Set(); + if (this.node.expression.template_scope.names.has(object)) { + this.node.expression.template_scope.dependencies_for_name + .get(object) + .forEach((name) => dependencies.add(name)); + } else { + dependencies.add(object); + } + + const result = new Set(dependencies); + dependencies.forEach((dependency) => { + const indirect_dependencies = this.parent.renderer.component.indirect_dependencies.get(dependency); + if (indirect_dependencies) { + indirect_dependencies.forEach(indirect_dependency => { + result.add(indirect_dependency); + }); + } + }); + + return result; + } + is_readonly_media_attribute() { return this.node.is_readonly_media_attribute(); } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 9ec36b12d7da..583274044bcb 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -466,7 +466,7 @@ export default class ElementWrapper extends Wrapper { binding_group.bindings.forEach(binding => { // TODO this is a mess - add_to_set(dependencies, binding.get_dependencies()); + add_to_set(dependencies, binding.get_update_dependencies()); add_to_set(contextual_dependencies, binding.handler.contextual_dependencies); binding.render(block, lock); diff --git a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts index 1b8c4f9db869..af440b63414e 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts @@ -12,7 +12,7 @@ export default function bind_this(component: Component, block: Block, binding: B const callee = block.renderer.reference(fn.name); const { contextual_dependencies, mutation } = binding.handler; - const dependencies = binding.get_dependencies(); + const dependencies = binding.get_update_dependencies(); const body = b` ${mutation} diff --git a/test/runtime/samples/binding-input-member-expression-update/_config.js b/test/runtime/samples/binding-input-member-expression-update/_config.js new file mode 100644 index 000000000000..c0dfc3bbe8c4 --- /dev/null +++ b/test/runtime/samples/binding-input-member-expression-update/_config.js @@ -0,0 +1,18 @@ +// binding member expression shouldn't invalidate the property name +export default { + async test({ assert, component, target, window }) { + const input = target.querySelector('input'); + assert.deepEqual(component.logs.length, 1); + assert.equal(input.value, 'abc'); + + input.value = 'hij'; + await input.dispatchEvent(new window.Event('input')); + + assert.deepEqual(component.values.a, 'hij'); + assert.deepEqual(component.logs.length, 1); + + component.paths = ['b']; + assert.deepEqual(component.logs.length, 2); + assert.equal(input.value, 'def'); + } +}; diff --git a/test/runtime/samples/binding-input-member-expression-update/main.svelte b/test/runtime/samples/binding-input-member-expression-update/main.svelte new file mode 100644 index 000000000000..dc72b229ba86 --- /dev/null +++ b/test/runtime/samples/binding-input-member-expression-update/main.svelte @@ -0,0 +1,9 @@ + + + diff --git a/test/runtime/samples/binding-this-each-key/_config.js b/test/runtime/samples/binding-this-each-key/_config.js new file mode 100644 index 000000000000..332e14fda80a --- /dev/null +++ b/test/runtime/samples/binding-this-each-key/_config.js @@ -0,0 +1,10 @@ +export default { + html: '
content
content
content
', + + test({ assert, target, component }) { + const divs = target.querySelectorAll('div'); + assert.equal(component.refs[0], divs[0]); + assert.equal(component.refs[1], divs[1]); + assert.equal(component.refs[2], divs[2]); + } +}; diff --git a/test/runtime/samples/binding-this-each-key/main.svelte b/test/runtime/samples/binding-this-each-key/main.svelte new file mode 100644 index 000000000000..cff2ffa226ca --- /dev/null +++ b/test/runtime/samples/binding-this-each-key/main.svelte @@ -0,0 +1,15 @@ + + +{#each list as { id }, index (id)} +
+ content +
+{/each} diff --git a/test/runtime/samples/binding-this-member-expression-update/_config.js b/test/runtime/samples/binding-this-member-expression-update/_config.js new file mode 100644 index 000000000000..782d44311cac --- /dev/null +++ b/test/runtime/samples/binding-this-member-expression-update/_config.js @@ -0,0 +1,8 @@ +// binding member expression shouldn't invalidate the property name +export default { + test({ assert, component, target }) { + const div = target.querySelector('div'); + assert.equal(div, component.container.a); + assert.deepEqual(component.logs.length, 1); + } +}; diff --git a/test/runtime/samples/binding-this-member-expression-update/main.svelte b/test/runtime/samples/binding-this-member-expression-update/main.svelte new file mode 100644 index 000000000000..327d63d494b2 --- /dev/null +++ b/test/runtime/samples/binding-this-member-expression-update/main.svelte @@ -0,0 +1,9 @@ + + +