diff --git a/src/generators/dom/visitors/Component.ts b/src/generators/dom/visitors/Component.ts index 1a06ebadec..5ac1e36ead 100644 --- a/src/generators/dom/visitors/Component.ts +++ b/src/generators/dom/visitors/Component.ts @@ -7,21 +7,10 @@ import getTailSnippet from '../../../utils/getTailSnippet'; import getObject from '../../../utils/getObject'; import getExpressionPrecedence from '../../../utils/getExpressionPrecedence'; import { stringify } from '../../../utils/stringify'; +import stringifyProps from '../../../utils/stringifyProps'; import { Node } from '../../../interfaces'; import { State } from '../interfaces'; -function stringifyProps(props: string[]) { - if (!props.length) return '{}'; - - const joined = props.join(', '); - if (joined.length > 40) { - // make larger data objects readable - return `{\n\t${props.join(',\n\t')}\n}`; - } - - return `{ ${joined} }`; -} - interface Attribute { name: string; value: any; diff --git a/src/generators/dom/visitors/Element/addBindings.ts b/src/generators/dom/visitors/Element/addBindings.ts index af0aabf8bb..13250e56ba 100644 --- a/src/generators/dom/visitors/Element/addBindings.ts +++ b/src/generators/dom/visitors/Element/addBindings.ts @@ -7,6 +7,7 @@ import { Node } from '../../../../interfaces'; import { State } from '../../interfaces'; import getObject from '../../../../utils/getObject'; import getTailSnippet from '../../../../utils/getTailSnippet'; +import stringifyProps from '../../../../utils/stringifyProps'; import visitBinding from './Binding'; import { generateRule } from '../../../../shared/index'; import flatten from '../../../../utils/flattenReference'; @@ -15,20 +16,6 @@ interface Binding { name: string; } -const types: Record void> = { - input: addInputBinding, - textarea: addInputBinding, - select: addSelectBinding, - audio: addMediaBinding, - video: addMediaBinding -}; - const readOnlyMediaAttributes = new Set([ 'duration', 'buffered', @@ -179,10 +166,26 @@ export default function addBindings( const lock = needsLock ? block.getUniqueName(`${node.var}_updating`) : null; if (needsLock) block.addVariable(lock, 'false'); + const usesContext = group.bindings.some(binding => binding.setter.usesContext); + const usesState = group.bindings.some(binding => binding.setter.usesState); + const mutations = group.bindings.map(binding => binding.setter.mutation).filter(Boolean).join('\n'); + + const updates = new Set(); + group.bindings.forEach(binding => { + binding.setter.updates.forEach(update => { + updates.add(update); + }); + }); + + const props = Array.from(updates).join(', '); // TODO use stringifyProps once indenting is fixed + block.builders.init.addBlock(deindent` function ${handler}() { + ${usesContext && `var context = ${node.var}._svelte;`} + ${usesState && `var state = #component.get();`} ${needsLock && `${lock} = true;`} - ${group.bindings.map(binding => binding.setter)} + ${mutations.length > 0 && mutations} + #component.set({ ${props} }); ${needsLock && `${lock} = false;`} } `); @@ -256,24 +259,20 @@ function getSetter( dependencies: string[], value: string, ) { - const tail = attribute.value.type === 'MemberExpression' - ? getTailSnippet(attribute.value) - : ''; - if (block.contexts.has(name)) { - const prop = dependencies[0]; - const computed = isComputed(attribute.value); - - return deindent` - var list = ${node.var}._svelte.${block.listNames.get(name)}; - var index = ${node.var}._svelte.${block.indexNames.get(name)}; - ${computed && `var state = #component.get();`} - list[index]${tail} = ${value}; - - ${computed - ? `#component.set({${dependencies.map((prop: string) => `${prop}: state.${prop}`).join(', ')} });` - : `#component.set({${dependencies.map((prop: string) => `${prop}: #component.get('${prop}')`).join(', ')} });`} - `; + const tail = attribute.value.type === 'MemberExpression' + ? getTailSnippet(attribute.value) + : ''; + + const list = `context.${block.listNames.get(name)}`; + const index = `context.${block.indexNames.get(name)}`; + + return { + usesContext: true, + usesState: true, + mutation: `${list}[${index}]${tail} = ${value};`, + updates: dependencies.map(prop => `${prop}: state.${prop}`) + }; } if (attribute.value.type === 'MemberExpression') { @@ -286,14 +285,20 @@ function getSetter( // that we don't have to do the `.some()` here dependencies = dependencies.filter(prop => !generator.computations.some(computation => computation.key === prop)); - return deindent` - var state = #component.get(); - ${snippet} = ${value}; - #component.set({ ${dependencies.map((prop: string) => `${prop}: state.${prop}`).join(', ')} }); - `; + return { + usesContext: false, + usesState: true, + mutation: `${snippet} = ${value}`, + updates: dependencies.map((prop: string) => `${prop}: state.${prop}`) + }; } - return `#component.set({ ${name}: ${value} });`; + return { + usesContext: false, + usesState: false, + mutation: null, + updates: [`${name}: ${value}`] + }; } function getBindingValue( diff --git a/src/utils/stringifyProps.ts b/src/utils/stringifyProps.ts new file mode 100644 index 0000000000..e9c27d687e --- /dev/null +++ b/src/utils/stringifyProps.ts @@ -0,0 +1,11 @@ +export default function stringifyProps(props: string[]) { + if (!props.length) return '{}'; + + const joined = props.join(', '); + if (joined.length > 40) { + // make larger data objects readable + return `{\n\t${props.join(',\n\t')}\n}`; + } + + return `{ ${joined} }`; +} \ No newline at end of file diff --git a/test/runtime/samples/binding-input-checkbox-indeterminate/_config.js b/test/runtime/samples/binding-input-checkbox-indeterminate/_config.js index 15a2d63002..3d905e5a9e 100644 --- a/test/runtime/samples/binding-input-checkbox-indeterminate/_config.js +++ b/test/runtime/samples/binding-input-checkbox-indeterminate/_config.js @@ -24,7 +24,7 @@ export default { assert.equal(component.get('indeterminate'), false); assert.equal(component.get('checked'), true); - assert.equal(target.innerHTML, ` + assert.htmlEqual(target.innerHTML, `

checked? true

indeterminate? false

@@ -33,7 +33,7 @@ export default { component.set({ indeterminate: true }); assert.equal(input.indeterminate, true); assert.equal(input.checked, true); - assert.equal(target.innerHTML, ` + assert.htmlEqual(target.innerHTML, `

checked? true

indeterminate? true