diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 542e9d1702..fddd1972bf 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -12,7 +12,7 @@ import get_object from '../../utils/get_object'; import Block from '../../render_dom/Block'; import { INode } from '../interfaces'; import is_dynamic from '../../render_dom/wrappers/shared/is_dynamic'; -import { nodes_match } from '../../../utils/nodes_match'; +import { invalidate } from '../../utils/invalidate'; const binary_operators: Record = { '**': 15, @@ -384,7 +384,6 @@ export default class Expression { contextual_dependencies = null; } - // TODO dry out — most of this is shared with render_dom/index.ts if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') { const assignee = node.type === 'AssignmentExpression' ? node.left : node.argument; @@ -404,57 +403,7 @@ export default class Expression { } }); - const [head, ...tail] = Array.from(traced).filter(name => { - const owner = scope.find_owner(name); - if (owner && owner !== component.instance_scope) return; - - const variable = component.var_lookup.get(name); - - return variable && ( - !variable.hoistable && - !variable.global && - !variable.module && - ( - variable.referenced || - variable.is_reactive_dependency || - variable.export_name - ) - ); - }); - - if (head) { - component.has_reactive_assignments = true; - - if (node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) { - code.overwrite(node.start, node.end, component.invalidate(head)); - } else { - let suffix = ')'; - - if (head[0] === '$') { - code.prependRight(node.start, `${component.helper('set_store_value')}(${head.slice(1)}, `); - } else { - let prefix = `$$invalidate`; - - const variable = component.var_lookup.get(head); - if (variable.subscribable && variable.reassigned) { - prefix = `$$subscribe_${head}($$invalidate`; - suffix += `)`; - } - - code.prependRight(node.start, `${prefix}('${head}', `); - } - - const extra_args = tail.map(name => component.invalidate(name)); - - if (assignee.type !== 'Identifier' || node.type === 'UpdateExpression' && !node.prefix || extra_args.length > 0) { - extra_args.unshift(head); - } - - suffix = `${extra_args.map(arg => `, ${arg}`).join('')}${suffix}`; - - code.appendLeft(node.end, suffix); - } - } + invalidate(component, scope, code, node, Array.from(traced)); } } }); diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 73655ce6ed..a08df9e83d 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -7,8 +7,8 @@ import { CompileOptions } from '../../interfaces'; import { walk } from 'estree-walker'; import { stringify_props } from '../utils/stringify_props'; import add_to_set from '../utils/add_to_set'; -import { nodes_match } from '../../utils/nodes_match'; import { extract_names } from '../utils/scope'; +import { invalidate } from '../utils/invalidate'; export default function dom( component: Component, @@ -179,57 +179,7 @@ export default function dom( // onto the initial function call const names = new Set(extract_names(assignee)); - const [head, ...tail] = Array.from(names).filter(name => { - const owner = scope.find_owner(name); - if (owner && owner !== component.instance_scope) return; - - const variable = component.var_lookup.get(name); - - return variable && ( - !variable.hoistable && - !variable.global && - !variable.module && - ( - variable.referenced || - variable.is_reactive_dependency || - variable.export_name - ) - ); - }); - - if (head) { - component.has_reactive_assignments = true; - - if (node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) { - code.overwrite(node.start, node.end, component.invalidate(head)); - } else { - let suffix = ')'; - - if (head[0] === '$') { - code.prependRight(node.start, `${component.helper('set_store_value')}(${head.slice(1)}, `); - } else { - let prefix = `$$invalidate`; - - const variable = component.var_lookup.get(head); - if (variable.subscribable && variable.reassigned) { - prefix = `$$subscribe_${head}($$invalidate`; - suffix += `)`; - } - - code.prependRight(node.start, `${prefix}('${head}', `); - } - - const extra_args = tail.map(name => component.invalidate(name)); - - if (assignee.type !== 'Identifier' || node.type === 'UpdateExpression' && !node.prefix || extra_args.length > 0) { - extra_args.unshift(head); - } - - suffix = `${extra_args.map(arg => `, ${arg}`).join('')}${suffix}`; - - code.appendLeft(node.end, suffix); - } - } + invalidate(component, scope, code, node, Array.from(names)); } } }); diff --git a/src/compiler/compile/utils/invalidate.ts b/src/compiler/compile/utils/invalidate.ts new file mode 100644 index 0000000000..2b751a4e3e --- /dev/null +++ b/src/compiler/compile/utils/invalidate.ts @@ -0,0 +1,65 @@ +import Component from '../Component'; +import MagicString from 'magic-string'; +import { Node } from '../../interfaces'; +import { nodes_match } from '../../utils/nodes_match'; +import { Scope } from './scope'; + +export function invalidate(component: Component, scope: Scope, code: MagicString, node: Node, names: string[]) { + const [head, ...tail] = Array.from(names).filter(name => { + const owner = scope.find_owner(name); + if (owner && owner !== component.instance_scope) return false; + + const variable = component.var_lookup.get(name); + + return variable && ( + !variable.hoistable && + !variable.global && + !variable.module && + ( + variable.referenced || + variable.is_reactive_dependency || + variable.export_name + ) + ); + }); + + if (head) { + component.has_reactive_assignments = true; + + if (node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) { + code.overwrite(node.start, node.end, component.invalidate(head)); + } else { + let suffix = ')'; + + if (head[0] === '$') { + code.prependRight(node.start, `${component.helper('set_store_value')}(${head.slice(1)}, `); + } else { + let prefix = `$$invalidate`; + + const variable = component.var_lookup.get(head); + if (variable.subscribable && variable.reassigned) { + prefix = `$$subscribe_${head}($$invalidate`; + suffix += `)`; + } + + code.prependRight(node.start, `${prefix}('${head}', `); + } + + const extra_args = tail.map(name => component.invalidate(name)); + + const pass_value = ( + extra_args.length > 0 || + (node.type === 'AssignmentExpression' && node.left.type !== 'Identifier') || + (node.type === 'UpdateExpression' && !node.prefix) + ); + + if (pass_value) { + extra_args.unshift(head); + } + + suffix = `${extra_args.map(arg => `, ${arg}`).join('')}${suffix}`; + + code.appendLeft(node.end, suffix); + } + } +} \ No newline at end of file