From b94f63ed704427951c90fd18dddf40a4b9ce0308 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 11 Feb 2018 15:02:25 -0500 Subject: [PATCH] everything working except some destructuring stuff --- src/generators/Generator.ts | 42 +++++----- src/generators/dom/Block.ts | 25 +++++- src/generators/nodes/AwaitBlock.ts | 12 +-- src/generators/nodes/EachBlock.ts | 80 ++++++++----------- .../expected-bundle.js | 10 ++- .../each-block-changed-check/expected.js | 10 ++- 6 files changed, 100 insertions(+), 79 deletions(-) diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts index 5570fe0354..2463c33325 100644 --- a/src/generators/Generator.ts +++ b/src/generators/Generator.ts @@ -242,26 +242,30 @@ export default class Generator { if (name === 'event' && isEventHandler) { // noop } else if (contexts.has(name)) { - // const contextName = contexts.get(name); - // if (contextName !== name) { - // // this is true for 'reserved' names like `state` and `component`, - // // also destructured contexts - // code.overwrite( - // node.start, - // node.start + name.length, - // contextName, - // { storeName: true, contentOnly: false } - // ); - - // const destructuredName = contextName.replace(/\[\d+\]/, ''); - // if (destructuredName !== contextName) { - // // so that hoisting the context works correctly - // usedContexts.add(destructuredName); - // } + // if (self.constructor.name === 'DomGenerator') { // TODO filthy, temporary hack + const contextName = contexts.get(name); + if (contextName !== name) { + // this is true for 'reserved' names like `state` and `component`, + // also destructured contexts + + code.overwrite( + node.start, + node.start + name.length, + contextName, + { storeName: true, contentOnly: false } + ); + + const destructuredName = contextName.replace(/\[\d+\]/, ''); + if (destructuredName !== contextName) { + // so that hoisting the context works correctly + usedContexts.add(destructuredName); + } + } + + // TODO filthy, temporary hack + // if (!isEventHandler) code.prependRight(node.start, `state.`); // } - // TODO filthy, temporary hack - if (self.constructor.name === 'DomGenerator') code.prependRight(node.start, `state.`); usedContexts.add(name); } else if (helpers.has(name)) { let object = node; @@ -270,7 +274,7 @@ export default class Generator { const alias = self.templateVars.get(`helpers-${name}`); if (alias !== name) code.overwrite(object.start, object.end, alias); } else if (indexes.has(name)) { - if (self.constructor.name === 'DomGenerator') code.prependRight(node.start, `state.`); + if (self.constructor.name === 'DomGenerator' && !isEventHandler) code.prependRight(node.start, `state.`); const context = indexes.get(name); usedContexts.add(context); // TODO is this right? diff --git a/src/generators/dom/Block.ts b/src/generators/dom/Block.ts index 15ee602ee2..e1ed62c242 100644 --- a/src/generators/dom/Block.ts +++ b/src/generators/dom/Block.ts @@ -114,7 +114,12 @@ export default class Block { this.aliases = new Map(); this.variables = new Map(); - this.getUniqueName = this.generator.getUniqueNameMaker([]); // TODO this is wrong... we probably don't need this any more + // this.getUniqueName = this.generator.getUniqueNameMaker([]); // TODO this is wrong... we probably don't need this any more + + const getUniqueName = this.generator.getUniqueNameMaker([]); // TODO this is wrong... we probably don't need this any more + this.getUniqueName = name => { + return getUniqueName(name); + } this.hasUpdateMethod = false; // determined later } @@ -189,6 +194,19 @@ export default class Block { this.builders.mount.addLine(`${this.autofocus}.focus();`); } + // TODO `this.contexts` is possibly redundant post-#1122 + const initializers = []; + const updaters = []; + this.contexts.forEach((alias, name) => { + // TODO only the ones that are actually used in this block... + const assignment = `${alias} = state.${name}`; + + initializers.push(assignment); + updaters.push(`${assignment};`); + + this.hasUpdateMethod = true; + }); + // minor hack – we need to ensure that any {{{triples}}} are detached first this.builders.unmount.addBlockAtStart(this.builders.detachRaw.toString()); @@ -248,11 +266,12 @@ export default class Block { } if (this.hasUpdateMethod) { - if (this.builders.update.isEmpty()) { + if (this.builders.update.isEmpty() && updaters.length === 0) { properties.addBlock(`p: @noop,`); } else { properties.addBlock(deindent` p: function update(changed, state) { + ${updaters} ${this.builders.update} }, `); @@ -327,6 +346,8 @@ export default class Block { return deindent` ${this.comment && `// ${escape(this.comment)}`} function ${this.name}(#component${this.key ? `, ${localKey}` : ''}, state) { + ${initializers.length > 0 && + `var ${initializers.join(', ')};`} ${this.variables.size > 0 && `var ${Array.from(this.variables.keys()) .map(key => { diff --git a/src/generators/nodes/AwaitBlock.ts b/src/generators/nodes/AwaitBlock.ts index 5fa04d2c74..168109614f 100644 --- a/src/generators/nodes/AwaitBlock.ts +++ b/src/generators/nodes/AwaitBlock.ts @@ -125,10 +125,12 @@ export default class AwaitBlock extends Node { if (@isPromise(${promise})) { ${promise}.then(function(${value}) { var state = #component.get(); - ${replace_await_block}(${token}, ${create_then_block}, @assign({}, state, { ${this.then.block.context}: ${value} })); + ${resolved} = { ${this.then.block.context}: ${value} }; + ${replace_await_block}(${token}, ${create_then_block}, @assign({}, state, ${resolved})); }, function (${error}) { var state = #component.get(); - ${replace_await_block}(${token}, ${create_catch_block}, @assign({}, state, { ${this.catch.block.context}: ${error} })); + ${resolved} = { ${this.catch.block.context}: ${error} }; + ${replace_await_block}(${token}, ${create_catch_block}, @assign({}, state, ${resolved})); }); // if we previously had a then/catch block, destroy it @@ -137,9 +139,9 @@ export default class AwaitBlock extends Node { return true; } } else { - ${resolved} = ${promise}; + ${resolved} = { ${this.then.block.context}: ${promise} }; if (${await_block_type} !== ${create_then_block}) { - ${replace_await_block}(${token}, ${create_then_block}, @assign({}, state, { ${this.then.block.context}: ${resolved} })); + ${replace_await_block}(${token}, ${create_then_block}, @assign({}, state, ${resolved})); return true; } } @@ -182,7 +184,7 @@ export default class AwaitBlock extends Node { if (${conditions.join(' && ')}) { // nothing } else { - ${await_block}.p(changed, state); + ${await_block}.p(changed, @assign({}, state, ${resolved})); } `); } else { diff --git a/src/generators/nodes/EachBlock.ts b/src/generators/nodes/EachBlock.ts index 7133ce8eac..4d3479d26d 100644 --- a/src/generators/nodes/EachBlock.ts +++ b/src/generators/nodes/EachBlock.ts @@ -34,67 +34,57 @@ export default class EachBlock extends Node { const { dependencies } = this.metadata; block.addDependencies(dependencies); - const indexNames = new Map(block.indexNames); - const indexName = this.index || `${this.context}_index`; - indexNames.set(this.context, indexName); - - const listNames = new Map(block.listNames); - const listName = ( - (this.expression.type === 'MemberExpression' && !this.expression.computed) ? this.expression.property.name : - this.expression.type === 'Identifier' ? this.expression.name : - `each_value` - ); - listNames.set(this.context, listName); - - const contextTypes = new Map(block.contextTypes); - contextTypes.set(this.context, 'each'); - - const context = this.context; - const contexts = new Map(block.contexts); - contexts.set(this.context, context); // TODO this is now redundant - - const indexes = new Map(block.indexes); - if (this.index) indexes.set(this.index, this.context); - - const changeableIndexes = new Map(block.changeableIndexes); - if (this.index) changeableIndexes.set(this.index, this.key); - - if (this.destructuredContexts) { - for (let i = 0; i < this.destructuredContexts.length; i += 1) { - contexts.set(this.destructuredContexts[i], `${context}[${i}]`); - } - } - this.block = block.child({ comment: createDebuggingComment(this, this.generator), name: this.generator.getUniqueName('create_each_block'), context: this.context, key: this.key, - contexts, - contextTypes, - indexes, - changeableIndexes, + contexts: new Map(block.contexts), + contextTypes: new Map(block.contextTypes), + indexes: new Map(block.indexes), + changeableIndexes: new Map(block.changeableIndexes), - listName, - indexName, + listName: ( + (this.expression.type === 'MemberExpression' && !this.expression.computed) ? this.expression.property.name : + this.expression.type === 'Identifier' ? this.expression.name : + `each_value` + ), + indexName: this.index || `${this.context}_index`, - indexNames, - listNames + indexNames: new Map(block.indexNames), + listNames: new Map(block.listNames) }); - this.contextProps = [ - `${context}: ${listName}[#i]`, - `${indexName}: #i` - ]; + this.block.contextTypes.set(this.context, 'each'); + this.block.indexNames.set(this.context, this.block.indexName); + this.block.listNames.set(this.context, this.block.listName); + if (this.index) { + this.block.indexes.set(this.index, this.context); + this.block.changeableIndexes.set(this.index, this.key) + } + + const context = this.block.getUniqueName(this.context); + this.block.contexts.set(this.context, context); // TODO this is now redundant? if (this.destructuredContexts) { for (let i = 0; i < this.destructuredContexts.length; i += 1) { - contexts.set(this.destructuredContexts[i], `${context}[${i}]`); - this.contextProps.push(`${this.destructuredContexts[i]}: ${listName}[#i][${i}]`); + this.block.contexts.set(this.destructuredContexts[i], `${context}[${i}]`); } } + this.contextProps = [ + `${this.context}: ${this.block.listName}[#i]`, + `${this.block.indexName}: #i` + ]; + + // if (this.destructuredContexts) { + // for (let i = 0; i < this.destructuredContexts.length; i += 1) { + // contexts.set(this.destructuredContexts[i], `${context}[${i}]`); + // this.contextProps.push(`${this.destructuredContexts[i]}: ${this.block.listName}[#i][${i}]`); + // } + // } + this.generator.blocks.push(this.block); this.initChildren(this.block, stripWhitespace, nextSibling); block.addDependencies(this.block.dependencies); diff --git a/test/js/samples/each-block-changed-check/expected-bundle.js b/test/js/samples/each-block-changed-check/expected-bundle.js index f90627f266..866f90aa55 100644 --- a/test/js/samples/each-block-changed-check/expected-bundle.js +++ b/test/js/samples/each-block-changed-check/expected-bundle.js @@ -284,7 +284,8 @@ function create_main_fragment(component, state) { // (1:0) {{#each comments as comment, i}} function create_each_block(component, state) { - var div, strong, text, text_1, span, text_2_value = state.comment.author, text_2, text_3, text_4_value = state.elapsed(state.comment.time, state.time), text_4, text_5, text_6, raw_value = state.comment.html, raw_before; + var comment = state.comment; + var div, strong, text, text_1, span, text_2_value = comment.author, text_2, text_3, text_4_value = state.elapsed(comment.time, state.time), text_4, text_5, text_6, raw_value = comment.html, raw_before; return { c: function create() { @@ -323,15 +324,16 @@ function create_each_block(component, state) { }, p: function update(changed, state) { - if ((changed.comments) && text_2_value !== (text_2_value = state.comment.author)) { + comment = state.comment; + if ((changed.comments) && text_2_value !== (text_2_value = comment.author)) { text_2.data = text_2_value; } - if ((changed.elapsed || changed.comments || changed.time) && text_4_value !== (text_4_value = state.elapsed(state.comment.time, state.time))) { + if ((changed.elapsed || changed.comments || changed.time) && text_4_value !== (text_4_value = state.elapsed(comment.time, state.time))) { text_4.data = text_4_value; } - if ((changed.comments) && raw_value !== (raw_value = state.comment.html)) { + if ((changed.comments) && raw_value !== (raw_value = comment.html)) { detachAfter(raw_before); raw_before.insertAdjacentHTML("afterend", raw_value); } diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index 414fcb3f06..6ea50f4ae4 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -84,7 +84,8 @@ function create_main_fragment(component, state) { // (1:0) {{#each comments as comment, i}} function create_each_block(component, state) { - var div, strong, text, text_1, span, text_2_value = state.comment.author, text_2, text_3, text_4_value = state.elapsed(state.comment.time, state.time), text_4, text_5, text_6, raw_value = state.comment.html, raw_before; + var comment = state.comment; + var div, strong, text, text_1, span, text_2_value = comment.author, text_2, text_3, text_4_value = state.elapsed(comment.time, state.time), text_4, text_5, text_6, raw_value = comment.html, raw_before; return { c: function create() { @@ -123,15 +124,16 @@ function create_each_block(component, state) { }, p: function update(changed, state) { - if ((changed.comments) && text_2_value !== (text_2_value = state.comment.author)) { + comment = state.comment; + if ((changed.comments) && text_2_value !== (text_2_value = comment.author)) { text_2.data = text_2_value; } - if ((changed.elapsed || changed.comments || changed.time) && text_4_value !== (text_4_value = state.elapsed(state.comment.time, state.time))) { + if ((changed.elapsed || changed.comments || changed.time) && text_4_value !== (text_4_value = state.elapsed(comment.time, state.time))) { text_4.data = text_4_value; } - if ((changed.comments) && raw_value !== (raw_value = state.comment.html)) { + if ((changed.comments) && raw_value !== (raw_value = comment.html)) { detachAfter(raw_before); raw_before.insertAdjacentHTML("afterend", raw_value); }