diff --git a/src/compile/nodes/shared/Expression.ts b/src/compile/nodes/shared/Expression.ts index 7a3ee7b396..1a09d0ebe4 100644 --- a/src/compile/nodes/shared/Expression.ts +++ b/src/compile/nodes/shared/Expression.ts @@ -65,8 +65,9 @@ export default class Expression { node: any; snippet: string; references: Set; - dependencies: Set; - contextual_dependencies: Set; + dependencies: Set = new Set(); + contextual_dependencies: Set = new Set(); + dynamic_dependencies: Set = new Set(); template_scope: TemplateScope; scope: Scope; @@ -99,17 +100,31 @@ export default class Expression { this.owner = owner; this.is_synthetic = owner.isSynthetic; - const expression_dependencies = new Set(); - const expression_contextual_dependencies = new Set(); - - let dependencies = expression_dependencies; - let contextual_dependencies = expression_contextual_dependencies; + const { dependencies, contextual_dependencies, dynamic_dependencies } = this; let { map, scope } = createScopes(info); this.scope = scope; this.scope_map = map; const expression = this; + let function_expression; + + function add_dependency(name) { + dependencies.add(name); + + if (!function_expression) { + // dynamic_dependencies is used to create `if (changed.foo || ...)` + // conditions — it doesn't apply if the dependency is inside a + // function, and it only applies if the dependency is writable + if (component.instance_script) { + if (component.writable_declarations.has(name)) { + dynamic_dependencies.add(name); + } + } else { + dynamic_dependencies.add(name); + } + } + } // discover dependencies, but don't change the code yet walk(info, { @@ -121,6 +136,10 @@ export default class Expression { scope = map.get(node); } + if (!function_expression && /FunctionExpression/.test(node.type)) { + function_expression = node; + } + if (isReference(node, parent)) { const { name } = flattenReference(node); @@ -132,21 +151,26 @@ export default class Expression { contextual_dependencies.add(name); - template_scope.dependenciesForName.get(name).forEach(dependency => { - dependencies.add(dependency); - }); + template_scope.dependenciesForName.get(name).forEach(add_dependency); } else { - dependencies.add(name); + add_dependency(name); component.template_references.add(name); } this.skip(); } + }, + + leave(node) { + if (map.has(node)) { + scope = scope.parent; + } + + if (node === function_expression) { + function_expression = null; + } } }); - - this.dependencies = dependencies; - this.contextual_dependencies = contextual_dependencies; } getPrecedence() { diff --git a/src/compile/render-dom/wrappers/shared/addActions.ts b/src/compile/render-dom/wrappers/shared/addActions.ts index c5180ff043..2749eb7820 100644 --- a/src/compile/render-dom/wrappers/shared/addActions.ts +++ b/src/compile/render-dom/wrappers/shared/addActions.ts @@ -14,7 +14,7 @@ export default function addActions( let snippet, dependencies; if (expression) { snippet = expression.render(); - dependencies = expression.dependencies; + dependencies = expression.dynamic_dependencies; expression.declarations.forEach(declaration => { block.builders.init.addBlock(declaration); diff --git a/test/js/samples/action-custom-event-handler/expected.js b/test/js/samples/action-custom-event-handler/expected.js index 138b0d3abc..86e300523c 100644 --- a/test/js/samples/action-custom-event-handler/expected.js +++ b/test/js/samples/action-custom-event-handler/expected.js @@ -1,5 +1,5 @@ /* generated by Svelte vX.Y.Z-alpha1 */ -import { SvelteComponent as SvelteComponent_1, addListener, createElement, detachNode, flush, init, insert, noop, removeListener, run, safe_not_equal } from "svelte/internal.js"; +import { SvelteComponent as SvelteComponent_1, createElement, detachNode, flush, init, insert, noop, run, safe_not_equal } from "svelte/internal.js"; function create_fragment(component, ctx) { var button, foo_action, current;