From ba5c3ce5740b992c2e047cc4324aad78eb55d4dc Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 15 Dec 2018 12:50:39 -0500 Subject: [PATCH] replace `x = x` altogether --- src/compile/render-dom/index.ts | 23 ++++-- src/utils/nodes_match.ts | 32 +++++++++ .../expected.js | 70 +++++++++++++++++++ .../input.html | 12 ++++ 4 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 src/utils/nodes_match.ts create mode 100644 test/js/samples/instrumentation-script-x-equals-x/expected.js create mode 100644 test/js/samples/instrumentation-script-x-equals-x/input.html diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index c86ad1c5e7..0384a4162e 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -9,6 +9,7 @@ import stringifyProps from '../../utils/stringifyProps'; import addToSet from '../../utils/addToSet'; import getObject from '../../utils/getObject'; import { extractNames } from '../../utils/annotateWithScopes'; +import { nodes_match } from '../../utils/nodes_match'; export default function dom( component: Component, @@ -173,12 +174,22 @@ export default function dom( ? [getObject(node.left).name] : extractNames(node.left); - names.forEach(name => { - if (scope.findOwner(name) === component.instance_scope) { - pending_assignments.add(name); - component.has_reactive_assignments = true; - } - }); + if (node.operator === '=' && nodes_match(node.left, node.right)) { + const dirty = names.filter(name => { + return scope.findOwner(name) === component.instance_scope; + }); + + if (dirty.length) component.has_reactive_assignments = true; + + code.overwrite(node.start, node.end, dirty.map(n => `$$make_dirty('${n}')`).join('; ')); + } else { + names.forEach(name => { + if (scope.findOwner(name) === component.instance_scope) { + pending_assignments.add(name); + component.has_reactive_assignments = true; + } + }); + } } else if (node.type === 'UpdateExpression') { diff --git a/src/utils/nodes_match.ts b/src/utils/nodes_match.ts new file mode 100644 index 0000000000..2b6f998c19 --- /dev/null +++ b/src/utils/nodes_match.ts @@ -0,0 +1,32 @@ +export function nodes_match(a, b) { + if (!!a !== !!b) return false; + if (Array.isArray(a) !== Array.isArray(b)) return false; + + if (a && typeof a === 'object') { + if (Array.isArray(a)) { + if (a.length !== b.length) return false; + return a.every((child, i) => nodes_match(child, b[i])); + } + + const a_keys = Object.keys(a).sort(); + const b_keys = Object.keys(b).sort(); + + if (a_keys.length !== b_keys.length) return false; + + let i = a_keys.length; + while (i--) { + const key = a_keys[i]; + if (b_keys[i] !== key) return false; + + if (key === 'start' || key === 'end') continue; + + if (!nodes_match(a[key], b[key])) { + return false; + } + } + + return true; + } + + return a === b; +} \ No newline at end of file diff --git a/test/js/samples/instrumentation-script-x-equals-x/expected.js b/test/js/samples/instrumentation-script-x-equals-x/expected.js new file mode 100644 index 0000000000..e34525d978 --- /dev/null +++ b/test/js/samples/instrumentation-script-x-equals-x/expected.js @@ -0,0 +1,70 @@ +/* generated by Svelte vX.Y.Z */ +import { SvelteComponent as SvelteComponent_1, addListener, append, createElement, createText, detachNode, init, insert, run, safe_not_equal, setData } from "svelte/internal.js"; + +function create_fragment(component, ctx) { + var button, text1, p, text2, text3_value = ctx.things.length, text3, current, dispose; + + return { + c() { + button = createElement("button"); + button.textContent = "foo"; + text1 = createText("\n\n"); + p = createElement("p"); + text2 = createText("number of things: "); + text3 = createText(text3_value); + dispose = addListener(button, "click", ctx.foo); + }, + + m(target, anchor) { + insert(target, button, anchor); + insert(target, text1, anchor); + insert(target, p, anchor); + append(p, text2); + append(p, text3); + current = true; + }, + + p(changed, ctx) { + if ((changed.things) && text3_value !== (text3_value = ctx.things.length)) { + setData(text3, text3_value); + } + }, + + i(target, anchor) { + if (current) return; + this.m(target, anchor); + }, + + o: run, + + d(detach) { + if (detach) { + detachNode(button); + detachNode(text1); + detachNode(p); + } + + dispose(); + } + }; +} + +function define($$self, $$props, $$make_dirty) { + let things = []; + + function foo() { + things.push(1); + $$make_dirty('things'); + } + + $$self.$$.get = () => ({ things, foo }); +} + +class SvelteComponent extends SvelteComponent_1 { + constructor(options) { + super(); + init(this, options, define, create_fragment, safe_not_equal); + } +} + +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/instrumentation-script-x-equals-x/input.html b/test/js/samples/instrumentation-script-x-equals-x/input.html new file mode 100644 index 0000000000..0873e9fa80 --- /dev/null +++ b/test/js/samples/instrumentation-script-x-equals-x/input.html @@ -0,0 +1,12 @@ + + + + +

number of things: {things.length}

\ No newline at end of file