From 7d55a57a2cac704215a416e9d642a9bf4d9da5f8 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 4 Aug 2018 10:27:24 -0400 Subject: [PATCH] handle rest elements in computed properties - fixes #1540 --- src/compile/Compiler.ts | 17 ++++++++----- src/compile/dom/index.ts | 6 +++-- src/shared/utils.js | 6 +++++ src/utils/annotateWithScopes.ts | 6 ++++- test/runtime/samples/object-rest/_config.js | 27 +++++++++++++++++++++ test/runtime/samples/object-rest/main.html | 18 ++++++++++++++ 6 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 test/runtime/samples/object-rest/_config.js create mode 100644 test/runtime/samples/object-rest/main.html diff --git a/src/compile/Compiler.ts b/src/compile/Compiler.ts index be5ca6c65195..690b837d7901 100644 --- a/src/compile/Compiler.ts +++ b/src/compile/Compiler.ts @@ -24,7 +24,8 @@ import { Node, GenerateOptions, ShorthandImport, Ast, CompileOptions, CustomElem interface Computation { key: string; - deps: string[] + deps: string[]; + hasRestParam: boolean; } function detectIndentation(str: string) { @@ -436,7 +437,6 @@ export default class Compiler { code, source, computations, - methods, templateProperties, imports } = this; @@ -588,15 +588,20 @@ export default class Compiler { const param = value.params[0]; - if (param.type === 'ObjectPattern') { + const hasRestParam = ( + param.properties && + param.properties.some(prop => prop.type === 'RestElement') + ); + + if (param.type !== 'ObjectPattern' || hasRestParam) { + fullStateComputations.push({ key, deps: null, hasRestParam }); + } else { const deps = param.properties.map(prop => prop.key.name); deps.forEach(dep => { this.expectedProperties.add(dep); }); dependencies.set(key, deps); - } else { - fullStateComputations.push({ key, deps: null }) } }); @@ -611,7 +616,7 @@ export default class Compiler { const deps = dependencies.get(key); deps.forEach(visit); - computations.push({ key, deps }); + computations.push({ key, deps, hasRestParam: false }); const prop = templateProperties.computed.value.properties.find((prop: Node) => getName(prop.key) === key); }; diff --git a/src/compile/dom/index.ts b/src/compile/dom/index.ts index 0a02b664bed1..1eada67e9ee9 100644 --- a/src/compile/dom/index.ts +++ b/src/compile/dom/index.ts @@ -67,7 +67,7 @@ export default function dom( const computationDeps = new Set(); if (computations.length) { - computations.forEach(({ key, deps }) => { + computations.forEach(({ key, deps, hasRestParam }) => { if (target.readonly.has(key)) { // bindings throw new Error( @@ -89,8 +89,10 @@ export default function dom( } else { // computed property depends on entire state object — // these must go at the end + const arg = hasRestParam ? `@exclude(state, "${key}")` : `state`; + computationBuilder.addLine( - `if (this._differs(state.${key}, (state.${key} = %computed-${key}(state)))) changed.${key} = true;` + `if (this._differs(state.${key}, (state.${key} = %computed-${key}(${arg})))) changed.${key} = true;` ); } }); diff --git a/src/shared/utils.js b/src/shared/utils.js index c431a673f822..1394f55a46d0 100644 --- a/src/shared/utils.js +++ b/src/shared/utils.js @@ -25,4 +25,10 @@ export function addLoc(element, file, line, column, char) { element.__svelte_meta = { loc: { file, line, column, char } }; +} + +export function exclude(src, prop) { + const tar = {}; + for (const k in src) k === prop || (tar[k] = src[k]); + return tar; } \ No newline at end of file diff --git a/src/utils/annotateWithScopes.ts b/src/utils/annotateWithScopes.ts index 408de776b253..08ac93387cf3 100644 --- a/src/utils/annotateWithScopes.ts +++ b/src/utils/annotateWithScopes.ts @@ -137,7 +137,11 @@ const extractors = { ObjectPattern(names: string[], param: Node) { param.properties.forEach((prop: Node) => { - extractors[prop.value.type](names, prop.value); + if (prop.type === 'RestElement') { + names.push(prop.argument.name); + } else { + extractors[prop.value.type](names, prop.value); + } }); }, diff --git a/test/runtime/samples/object-rest/_config.js b/test/runtime/samples/object-rest/_config.js new file mode 100644 index 000000000000..7a60f0d5638c --- /dev/null +++ b/test/runtime/samples/object-rest/_config.js @@ -0,0 +1,27 @@ +export default { + skip: +/v(\d+)/.exec(process.version)[1] < 8, + + html: ` +
{"wanted":2}
+ `, + + test(assert, component, target) { + component.set({ + unwanted: 3, + wanted: 4 + }); + + assert.htmlEqual(target.innerHTML, ` +
{"wanted":4}
+ `); + + component.set({ + unwanted: 5, + wanted: 6 + }); + + assert.htmlEqual(target.innerHTML, ` +
{"wanted":6}
+ `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/object-rest/main.html b/test/runtime/samples/object-rest/main.html new file mode 100644 index 000000000000..e66a89291e61 --- /dev/null +++ b/test/runtime/samples/object-rest/main.html @@ -0,0 +1,18 @@ +
{JSON.stringify(props)}
+ \ No newline at end of file