diff --git a/src/generators/dom/visitors/Component/Component.ts b/src/generators/dom/visitors/Component/Component.ts index 506384c5d6..1be67726ae 100644 --- a/src/generators/dom/visitors/Component/Component.ts +++ b/src/generators/dom/visitors/Component/Component.ts @@ -153,74 +153,9 @@ export default function visitComponent( const statements: string[] = []; let name_updating: string; let name_initial_data: string; + let _beforecreate: string = null; let bindings = []; - if (local.bindings.length) { - name_updating = block.alias(`${name}_updating`); - name_initial_data = block.getUniqueName(`${name}_initial_data`); - - block.addVariable(name_updating, '{}'); - - bindings = local.bindings.map(binding => { - let setParentFromChild; - - const { name: key } = getObject(binding.value); - - if (block.contexts.has(key)) { - const prop = binding.dependencies[0]; - const computed = isComputed(binding.value); - const tail = binding.value.type === 'MemberExpression' ? getTailSnippet(binding.value) : ''; - - setParentFromChild = deindent` - var list = ${name}._context.${block.listNames.get(key)}; - var index = ${name}._context.${block.indexNames.get(key)}; - list[index]${tail} = childState.${binding.name}; - - ${binding.dependencies - .map((prop: string) => `newState.${prop} = state.${prop};`) - .join('\n')} - `; - } - - else if (binding.value.type === 'MemberExpression') { - setParentFromChild = deindent` - ${binding.snippet} = childState.${binding.name}; - ${binding.dependencies.map((prop: string) => `newState.${prop} = state.${prop};`).join('\n')} - `; - } - - else { - setParentFromChild = `newState.${binding.value.name} = childState.${binding.name};`; - } - - return { - init: deindent` - if ( ${binding.prop} in ${binding.obj} ) { - ${name_initial_data}.${binding.name} = ${binding.snippet}; - ${name_updating}.${binding.name} = true; - }`, - bind: deindent` - if (!${name_updating}.${binding.name} && changed.${binding.name}) { - ${setParentFromChild} - } - `, - setParentFromChild: deindent` - if (!${name_updating}.${binding.name}) { - ${setParentFromChild} - } - `, - - // TODO could binding.dependencies.length ever be 0? - update: binding.dependencies.length && deindent` - if ( !${name_updating}.${binding.name} && ${binding.dependencies.map((dependency: string) => `changed.${dependency}`).join(' || ')} ) { - ${name}_changes.${binding.name} = ${binding.snippet}; - ${name_updating}.${binding.name} = true; - } - ` - } - }); - } - if ( local.staticAttributes.length || local.dynamicAttributes.length || @@ -232,9 +167,90 @@ export default function visitComponent( const initialPropString = stringifyProps(initialProps); + const updates: string[] = []; + + local.dynamicAttributes.forEach(attribute => { + if (attribute.dependencies.length) { + updates.push(deindent` + if ( ${attribute.dependencies + .map(dependency => `changed.${dependency}`) + .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};`); + } + }); + if (local.bindings.length) { + name_updating = block.alias(`${name}_updating`); + name_initial_data = block.getUniqueName(`${name}_initial_data`); + + block.addVariable(name_updating, '{}'); statements.push(`var ${name_initial_data} = ${initialPropString};`); + bindings = local.bindings.map(binding => { + let setParentFromChild; + + const { name: key } = getObject(binding.value); + + if (block.contexts.has(key)) { + const prop = binding.dependencies[0]; + const computed = isComputed(binding.value); + const tail = binding.value.type === 'MemberExpression' ? getTailSnippet(binding.value) : ''; + + setParentFromChild = deindent` + var list = ${name}._context.${block.listNames.get(key)}; + var index = ${name}._context.${block.indexNames.get(key)}; + list[index]${tail} = childState.${binding.name}; + + ${binding.dependencies + .map((prop: string) => `newState.${prop} = state.${prop};`) + .join('\n')} + `; + } + + else if (binding.value.type === 'MemberExpression') { + setParentFromChild = deindent` + ${binding.snippet} = childState.${binding.name}; + ${binding.dependencies.map((prop: string) => `newState.${prop} = state.${prop};`).join('\n')} + `; + } + + else { + setParentFromChild = `newState.${binding.value.name} = childState.${binding.name};`; + } + + return { + init: deindent` + if ( ${binding.prop} in ${binding.obj} ) { + ${name_initial_data}.${binding.name} = ${binding.snippet}; + ${name_updating}.${binding.name} = true; + }`, + bind: deindent` + if (!${name_updating}.${binding.name} && changed.${binding.name}) { + ${setParentFromChild} + } + `, + setParentFromChild: deindent` + if (!${name_updating}.${binding.name}) { + ${setParentFromChild} + } + `, + + // TODO could binding.dependencies.length ever be 0? + update: binding.dependencies.length && deindent` + if ( !${name_updating}.${binding.name} && ${binding.dependencies.map((dependency: string) => `changed.${dependency}`).join(' || ')} ) { + ${name}_changes.${binding.name} = ${binding.snippet}; + ${name_updating}.${binding.name} = true; + } + ` + } + }); + bindings.forEach(binding => { statements.push(binding.init); }); @@ -250,9 +266,31 @@ export default function visitComponent( ${name_updating} = {}; } `); + + bindings.forEach(binding => { + if (binding.update) updates.push(binding.update); + }); + + _beforecreate = deindent` + #component._root._beforecreate.push(function () { + var state = #component.get(), childState = ${name}.get(), newState = {}; + if (!childState) return; + ${bindings.map(binding => binding.setParentFromChild).join('\n')} + ${name_updating} = { ${local.bindings.map(binding => `${binding.name}: true`).join(', ')} }; + #component._set(newState); + ${name_updating} = {}; + }); + `; } else if (initialProps.length) { componentInitProperties.push(`data: ${initialPropString}`); } + + local.update.addBlock(deindent` + var ${name}_changes = {}; + ${updates.join('\n')} + ${name}._set( ${name}_changes ); + ${bindings.length && `${name_updating} = {};`} + `); } const expression = node.name === ':Self' @@ -265,51 +303,9 @@ export default function visitComponent( var ${name} = new ${expression}({ ${componentInitProperties.join(',\n')} }); - `); - - if (bindings.length) { - local.create.addBlock(deindent` - #component._root._beforecreate.push(function () { - var state = #component.get(), childState = ${name}.get(), newState = {}; - if (!childState) return; - ${bindings.map(binding => binding.setParentFromChild).join('\n')} - ${name_updating} = { ${local.bindings.map(binding => `${binding.name}: true`).join(', ')} }; - #component._set(newState); - ${name_updating} = {}; - }); - `); - } - - if (local.dynamicAttributes.length || local.bindings.length) { - const updates: string[] = []; - - local.dynamicAttributes.forEach(attribute => { - if (attribute.dependencies.length) { - updates.push(deindent` - if ( ${attribute.dependencies - .map(dependency => `changed.${dependency}`) - .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};`); - } - }); - - bindings.forEach(binding => { - if (binding.update) updates.push(binding.update); - }); - local.update.addBlock(deindent` - var ${name}_changes = {}; - ${updates.join('\n')} - ${name}._set( ${name}_changes ); - ${bindings.length && `${name_updating} = {};`} - `); - } + ${_beforecreate} + `); if (isTopLevel) block.builders.unmount.addLine(`${name}._fragment.unmount();`);