From be559b1119aedad6e943d211a3cc3831059b5eff Mon Sep 17 00:00:00 2001 From: Scott J Miles Date: Mon, 18 May 2015 13:23:41 -0700 Subject: [PATCH 01/14] rename `effect.arg` to `effect.trigger` to avoid confusion with `effect.args` --- src/lib/bind/effects.html | 2 +- src/standard/effects.html | 10 +++++----- src/standard/notify-path.html | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/bind/effects.html b/src/lib/bind/effects.html index 4b2a494dcf..46fde85639 100644 --- a/src/lib/bind/effects.html +++ b/src/lib/bind/effects.html @@ -95,7 +95,7 @@ // Only send the actual path changed info if the change that // caused the observer to run matched the wildcard var baseChanged = (name.indexOf(path + '.') === 0); - var matches = (effect.arg.name.indexOf(name) === 0 && !baseChanged); + var matches = (effect.trigger.name.indexOf(name) === 0 && !baseChanged); values[i] = { path: matches ? path : name, value: matches ? value : v, diff --git a/src/standard/effects.html b/src/standard/effects.html index 5061ea8b7e..7b3c7fd9aa 100644 --- a/src/standard/effects.html +++ b/src/standard/effects.html @@ -21,8 +21,8 @@ * property | ann | anCmp | cmp | obs | cplxOb | description * ---------|-----|-------|-----|-----|--------|---------------------------------------- * method | | X | X | X | X | function name to call on instance - * args | | X | X | | X | list of all arg descriptors for fn - * arg | | X | X | | X | arg descriptor for effect + * args | | X | X | | X | arg descriptors for triggers of fn + * trigger | | X | X | | X | describes triggering dependency (one of args) * property | | | X | X | | property for effect to set or get * name | X | | | | | annotation value (text inside {{...}}) * kind | X | X | | | | binding type (property or attribute) @@ -102,7 +102,7 @@ this._addPropertyEffect(arg.model, 'compute', { method: sig.method, args: sig.args, - arg: arg, + trigger: arg, property: name }); }, this); @@ -129,7 +129,7 @@ this._addPropertyEffect(arg.model, 'complexObserver', { method: sig.method, args: sig.args, - arg: arg + trigger: arg }); }, this); }, @@ -171,7 +171,7 @@ kind: note.kind, method: sig.method, args: sig.args, - arg: arg, + trigger: arg, property: note.name, index: index, negate: note.negate diff --git a/src/standard/notify-path.html b/src/standard/notify-path.html index 1c4cce67b6..72082f3558 100644 --- a/src/standard/notify-path.html +++ b/src/standard/notify-path.html @@ -212,10 +212,10 @@ }, _pathMatchesEffect: function(path, effect) { - var effectArg = effect.arg.name; + var effectArg = effect.trigger.name; return (effectArg == path) || (effectArg.indexOf(path + '.') === 0) || - (effect.arg.wildcard && path.indexOf(effectArg) === 0); + (effect.trigger.wildcard && path.indexOf(effectArg) === 0); }, linkPaths: function(to, from) { From db2741174534222c25d4e8418edd3f502b471c5b Mon Sep 17 00:00:00 2001 From: Scott J Miles Date: Mon, 18 May 2015 16:45:08 -0700 Subject: [PATCH 02/14] support literal args in `_marshalArgs` --- src/lib/bind/effects.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lib/bind/effects.html b/src/lib/bind/effects.html index 46fde85639..c1ca8661da 100644 --- a/src/lib/bind/effects.html +++ b/src/lib/bind/effects.html @@ -86,8 +86,13 @@ for (var i=0, l=args.length; i 1 && v === undefined) { return; } From 69c472fe9a18f4ab7a84d5c4fabab45c1bc38a62 Mon Sep 17 00:00:00 2001 From: Scott J Miles Date: Mon, 18 May 2015 16:48:42 -0700 Subject: [PATCH 03/14] require method expressions to use `,` as argument delimeter, trim white space from arguments, support literal arguments described as JSON --- src/standard/effects.html | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/standard/effects.html b/src/standard/effects.html index 7b3c7fd9aa..b6009209d1 100644 --- a/src/standard/effects.html +++ b/src/standard/effects.html @@ -71,27 +71,53 @@ } }, + // method expressions are of the form: `name([arg1, arg2, .... argn])` _parseMethod: function(expression) { var m = expression.match(/(\w*)\((.*)\)/); if (m) { return { method: m[1], - args: m[2].split(/[^\w.*]+/).map(this._parseArg, this) + args: m[2].split(',').map(this._parseArg, this) }; } }, - _parseArg: function(arg) { + _parseArg: function(rawArg) { + // clean up string + var arg = String(rawArg).trim(); + // basic argument descriptor var a = { name: arg, model: this._modelForPath(arg) }; + // detect structured path (has dots) a.structured = arg.indexOf('.') > 0; if (a.structured) { a.wildcard = (arg.slice(-2) == '.*'); if (a.wildcard) { a.name = arg.slice(0, -2); } + } else { + // detect literal value (must be JSON) + var fc = arg[0]; + if (fc >= '0' && fc <= '9') { + fc = '#'; + } + switch(fc) { + // TODO(sjmiles): single-quote is invalid JSON + //case "'": + case '"': + case '{': + case '[': + case '#': + try { + a.value = JSON.parse(arg); + a.literal = true; + } catch(x) { + // warn? + } + break; + } } return a; }, From 3fd8fbb973d5c82e3dfe7615ca127de81fa92f6f Mon Sep 17 00:00:00 2001 From: Scott J Miles Date: Mon, 18 May 2015 16:49:29 -0700 Subject: [PATCH 04/14] basic test for computed expression containing literal args (must also contain at least one push dependency at this time) --- test/unit/bind-elements.html | 11 +++++++++-- test/unit/bind.html | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/test/unit/bind-elements.html b/test/unit/bind-elements.html index 4b8d4f7ddf..1a49716ce9 100644 --- a/test/unit/bind-elements.html +++ b/test/unit/bind-elements.html @@ -13,7 +13,9 @@ style$="{{boundStyle}}" data-id$="{{dataSetId}}" custom-event-value="{{customEventValue::custom}}" - custom-event-object-value="{{customEventObject.value::change}}"> + custom-event-object-value="{{customEventObject.value::change}}" + computed-from-mixed-literals='{{computeFromLiterals(3, "foo", bool)}}' + > Test {{text}} @@ -82,7 +84,7 @@ } }, observers: [ - 'multipleDepChangeHandler(dep1 dep2 dep3)', + 'multipleDepChangeHandler(dep1, dep2, dep3)', 'customEventObjectValueChanged(customEventObject.value)' ], created: function() { @@ -184,6 +186,11 @@ assert.equal(arguments.length, 1, 'observer argument length wrong'); assert.equal(val, this.customEventObject.value, 'observer value argument wrong'); // note, no `old` argument for path observers + }, + computeFromLiterals: function(num, str) { + assert.equal(num, 3); + assert.equal(str, 'foo'); + return num + str; } }); diff --git a/test/unit/bind.html b/test/unit/bind.html index f221931e82..c541ae5cce 100644 --- a/test/unit/bind.html +++ b/test/unit/bind.html @@ -138,6 +138,11 @@ assert.equal(el.observerCounts.computedFromMultipleValuesChanged, 1, 'observer not called'); }); + test('computed annotation with literals', function() { + el.bool = true; + assert.equal(el.$.boundChild.computedFromMixedLiterals, '3foo', 'Wrong result from literal arg computation'); + }); + test('no read-only observer called with assignment', function() { el.readolyvalue = 46; assert.equal(el.observerCounts.readonlyvalueChanged, 0, 'observer should not be called for readOnly prop assignment'); From 89650a1f748e804e8e90ec0bbdbdbb7d0f7fd28e Mon Sep 17 00:00:00 2001 From: Scott J Miles Date: Mon, 18 May 2015 16:52:45 -0700 Subject: [PATCH 05/14] rename `standard/effects.html` to `standard/effectBuilder.html` --- polymer.html | 2 +- src/standard/{effects.html => effectBuilder.html} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/standard/{effects.html => effectBuilder.html} (100%) diff --git a/polymer.html b/polymer.html index bc5517c396..3e7d6a61b1 100644 --- a/polymer.html +++ b/polymer.html @@ -14,7 +14,7 @@ - + diff --git a/src/standard/effects.html b/src/standard/effectBuilder.html similarity index 100% rename from src/standard/effects.html rename to src/standard/effectBuilder.html From ab6ce1e19987f777d825a220cc4c34e574fac134 Mon Sep 17 00:00:00 2001 From: Scott J Miles Date: Mon, 18 May 2015 17:58:25 -0700 Subject: [PATCH 06/14] * do not treat literal arguments as effect triggers * detect when an annotated computation has only literal arguments, flag it a `static` effect * when adding a static effect, add it only to the effect list for the __static__ pseudo-property * expose _executeStaticEffects method to process static effects on demand --- src/standard/effectBuilder.html | 507 +++++++++++++++++--------------- 1 file changed, 267 insertions(+), 240 deletions(-) diff --git a/src/standard/effectBuilder.html b/src/standard/effectBuilder.html index b6009209d1..8afcfa2694 100644 --- a/src/standard/effectBuilder.html +++ b/src/standard/effectBuilder.html @@ -1,240 +1,267 @@ - - - - - - + + + + + + From 6fd5ef8cddce7a294cdecc738b627973f5c21efc Mon Sep 17 00:00:00 2001 From: Scott J Miles Date: Mon, 18 May 2015 17:58:50 -0700 Subject: [PATCH 07/14] `_executeStaticEffects` at configure-time --- src/standard/configure.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/standard/configure.html b/src/standard/configure.html index 78020b7431..d2c114eb02 100644 --- a/src/standard/configure.html +++ b/src/standard/configure.html @@ -67,7 +67,10 @@ // configure: returns user supplied default property values // combines with _config to create final property values _configure: function() { + // TODO(sjmiles): does what? this._configureAnnotationReferences(); + // process static effects, e.g. computations that have only literal arguments + this._executeStaticEffects(); // get individual default values from property configs var config = {}; // mixed-in behaviors From 0fe9fe759fe72664b452a9170a2c38f472a59807 Mon Sep 17 00:00:00 2001 From: Scott J Miles Date: Mon, 18 May 2015 17:59:26 -0700 Subject: [PATCH 08/14] rudimentary test for a static effect (annotated computation with only literal arguments) --- test/unit/bind-elements.html | 1 + test/unit/bind.html | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit/bind-elements.html b/test/unit/bind-elements.html index 1a49716ce9..342c4950a8 100644 --- a/test/unit/bind-elements.html +++ b/test/unit/bind-elements.html @@ -15,6 +15,7 @@ custom-event-value="{{customEventValue::custom}}" custom-event-object-value="{{customEventObject.value::change}}" computed-from-mixed-literals='{{computeFromLiterals(3, "foo", bool)}}' + computed-from-pure-literals='{{computeFromLiterals(3, "foo")}}' > Test diff --git a/test/unit/bind.html b/test/unit/bind.html index c541ae5cce..207832b9e8 100644 --- a/test/unit/bind.html +++ b/test/unit/bind.html @@ -140,7 +140,8 @@ test('computed annotation with literals', function() { el.bool = true; - assert.equal(el.$.boundChild.computedFromMixedLiterals, '3foo', 'Wrong result from literal arg computation'); + assert.equal(el.$.boundChild.computedFromMixedLiterals, '3foo', 'Wrong result from mixed literal arg computation'); + assert.equal(el.$.boundChild.computedFromPureLiterals, '3foo', 'Wrong result from pure literal arg computation'); }); test('no read-only observer called with assignment', function() { From 42eaedd172826c66ba47b168c9c8a5de014474ae Mon Sep 17 00:00:00 2001 From: Scott J Miles Date: Wed, 20 May 2015 15:10:53 -0700 Subject: [PATCH 09/14] * remove bogus support for arbitrary JSON in literal arguments, literal arguments must now be either String or Number * support using escaped-commas in literal-string arguments: `compute("foo\,bar", zot, 3)` * support other character escaping which is naturally broken by HTML parser `compute('foo\'bar')` * test for literal argument _before_ looking for structured args --- src/standard/effectBuilder.html | 70 +++++++++++++++++---------------- test/unit/bind-elements.html | 8 +++- test/unit/bind.html | 2 + 3 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/standard/effectBuilder.html b/src/standard/effectBuilder.html index 8afcfa2694..8230932b4d 100644 --- a/src/standard/effectBuilder.html +++ b/src/standard/effectBuilder.html @@ -168,14 +168,13 @@ _parseMethod: function(expression) { var m = expression.match(/(\w*)\((.*)\)/); if (m) { - return this._parseArgs({ - method: m[1], - static: true - }, m[2].split(',')); + // replace escaped commas with comma entity, split on un-escaped commas + var args = m[2].replace(/\\,/g, ',').split(','); + return this._parseArgs(args, { method: m[1], static: true }); } }, - _parseArgs: function(effect, argList) { + _parseArgs: function(argList, effect) { effect.args = argList.map(function(rawArg) { var arg = this._parseArg(rawArg); if (!arg.literal) { @@ -187,40 +186,43 @@ }, _parseArg: function(rawArg) { - // clean up string - var arg = String(rawArg).trim(); + // clean up whitespace + var arg = String(rawArg).trim() + // replace comma entity with comma + .replace(/,/g, ',') + // repair escape sequences + .replace(/\\(.)/g, '\$1') + ; // basic argument descriptor var a = { name: arg, model: this._modelForPath(arg) }; - // detect structured path (has dots) - a.structured = arg.indexOf('.') > 0; - if (a.structured) { - a.wildcard = (arg.slice(-2) == '.*'); - if (a.wildcard) { - a.name = arg.slice(0, -2); - } - } else { - // detect literal value (must be JSON) - var fc = arg[0]; - if (fc >= '0' && fc <= '9') { - fc = '#'; - } - switch(fc) { - // TODO(sjmiles): single-quote is invalid JSON - //case "'": - case '"': - case '{': - case '[': - case '#': - try { - a.value = JSON.parse(arg); - a.literal = true; - } catch(x) { - // warn? - } - break; + // detect literal value (must be String or Number) + var fc = arg[0]; + if (fc >= '0' && fc <= '9') { + fc = '#'; + } + switch(fc) { + case "'": + case '"': + a.value = arg.slice(1, -1); + a.literal = true; + break; + case '#': + a.value = Number(arg); + a.literal = true; + break; + } + // if not literal, look for structured path + if (!a.literal) { + // detect structured path (has dots) + a.structured = arg.indexOf('.') > 0; + if (a.structured) { + a.wildcard = (arg.slice(-2) == '.*'); + if (a.wildcard) { + a.name = arg.slice(0, -2); + } } } return a; diff --git a/test/unit/bind-elements.html b/test/unit/bind-elements.html index 342c4950a8..f49985c46e 100644 --- a/test/unit/bind-elements.html +++ b/test/unit/bind-elements.html @@ -15,12 +15,15 @@ custom-event-value="{{customEventValue::custom}}" custom-event-object-value="{{customEventObject.value::change}}" computed-from-mixed-literals='{{computeFromLiterals(3, "foo", bool)}}' - computed-from-pure-literals='{{computeFromLiterals(3, "foo")}}' + computed-from-pure-literals='{{computeFromLiterals( 3, "foo")}}' + computed-from-tricky-literals="{{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}}" + computed-from-tricky-literals2='{{computeFromTrickyLiterals(3,"tricky\,\'zot\'" )}}' > Test {{text}} + {{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}} diff --git a/test/unit/bind.html b/test/unit/bind.html index 207832b9e8..36f821de20 100644 --- a/test/unit/bind.html +++ b/test/unit/bind.html @@ -142,6 +142,8 @@ el.bool = true; assert.equal(el.$.boundChild.computedFromMixedLiterals, '3foo', 'Wrong result from mixed literal arg computation'); assert.equal(el.$.boundChild.computedFromPureLiterals, '3foo', 'Wrong result from pure literal arg computation'); + assert.equal(el.$.boundChild.computedFromTrickyLiterals, '3tricky,\'zot\'', 'Wrong result from tricky literal arg computation'); + assert.equal(el.$.computedContent.textContent, '3tricky,\'zot\'', 'Wrong textContent from tricky literal arg computation'); }); test('no read-only observer called with assignment', function() { From c00134435c04ac7fa28ce6b69aa0833317f7c893 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Fri, 22 May 2015 12:58:12 -0700 Subject: [PATCH 10/14] Accept no-arg computed fns as static. Fixes #1516. --- src/standard/effectBuilder.html | 20 +++++++++++++------- test/unit/bind-elements.html | 4 ++++ test/unit/bind.html | 4 ++++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/standard/effectBuilder.html b/src/standard/effectBuilder.html index 8230932b4d..cd19e89f33 100644 --- a/src/standard/effectBuilder.html +++ b/src/standard/effectBuilder.html @@ -168,21 +168,27 @@ _parseMethod: function(expression) { var m = expression.match(/(\w*)\((.*)\)/); if (m) { - // replace escaped commas with comma entity, split on un-escaped commas - var args = m[2].replace(/\\,/g, ',').split(','); - return this._parseArgs(args, { method: m[1], static: true }); + var sig = { method: m[1], static: true }; + if (m[2].trim()) { + // replace escaped commas with comma entity, split on un-escaped commas + var args = m[2].replace(/\\,/g, ',').split(','); + return this._parseArgs(args, sig); + } else { + sig.args = Polymer.nar; + return sig; + } } }, - _parseArgs: function(argList, effect) { - effect.args = argList.map(function(rawArg) { + _parseArgs: function(argList, sig) { + sig.args = argList.map(function(rawArg) { var arg = this._parseArg(rawArg); if (!arg.literal) { - effect.static = false; + sig.static = false; } return arg; }, this); - return effect; + return sig; }, _parseArg: function(rawArg) { diff --git a/test/unit/bind-elements.html b/test/unit/bind-elements.html index f49985c46e..7c3a7a634c 100644 --- a/test/unit/bind-elements.html +++ b/test/unit/bind-elements.html @@ -18,6 +18,7 @@ computed-from-pure-literals='{{computeFromLiterals( 3, "foo")}}' computed-from-tricky-literals="{{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}}" computed-from-tricky-literals2='{{computeFromTrickyLiterals(3,"tricky\,\'zot\'" )}}' + computed-from-no-args="{{computeFromNoArgs( )}}" > Test @@ -198,6 +199,9 @@ }, computeFromTrickyLiterals: function(a, b) { return a + b; + }, + computeFromNoArgs: function() { + return 'no args!'; } }); diff --git a/test/unit/bind.html b/test/unit/bind.html index 36f821de20..b753f3b9ec 100644 --- a/test/unit/bind.html +++ b/test/unit/bind.html @@ -146,6 +146,10 @@ assert.equal(el.$.computedContent.textContent, '3tricky,\'zot\'', 'Wrong textContent from tricky literal arg computation'); }); + test('computed annotation with no args', function() { + assert.equal(el.$.boundChild.computedFromNoArgs, 'no args!', 'Wrong content when computed has no args'); + }); + test('no read-only observer called with assignment', function() { el.readolyvalue = 46; assert.equal(el.observerCounts.readonlyvalueChanged, 0, 'observer should not be called for readOnly prop assignment'); From cf5cba7c1805de7945cc3950cd8c3b11d2012450 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Fri, 22 May 2015 14:26:12 -0700 Subject: [PATCH 11/14] Update comment. --- src/standard/configure.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/standard/configure.html b/src/standard/configure.html index d2c114eb02..5df37658bc 100644 --- a/src/standard/configure.html +++ b/src/standard/configure.html @@ -67,7 +67,9 @@ // configure: returns user supplied default property values // combines with _config to create final property values _configure: function() { - // TODO(sjmiles): does what? + // some annotation data needs to be handed from host to client + // e.g. hand template content stored in notes to children as part of + // configure flow so templates have their content at ready time this._configureAnnotationReferences(); // process static effects, e.g. computations that have only literal arguments this._executeStaticEffects(); From ffc361cf348b2f1d252c07d177283a58cee3c1ba Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Fri, 22 May 2015 14:37:57 -0700 Subject: [PATCH 12/14] Add comment about escaping. --- src/standard/effectBuilder.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/standard/effectBuilder.html b/src/standard/effectBuilder.html index cd19e89f33..bfc939fed1 100644 --- a/src/standard/effectBuilder.html +++ b/src/standard/effectBuilder.html @@ -193,10 +193,12 @@ _parseArg: function(rawArg) { // clean up whitespace - var arg = String(rawArg).trim() + var arg = rawArg.trim() // replace comma entity with comma .replace(/,/g, ',') - // repair escape sequences + // repair extra escape sequences; note only commas strictly need + // escaping, but we allow any other char to be escaped since its + // likely users will do this .replace(/\\(.)/g, '\$1') ; // basic argument descriptor From e6859b6b9ec71f548ca5457e3db5dc01c64a25d1 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Fri, 22 May 2015 15:04:30 -0700 Subject: [PATCH 13/14] Move _executeStaticEffects to _applyConfig timing. --- src/standard/configure.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/standard/configure.html b/src/standard/configure.html index 5df37658bc..ce957ecbb2 100644 --- a/src/standard/configure.html +++ b/src/standard/configure.html @@ -71,8 +71,6 @@ // e.g. hand template content stored in notes to children as part of // configure flow so templates have their content at ready time this._configureAnnotationReferences(); - // process static effects, e.g. computations that have only literal arguments - this._executeStaticEffects(); // get individual default values from property configs var config = {}; // mixed-in behaviors @@ -137,6 +135,8 @@ // Override polymer-mini thunk _afterClientsReady: function() { + // process static effects, e.g. computations that have only literal arguments + this._executeStaticEffects(); this._applyConfig(this._config); this._flushHandlers(); }, From 40a957896d369e70ec7c73cbc4f5532d1fbef672 Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Fri, 22 May 2015 15:04:51 -0700 Subject: [PATCH 14/14] Add corrected computedFromTrickyLiterals2 test. --- test/unit/bind-elements.html | 2 +- test/unit/bind.html | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unit/bind-elements.html b/test/unit/bind-elements.html index 7c3a7a634c..6849c00d0e 100644 --- a/test/unit/bind-elements.html +++ b/test/unit/bind-elements.html @@ -17,7 +17,7 @@ computed-from-mixed-literals='{{computeFromLiterals(3, "foo", bool)}}' computed-from-pure-literals='{{computeFromLiterals( 3, "foo")}}' computed-from-tricky-literals="{{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}}" - computed-from-tricky-literals2='{{computeFromTrickyLiterals(3,"tricky\,\'zot\'" )}}' + computed-from-tricky-literals2='{{computeFromTrickyLiterals(3,"tricky\,'zot'" )}}' computed-from-no-args="{{computeFromNoArgs( )}}" > Test diff --git a/test/unit/bind.html b/test/unit/bind.html index b753f3b9ec..cba71e4a69 100644 --- a/test/unit/bind.html +++ b/test/unit/bind.html @@ -143,6 +143,7 @@ assert.equal(el.$.boundChild.computedFromMixedLiterals, '3foo', 'Wrong result from mixed literal arg computation'); assert.equal(el.$.boundChild.computedFromPureLiterals, '3foo', 'Wrong result from pure literal arg computation'); assert.equal(el.$.boundChild.computedFromTrickyLiterals, '3tricky,\'zot\'', 'Wrong result from tricky literal arg computation'); + assert.equal(el.$.boundChild.computedFromTrickyLiterals2, '3tricky,\'zot\'', 'Wrong result from tricky literal arg computation'); assert.equal(el.$.computedContent.textContent, '3tricky,\'zot\'', 'Wrong textContent from tricky literal arg computation'); });