diff --git a/src/compile/Compiler.ts b/src/compile/Compiler.ts index da5207de3996..ac584816b1e9 100644 --- a/src/compile/Compiler.ts +++ b/src/compile/Compiler.ts @@ -564,16 +564,29 @@ export default class Compiler { if (templateProperties.computed) { const dependencies = new Map(); + const fullStateComputations = []; + templateProperties.computed.value.properties.forEach((prop: Node) => { const key = getName(prop.key); const value = prop.value; - const deps = value.params[0].properties.map(prop => prop.key.name); - - deps.forEach(dep => { - this.expectedProperties.add(dep); + addDeclaration(key, value, false, 'computed', { + state: true, + changed: true }); - dependencies.set(key, deps); + + const param = value.params[0]; + + if (param.type === 'ObjectPattern') { + 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 }) + } }); const visited = new Set(); @@ -590,16 +603,15 @@ export default class Compiler { computations.push({ key, deps }); const prop = templateProperties.computed.value.properties.find((prop: Node) => getName(prop.key) === key); - - addDeclaration(key, prop.value, false, 'computed', { - state: true, - changed: true - }); }; templateProperties.computed.value.properties.forEach((prop: Node) => visit(getName(prop.key)) ); + + if (fullStateComputations.length > 0) { + computations.push(...fullStateComputations); + } } if (templateProperties.data) { diff --git a/src/compile/dom/index.ts b/src/compile/dom/index.ts index 3db1158449d7..db9b7061d612 100644 --- a/src/compile/dom/index.ts +++ b/src/compile/dom/index.ts @@ -64,10 +64,6 @@ export default function dom( if (computations.length) { computations.forEach(({ key, deps }) => { - deps.forEach(dep => { - computationDeps.add(dep); - }); - if (target.readonly.has(key)) { // bindings throw new Error( @@ -77,11 +73,22 @@ export default function dom( target.readonly.add(key); - const condition = `${deps.map(dep => `changed.${dep}`).join(' || ')}`; + if (deps) { + deps.forEach(dep => { + computationDeps.add(dep); + }); - const statement = `if (this._differs(state.${key}, (state.${key} = %computed-${key}(state)))) changed.${key} = true;`; + const condition = `${deps.map(dep => `changed.${dep}`).join(' || ')}`; + const statement = `if (this._differs(state.${key}, (state.${key} = %computed-${key}(state)))) changed.${key} = true;`; - computationBuilder.addConditional(condition, statement); + computationBuilder.addConditional(condition, statement); + } else { + // computed property depends on entire state object — + // these must go at the end + computationBuilder.addLine( + `if (this._differs(state.${key}, (state.${key} = %computed-${key}(state)))) changed.${key} = true;` + ); + } }); } diff --git a/src/compile/ssr/index.ts b/src/compile/ssr/index.ts index 5f5a410a9440..8fccc9b4f272 100644 --- a/src/compile/ssr/index.ts +++ b/src/compile/ssr/index.ts @@ -120,8 +120,7 @@ export default function ssr( ctx = Object.assign(${initialState.join(', ')}); ${computations.map( - ({ key, deps }) => - `ctx.${key} = %computed-${key}(ctx);` + ({ key }) => `ctx.${key} = %computed-${key}(ctx);` )} ${target.bindings.length && diff --git a/src/validate/js/propValidators/computed.ts b/src/validate/js/propValidators/computed.ts index d918fe3e8b22..d86f1d26501f 100644 --- a/src/validate/js/propValidators/computed.ts +++ b/src/validate/js/propValidators/computed.ts @@ -81,14 +81,5 @@ export default function computed(validator: Validator, prop: Node) { message: `Computed properties must take a single argument` }); } - - const param = params[0]; - if (param.type !== 'ObjectPattern') { - // TODO post-v2, allow the entire object to be passed in - validator.error(computation.value, { - code: `invalid-computed-argument`, - message: `Computed property argument must be a destructured object pattern` - }); - } }); } diff --git a/test/runtime/samples/computed-state-object/_config.js b/test/runtime/samples/computed-state-object/_config.js new file mode 100644 index 000000000000..d9fc4d82bafe --- /dev/null +++ b/test/runtime/samples/computed-state-object/_config.js @@ -0,0 +1,21 @@ +export default { + data: { a: 1 }, + + html: ` +

a: 1

+

x: 2

+

y: 4

+

z: 8

+ `, + + test(assert, component, target) { + component.set({ a: 2 }); + + assert.htmlEqual(target.innerHTML, ` +

a: 2

+

x: 4

+

y: 8

+

z: 16

+ `) + }, +}; diff --git a/test/runtime/samples/computed-state-object/main.html b/test/runtime/samples/computed-state-object/main.html new file mode 100644 index 000000000000..c8c313c8fb95 --- /dev/null +++ b/test/runtime/samples/computed-state-object/main.html @@ -0,0 +1,14 @@ +

a: {a}

+

x: {x}

+

y: {y}

+

z: {z}

+ +