From 9fd6c3d4081f3a42ea5a1f00497391bf886d69d3 Mon Sep 17 00:00:00 2001 From: Rich-Harris <richard.a.harris@gmail.com> Date: Sat, 19 Nov 2016 12:12:56 -0500 Subject: [PATCH] inline expressions --- compiler/generate/index.js | 45 +++++++++++++++++--- test/compiler/inline-expressions/_config.js | 13 ++++++ test/compiler/inline-expressions/main.svelte | 1 + 3 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 test/compiler/inline-expressions/_config.js create mode 100644 test/compiler/inline-expressions/main.svelte diff --git a/compiler/generate/index.js b/compiler/generate/index.js index 1e84d0c400..82658ff902 100644 --- a/compiler/generate/index.js +++ b/compiler/generate/index.js @@ -3,6 +3,7 @@ import { walk } from 'estree-walker'; import deindent from './utils/deindent.js'; import walkHtml from './utils/walkHtml.js'; import flattenReference from './utils/flattenReference.js'; +import isReference from './utils/isReference.js'; import contextualise from './utils/contextualise.js'; import counter from './utils/counter.js'; @@ -53,7 +54,11 @@ export default function generate ( parsed, template ) { } const renderers = []; + const expressionFunctions = []; + const getName = counter(); + + // TODO use getName instead of counters const counters = { if: 0, each: 0 @@ -209,7 +214,6 @@ export default function generate ( parsed, template ) { MustacheTag: { enter ( node ) { const name = current.counter( 'text' ); - const expression = flattenExpression( node.expression, current.contexts ); current.initStatements.push( deindent` var ${name} = document.createTextNode( '' ); @@ -217,12 +221,37 @@ export default function generate ( parsed, template ) { ${current.target}.appendChild( ${name} ); ` ); - current.updateStatements.push( deindent` - if ( ${expression} !== ${name}_value ) { - ${name}_value = ${expression}; - ${name}.data = ${name}_value; - } - ` ); + const usedContexts = contextualise( code, node.expression, current.contexts ); + const snippet = `[✂${node.expression.start}-${node.expression.end}✂]`; + + if ( isReference( node.expression ) ) { + const reference = `${template.slice( node.expression.start, node.expression.end )}`; + const qualified = usedContexts[0] === 'root' ? `root.${reference}` : reference; + + current.updateStatements.push( deindent` + if ( ${snippet} !== ${name}_value ) { + ${name}_value = ${qualified}; + ${name}.data = ${name}_value; + } + ` ); + } else { + const expressionFunction = getName( 'expression' ); + expressionFunctions.push( deindent` + function ${expressionFunction} ( ${usedContexts.join( ', ' )} ) { + return ${snippet}; + } + ` ); + + const temp = getName( 'temp' ); + + current.updateStatements.push( deindent` + var ${temp} = ${expressionFunction}( ${usedContexts.join( ', ' )} ); + if ( ${temp} !== ${name}_value ) { + ${name}_value = ${temp}; + ${name}.data = ${name}_value; + } + ` ); + } } }, @@ -399,6 +428,8 @@ export default function generate ( parsed, template ) { const result = deindent` ${parsed.js ? `[✂${parsed.js.content.start}-${parsed.js.content.end}✂]` : ``} + ${expressionFunctions.join( '\n\n' )} + ${renderers.reverse().join( '\n\n' )} export default function createComponent ( options ) { diff --git a/test/compiler/inline-expressions/_config.js b/test/compiler/inline-expressions/_config.js new file mode 100644 index 0000000000..e6033aa6cf --- /dev/null +++ b/test/compiler/inline-expressions/_config.js @@ -0,0 +1,13 @@ +import * as assert from 'assert'; + +export default { + data: { + a: 1, + b: 2 + }, + html: '<p>1 + 2 = 3</p>', + test ( component, target ) { + component.set({ a: 3, b: 4 }); + assert.equal( target.innerHTML, '<p>3 + 4 = 7</p>' ); + } +}; diff --git a/test/compiler/inline-expressions/main.svelte b/test/compiler/inline-expressions/main.svelte new file mode 100644 index 0000000000..93c55f37e3 --- /dev/null +++ b/test/compiler/inline-expressions/main.svelte @@ -0,0 +1 @@ +<p>{{a}} + {{b}} = {{a + b}}</p>