From 6e41ebe91b33e55235579326e47d8b0f94865b93 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sat, 31 Mar 2018 13:56:41 -0400 Subject: [PATCH] component spread --- src/generators/nodes/Component.ts | 69 +++++++++++++++---- test/js/samples/action/expected-bundle.js | 2 +- test/js/samples/action/expected.js | 2 +- .../expected-bundle.js | 3 +- .../component-static-immutable/expected.js | 3 +- .../expected-bundle.js | 3 +- .../component-static-immutable2/expected.js | 3 +- .../component-static/expected-bundle.js | 3 +- test/js/samples/component-static/expected.js | 3 +- .../css-shadow-dom-keyframes/expected.js | 2 +- .../samples/deconflict-builtins/expected.js | 2 +- .../each-block-changed-check/expected.js | 2 +- .../samples/event-handlers-custom/expected.js | 2 +- test/js/samples/setup-method/expected.js | 2 +- .../samples/ssr-preserve-comments/expected.js | 2 +- 15 files changed, 77 insertions(+), 26 deletions(-) diff --git a/src/generators/nodes/Component.ts b/src/generators/nodes/Component.ts index e6f26c30e4..a8c013b258 100644 --- a/src/generators/nodes/Component.ts +++ b/src/generators/nodes/Component.ts @@ -83,6 +83,7 @@ export default class Component extends Node { const statements: string[] = []; const name_initial_data = block.getUniqueName(`${name}_initial_data`); + const name_changes = block.getUniqueName(`${name}_changes`); let name_updating: string; let beforecreate: string = null; @@ -103,17 +104,62 @@ export default class Component extends Node { const updates: string[] = []; - const attributeObject = stringifyProps( - attributes.map((attribute: Attribute) => `${attribute.name}: ${attribute.value}`) - ); + const usesSpread = !!attributes.find(a => a.spread); + + const attributeObject = usesSpread + ? '{}' + : stringifyProps( + attributes.map((attribute: Attribute) => `${attribute.name}: ${attribute.value}`) + ); if (attributes.length || bindings.length) { componentInitProperties.push(`data: ${name_initial_data}`); } + if ((!usesSpread && attributes.filter(a => a.dynamic).length) || bindings.length) { + updates.push(`var ${name_changes} = {};`); + } + if (attributes.length) { - if (attributes.find(a => a.type === 'Spread')) { - // TODO + if (usesSpread) { + const levels = block.getUniqueName(`${this.var}_spread_levels`); + + const initialProps = []; + const changes = []; + + attributes + .forEach(munged => { + const { spread, name, dynamic, value, dependencies } = munged; + + if (spread) { + initialProps.push(value); + + const condition = dependencies && dependencies.map(d => `changed.${d}`).join(' || '); + changes.push(condition ? `${condition} && ${value}` : value); + } else { + const obj = `{ ${quoteIfNecessary(name, this.generator.legacy)}: ${value} }`; + initialProps.push(obj); + + const condition = dependencies && dependencies.map(d => `changed.${d}`).join(' || '); + changes.push(condition ? `${condition} && ${obj}` : obj); + } + }); + + statements.push(deindent` + var ${levels} = [ + ${initialProps.join(',\n')} + ]; + + for (var #i = 0; #i < ${levels}.length; #i += 1) { + ${name_initial_data} = @assign(${name_initial_data}, ${levels}[#i]); + } + `); + + updates.push(deindent` + var ${name_changes} = @getSpreadUpdate(${levels}, [ + ${changes.join(',\n')} + ]); + `); } else { attributes .filter((attribute: Attribute) => attribute.dynamic) @@ -122,14 +168,14 @@ export default class Component extends Node { updates.push(deindent` if (${attribute.dependencies .map(dependency => `changed.${dependency}`) - .join(' || ')}) ${name}_changes.${attribute.name} = ${attribute.value}; + .join(' || ')}) ${name_changes}.${attribute.name} = ${attribute.value}; `); } else { // TODO this is an odd situation to encounter – I *think* it should only happen with // each block indices, in which case it may be possible to optimise this - updates.push(`${name}_changes.${attribute.name} = ${attribute.value};`); + updates.push(`${name_changes}.${attribute.name} = ${attribute.value};`); } }); } @@ -213,7 +259,7 @@ export default class Component extends Node { updates.push(deindent` if (!${name_updating}.${binding.name} && ${binding.dependencies.map((dependency: string) => `changed.${dependency}`).join(' || ')}) { - ${name}_changes.${binding.name} = ${binding.snippet}; + ${name_changes}.${binding.name} = ${binding.snippet}; ${name_updating}.${binding.name} = true; } `); @@ -327,9 +373,8 @@ export default class Component extends Node { if (updates.length) { block.builders.update.addBlock(deindent` else { - var ${name}_changes = {}; ${updates} - ${name}._set(${name}_changes); + ${name}._set(${name_changes}); ${bindings.length && `${name_updating} = {};`} } `); @@ -376,9 +421,9 @@ export default class Component extends Node { if (updates.length) { block.builders.update.addBlock(deindent` - var ${name}_changes = {}; + var ${name_changes} = {}; ${updates} - ${name}._set(${name}_changes); + ${name}._set(${name_changes}); ${bindings.length && `${name_updating} = {};`} `); } diff --git a/test/js/samples/action/expected-bundle.js b/test/js/samples/action/expected-bundle.js index 96ad1ebe7d..68fdff503d 100644 --- a/test/js/samples/action/expected-bundle.js +++ b/test/js/samples/action/expected-bundle.js @@ -176,7 +176,7 @@ var proto = { /* generated by Svelte vX.Y.Z */ function link(node) { - + function onClick(event) { event.preventDefault(); history.pushState(null, null, event.target.href); diff --git a/test/js/samples/action/expected.js b/test/js/samples/action/expected.js index 6e1b5ef600..5562b84529 100644 --- a/test/js/samples/action/expected.js +++ b/test/js/samples/action/expected.js @@ -2,7 +2,7 @@ import { assign, createElement, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; function link(node) { - + function onClick(event) { event.preventDefault(); history.pushState(null, null, event.target.href); diff --git a/test/js/samples/component-static-immutable/expected-bundle.js b/test/js/samples/component-static-immutable/expected-bundle.js index 48fbb1e836..572dd75439 100644 --- a/test/js/samples/component-static-immutable/expected-bundle.js +++ b/test/js/samples/component-static-immutable/expected-bundle.js @@ -171,9 +171,10 @@ var Nested = window.Nested; function create_main_fragment(component, state) { + var nested_initial_data = { foo: "bar" }; var nested = new Nested({ root: component.root, - data: { foo: "bar" } + data: nested_initial_data }); return { diff --git a/test/js/samples/component-static-immutable/expected.js b/test/js/samples/component-static-immutable/expected.js index 5a60d641c2..ee5a447d64 100644 --- a/test/js/samples/component-static-immutable/expected.js +++ b/test/js/samples/component-static-immutable/expected.js @@ -5,9 +5,10 @@ var Nested = window.Nested; function create_main_fragment(component, state) { + var nested_initial_data = { foo: "bar" }; var nested = new Nested({ root: component.root, - data: { foo: "bar" } + data: nested_initial_data }); return { diff --git a/test/js/samples/component-static-immutable2/expected-bundle.js b/test/js/samples/component-static-immutable2/expected-bundle.js index 48fbb1e836..572dd75439 100644 --- a/test/js/samples/component-static-immutable2/expected-bundle.js +++ b/test/js/samples/component-static-immutable2/expected-bundle.js @@ -171,9 +171,10 @@ var Nested = window.Nested; function create_main_fragment(component, state) { + var nested_initial_data = { foo: "bar" }; var nested = new Nested({ root: component.root, - data: { foo: "bar" } + data: nested_initial_data }); return { diff --git a/test/js/samples/component-static-immutable2/expected.js b/test/js/samples/component-static-immutable2/expected.js index 5a60d641c2..ee5a447d64 100644 --- a/test/js/samples/component-static-immutable2/expected.js +++ b/test/js/samples/component-static-immutable2/expected.js @@ -5,9 +5,10 @@ var Nested = window.Nested; function create_main_fragment(component, state) { + var nested_initial_data = { foo: "bar" }; var nested = new Nested({ root: component.root, - data: { foo: "bar" } + data: nested_initial_data }); return { diff --git a/test/js/samples/component-static/expected-bundle.js b/test/js/samples/component-static/expected-bundle.js index 027cd3be45..9895844ac6 100644 --- a/test/js/samples/component-static/expected-bundle.js +++ b/test/js/samples/component-static/expected-bundle.js @@ -167,9 +167,10 @@ var Nested = window.Nested; function create_main_fragment(component, state) { + var nested_initial_data = { foo: "bar" }; var nested = new Nested({ root: component.root, - data: { foo: "bar" } + data: nested_initial_data }); return { diff --git a/test/js/samples/component-static/expected.js b/test/js/samples/component-static/expected.js index 2207d7a8e3..93584db49e 100644 --- a/test/js/samples/component-static/expected.js +++ b/test/js/samples/component-static/expected.js @@ -5,9 +5,10 @@ var Nested = window.Nested; function create_main_fragment(component, state) { + var nested_initial_data = { foo: "bar" }; var nested = new Nested({ root: component.root, - data: { foo: "bar" } + data: nested_initial_data }); return { diff --git a/test/js/samples/css-shadow-dom-keyframes/expected.js b/test/js/samples/css-shadow-dom-keyframes/expected.js index 680231c77d..eeac231db1 100644 --- a/test/js/samples/css-shadow-dom-keyframes/expected.js +++ b/test/js/samples/css-shadow-dom-keyframes/expected.js @@ -61,4 +61,4 @@ assign(assign(SvelteComponent.prototype, proto), { this.parentNode.removeChild(this); } }); -export default SvelteComponent; +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/deconflict-builtins/expected.js b/test/js/samples/deconflict-builtins/expected.js index 314708544b..e81e05fd32 100644 --- a/test/js/samples/deconflict-builtins/expected.js +++ b/test/js/samples/deconflict-builtins/expected.js @@ -121,4 +121,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); -export default SvelteComponent; +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index 407fcf81ea..cefd0a1338 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -166,4 +166,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); -export default SvelteComponent; +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/event-handlers-custom/expected.js b/test/js/samples/event-handlers-custom/expected.js index ee1d155e9d..e800fb1d0e 100644 --- a/test/js/samples/event-handlers-custom/expected.js +++ b/test/js/samples/event-handlers-custom/expected.js @@ -57,4 +57,4 @@ function SvelteComponent(options) { } assign(assign(SvelteComponent.prototype, methods), proto); -export default SvelteComponent; +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/setup-method/expected.js b/test/js/samples/setup-method/expected.js index 256d1710b4..feee1679e5 100644 --- a/test/js/samples/setup-method/expected.js +++ b/test/js/samples/setup-method/expected.js @@ -47,4 +47,4 @@ function SvelteComponent(options) { assign(assign(SvelteComponent.prototype, methods), proto); setup(SvelteComponent); -export default SvelteComponent; +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/ssr-preserve-comments/expected.js b/test/js/samples/ssr-preserve-comments/expected.js index eff9344154..3497a72832 100644 --- a/test/js/samples/ssr-preserve-comments/expected.js +++ b/test/js/samples/ssr-preserve-comments/expected.js @@ -59,4 +59,4 @@ SvelteComponent.renderCss = function() { }; }; -module.exports = SvelteComponent; +module.exports = SvelteComponent; \ No newline at end of file