From fc6d73b3539b3750d5690b47dd1beba2004b884b Mon Sep 17 00:00:00 2001 From: Phillip Johnsen Date: Sat, 16 May 2015 00:20:11 +0200 Subject: [PATCH 1/3] Bugfix for using values from view's context prototype. Fixes #445 --- mustache.js | 6 ++-- test/_files/uses_props_from_view_prototype.js | 30 +++++++++++++++++++ .../uses_props_from_view_prototype.mustache | 1 + .../_files/uses_props_from_view_prototype.txt | 1 + 4 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 test/_files/uses_props_from_view_prototype.js create mode 100644 test/_files/uses_props_from_view_prototype.mustache create mode 100644 test/_files/uses_props_from_view_prototype.txt diff --git a/mustache.js b/mustache.js index 6ff90f2..4fab12e 100644 --- a/mustache.js +++ b/mustache.js @@ -380,13 +380,13 @@ **/ while (value != null && index < names.length) { if (index === names.length - 1 && value != null) - lookupHit = (typeof value === 'object') && - value.hasOwnProperty(names[index]); + lookupHit = (typeof value === 'object') && value[names[index]]; + value = value[names[index++]]; } } else if (context.view != null && typeof context.view === 'object') { value = context.view[name]; - lookupHit = context.view.hasOwnProperty(name); + lookupHit = context.view.hasOwnProperty(name) || Object.prototype[name] !== value; } if (lookupHit) diff --git a/test/_files/uses_props_from_view_prototype.js b/test/_files/uses_props_from_view_prototype.js new file mode 100644 index 0000000..5fff76a --- /dev/null +++ b/test/_files/uses_props_from_view_prototype.js @@ -0,0 +1,30 @@ +var Aaa = (function () { + function Aaa(x, y) { + this.x = x; + this._y = y; + } + Object.defineProperty(Aaa.prototype, "y", { + get: function () { + return this._y; + }, + set: function (value) { + this._y = value; + }, + enumerable: true, + configurable: true + }); + return Aaa; +})(); +var Bbb = (function () { + function Bbb() { + } + return Bbb; +})(); + +var b = new Bbb(); +b.item = new Aaa("0", "00"); +b.items = []; +b.items.push({ a: new Aaa("1", "2") }); +b.items.push({ a: new Aaa("3", "4") }); + +(b) diff --git a/test/_files/uses_props_from_view_prototype.mustache b/test/_files/uses_props_from_view_prototype.mustache new file mode 100644 index 0000000..874f0c9 --- /dev/null +++ b/test/_files/uses_props_from_view_prototype.mustache @@ -0,0 +1 @@ +[{{ item.x }};{{ item.y }}]||{{#items}}[{{ a.x }};{{ a.y }} {{#a}}{{y}}{{/a}}]{{/items}} \ No newline at end of file diff --git a/test/_files/uses_props_from_view_prototype.txt b/test/_files/uses_props_from_view_prototype.txt new file mode 100644 index 0000000..f416840 --- /dev/null +++ b/test/_files/uses_props_from_view_prototype.txt @@ -0,0 +1 @@ +[0;00]||[1;2 2][3;4 4] \ No newline at end of file From 931f49b5dae31b1dd4c89947df16951adcf376c1 Mon Sep 17 00:00:00 2001 From: David da Silva Date: Fri, 29 May 2015 21:38:27 +0200 Subject: [PATCH 2/3] improve test with undefined/null lookup hit using dot notation --- test/_files/null_lookup_object.js | 15 ++++++++++++++- test/_files/null_lookup_object.mustache | 6 ++++++ test/_files/null_lookup_object.txt | 4 ++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/test/_files/null_lookup_object.js b/test/_files/null_lookup_object.js index 2f758a5..0f82480 100644 --- a/test/_files/null_lookup_object.js +++ b/test/_files/null_lookup_object.js @@ -14,5 +14,18 @@ "name": "Chris", "twitter": undefined } - ] + ], + "favorites": { + "color": "blue", + "president": "Bush", + "show": "Futurama" + }, + "mascot": { + "name": "Squid", + "favorites": { + "color": "orange", + "president": undefined, + "show": null + } + } }) diff --git a/test/_files/null_lookup_object.mustache b/test/_files/null_lookup_object.mustache index e709ae4..243e218 100644 --- a/test/_files/null_lookup_object.mustache +++ b/test/_files/null_lookup_object.mustache @@ -1,3 +1,9 @@ {{#fobject}} {{name}}'s twitter: {{#twitter}}{{.}}{{/twitter}}{{^twitter}}unknown{{/twitter}}. {{/fobject}} + +{{#mascot}} +{{name}}'s favorite color: {{#favorites.color}}{{.}}{{/favorites.color}}{{^favorites.color}}no one{{/favorites.color}}. +{{name}}'s favorite president: {{#favorites.president}}{{.}}{{/favorites.president}}{{^favorites.president}}no one{{/favorites.president}}. +{{name}}'s favorite show: {{#favorites.show}}{{.}}{{/favorites.show}}{{^favorites.show}}none{{/favorites.show}}. +{{/mascot}} diff --git a/test/_files/null_lookup_object.txt b/test/_files/null_lookup_object.txt index c1c727b..0f71bdb 100644 --- a/test/_files/null_lookup_object.txt +++ b/test/_files/null_lookup_object.txt @@ -1,3 +1,7 @@ Flor's twitter: @florrts. Miquel's twitter: unknown. Chris's twitter: unknown. + +Squid's favorite color: orange. +Squid's favorite president: no one. +Squid's favorite show: none. From 8adacd16413b41546a9a58aa93d63fee865c575d Mon Sep 17 00:00:00 2001 From: Phillip Johnsen Date: Wed, 10 Jun 2015 19:54:45 +0200 Subject: [PATCH 3/3] Bugfix for null/undefined when using dot notation --- mustache.js | 16 ++++++++++++---- test/render-helper.js | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/mustache.js b/mustache.js index 4fab12e..3cd0a13 100644 --- a/mustache.js +++ b/mustache.js @@ -29,6 +29,14 @@ return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); } + /** + * Null safe way of checking whether or not an object, + * including its prototype, has a given property + */ + function hasProperty (obj, propName) { + return obj != null && typeof obj === 'object' && (propName in obj); + } + // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577 // See https://github.com/janl/mustache.js/issues/189 var regExpTest = RegExp.prototype.test; @@ -379,14 +387,14 @@ * `undefined` and we want to avoid looking up parent contexts. **/ while (value != null && index < names.length) { - if (index === names.length - 1 && value != null) - lookupHit = (typeof value === 'object') && value[names[index]]; + if (index === names.length - 1) + lookupHit = hasProperty(value, names[index]); value = value[names[index++]]; } - } else if (context.view != null && typeof context.view === 'object') { + } else { value = context.view[name]; - lookupHit = context.view.hasOwnProperty(name) || Object.prototype[name] !== value; + lookupHit = hasProperty(context.view, name); } if (lookupHit) diff --git a/test/render-helper.js b/test/render-helper.js index aa39951..11e73c9 100644 --- a/test/render-helper.js +++ b/test/render-helper.js @@ -26,12 +26,12 @@ function getPartial(testName) { } // You can put the name of a specific test to run in the TEST environment -// variable (e.g. TEST=backslashes vows test/render-test.js) +// variable (e.g. TEST=backslashes mocha test/render-test.js) var testToRun = process.env.TEST; var testNames; if (testToRun) { - testNames = [testToRun]; + testNames = testToRun.split(','); } else { testNames = fs.readdirSync(_files).filter(function (file) { return (/\.js$/).test(file);