diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 45a8f3ae96..aa25b89771 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -213,15 +213,8 @@ export default class Expression { component.add_reference(name); // TODO is this redundant/misplaced? } } else if (is_contextual(component, template_scope, name)) { - const reference = block.renderer.reference(name); - if (node.type === 'Identifier') { - this.replace(reference); - } else { - while (node.object.type === 'MemberExpression') { - node = node.object; - } - node.object = reference; - } + const reference = block.renderer.reference(node); + this.replace(reference); } this.skip(); @@ -269,7 +262,7 @@ export default class Expression { component.partly_hoisted.push(declaration); block.renderer.add_to_context(id.name); - this.replace(block.renderer.reference(id.name)); + this.replace(block.renderer.reference(id)); } else { @@ -286,7 +279,7 @@ export default class Expression { component.partly_hoisted.push(declaration); block.renderer.add_to_context(id.name); - const callee = block.renderer.reference(id.name); + const callee = block.renderer.reference(id); this.replace(id as any); diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index c015bcfdb5..b7c91eede0 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -3,7 +3,8 @@ import { CompileOptions } from '../../interfaces'; import Component from '../Component'; import FragmentWrapper from './wrappers/Fragment'; import { x } from 'code-red'; -import { Node, Identifier } from 'estree'; +import { Node, Identifier, MemberExpression } from 'estree'; +import flatten_reference from '../utils/flatten_reference'; export default class Renderer { component: Component; // TODO Maybe Renderer shouldn't know about Component? @@ -158,23 +159,28 @@ export default class Renderer { : x`#changed & ${bitmask}`; } - reference(name) { - const i = this.context_lookup.get(name); - - if (name === `$$props`) return x`#ctx[${i}]`; - - let [head, ...tail] = name.split('.'); + reference(node: string | Identifier | MemberExpression) { + if (typeof node === 'string') { + node = { type: 'Identifier', name: node }; + } - const variable = this.component.var_lookup.get(head); + const { name, nodes } = flatten_reference(node); + const i = this.context_lookup.get(name); - if (variable) { - this.component.add_reference(name); // TODO we can probably remove most other occurrences of this + // TODO is this correct? + if (this.component.var_lookup.get(name)) { + this.component.add_reference(name); } if (i !== undefined) { - head = x`#ctx[${i}]`; + const replacement = x`#ctx[${i}]` as MemberExpression; + + replacement.object.loc = nodes[0].loc; + nodes[0] = replacement; + + return nodes.reduce((lhs, rhs) => x`${lhs}.${rhs}`); } - return [head, ...tail].reduce((lhs, rhs) => x`${lhs}.${rhs}`); + return node; } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts index e247156f8b..bc798d2e53 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts @@ -26,7 +26,7 @@ export default class EventHandlerWrapper { } get_snippet(block) { - const snippet = this.node.expression ? this.node.expression.manipulate(block) : block.renderer.reference(this.node.handler_name.name); + const snippet = this.node.expression ? this.node.expression.manipulate(block) : block.renderer.reference(this.node.handler_name); if (this.node.reassigned) { block.maintain_context = true; diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index cc0bd37723..467578abf9 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -488,7 +488,7 @@ export default class ElementWrapper extends Wrapper { const has_local_function = contextual_dependencies.size > 0 || needs_lock || animation_frame; - let callee = renderer.reference(handler.name); + let callee = renderer.reference(handler); // TODO dry this out — similar code for event handlers and component bindings if (has_local_function) { diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index b42302b222..3417b563e2 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -281,7 +281,7 @@ export default class InlineComponentWrapper extends Wrapper { const id = component.get_unique_name(`${this.var.name}_${binding.name}_binding`); renderer.add_to_context(id.name); - const callee = renderer.reference(id.name); + const callee = renderer.reference(id); const updating = block.get_unique_name(`updating_${binding.name}`); block.add_variable(updating);