diff --git a/src/compile/Component.ts b/src/compile/Component.ts index 3bf60fbc46..5a709a1abf 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -861,8 +861,7 @@ export default class Component { // reference instance variables other than other // hoistable functions. TODO others? - const { hoistable_names, hoistable_nodes, imported_declarations, instance_scope: scope } = this; - const template_scope = this.fragment.scope; + const { hoistable_names, hoistable_nodes, imported_declarations, var_lookup } = this; const top_level_function_declarations = new Map(); @@ -870,6 +869,8 @@ export default class Component { if (node.type === 'VariableDeclaration') { if (node.declarations.every(d => d.init && d.init.type === 'Literal' && !this.var_lookup.get(d.id.name).mutated)) { node.declarations.forEach(d => { + const variable = this.var_lookup.get(d.id.name); + variable.hoistable = true; hoistable_names.add(d.id.name); }); @@ -920,7 +921,9 @@ export default class Component { else if (owner === instance_scope) { if (name === fn_declaration.id.name) return; - if (hoistable_names.has(name)) return; + + const variable = var_lookup.get(name); + if (variable.hoistable) return; if (imported_declarations.has(name)) return; if (top_level_function_declarations.has(name)) { @@ -957,6 +960,8 @@ export default class Component { for (const [name, node] of top_level_function_declarations) { if (!checked.has(node) && is_hoistable(node)) { + const variable = this.var_lookup.get(name); + variable.hoistable = true; hoistable_names.add(name); hoistable_nodes.add(node); @@ -1079,7 +1084,8 @@ export default class Component { } qualify(name) { - if (this.hoistable_names.has(name)) return name; + const variable = this.var_lookup.get(name); + if (variable && variable.hoistable) return name; if (this.imported_declarations.has(name)) return name; if (this.declarations.indexOf(name) === -1) return name; diff --git a/src/compile/nodes/shared/Expression.ts b/src/compile/nodes/shared/Expression.ts index fab40ccdc2..5a90259be6 100644 --- a/src/compile/nodes/shared/Expression.ts +++ b/src/compile/nodes/shared/Expression.ts @@ -457,10 +457,12 @@ function isContextual(component: Component, scope: TemplateScope, name: string) // if it's a name below root scope, it's contextual if (!scope.isTopLevel(name)) return true; + const variable = component.var_lookup.get(name); + // hoistables, module declarations, and imports are non-contextual - if (component.hoistable_names.has(name)) return false; - if (component.module_scope && component.module_scope.declarations.has(name)) return false; - if (component.imported_declarations.has(name)) return false; + if (variable.hoistable) return false; + if (variable.module) return false; // TODO make all module-level variables hoistable by default + if (variable.import_type) return false; // TODO ditto // assume contextual return true; diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index 4f5312bf76..9fc17f713f 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -97,7 +97,7 @@ export default function dom( props.forEach(x => { const variable = component.var_lookup.get(x.name); - if (component.imported_declarations.has(x.name) || component.hoistable_names.has(x.name)) { + if (component.imported_declarations.has(x.name) || variable.hoistable) { body.push(deindent` get ${x.exported_as}() { return ${x.name}; @@ -254,14 +254,18 @@ export default function dom( `); const filtered_declarations = component.declarations.filter(name => { - if (component.hoistable_names.has(name)) return false; + const variable = component.var_lookup.get(name); + + if (variable && variable.hoistable) return false; if (component.imported_declarations.has(name)) return false; if (props.find(p => p.exported_as === name)) return true; return component.template_references.has(name); }); const filtered_props = props.filter(prop => { - if (component.hoistable_names.has(prop.name)) return false; + const variable = component.var_lookup.get(prop.name); + + if (variable.hoistable) return false; if (component.imported_declarations.has(prop.name)) return false; if (prop.name[0] === '$') return false; return true; diff --git a/src/compile/render-dom/wrappers/shared/addActions.ts b/src/compile/render-dom/wrappers/shared/addActions.ts index d5732e57bc..68f203e09a 100644 --- a/src/compile/render-dom/wrappers/shared/addActions.ts +++ b/src/compile/render-dom/wrappers/shared/addActions.ts @@ -22,11 +22,8 @@ export default function addActions( ); block.addVariable(name); - const fn = component.imported_declarations.has(action.name) || component.hoistable_names.has(action.name) - ? action.name - : `ctx.${action.name}`; - component.add_reference(action.name); + const fn = component.qualify(action.name); block.builders.mount.addLine( `${name} = ${fn}.call(null, ${target}${snippet ? `, ${snippet}` : ''}) || {};` diff --git a/src/interfaces.ts b/src/interfaces.ts index e511b754d0..2982bc008e 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -91,4 +91,5 @@ export interface Var { referenced?: boolean; writable?: boolean; initialised?: boolean; + hoistable?: boolean; } \ No newline at end of file