Skip to content

Commit f21a9e4

Browse files
authored
Merge pull request #603 from mde/mde-null-proto-where-possible
Move to utils, handle older runtimes, fix tests
2 parents a50e46f + 576283b commit f21a9e4

File tree

3 files changed

+40
-23
lines changed

3 files changed

+40
-23
lines changed

lib/ejs.js

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,6 @@ var _OPTS_PASSABLE_WITH_DATA_EXPRESS = _OPTS_PASSABLE_WITH_DATA.concat('cache');
6767
var _BOM = /^\uFEFF/;
6868
var _JS_IDENTIFIER = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
6969

70-
var createObj = function() {
71-
if (typeof Object.create !== 'function') {
72-
return function (o) {
73-
function F() {}
74-
F.prototype = o;
75-
return new F();
76-
};
77-
}
78-
return Object.create;
79-
}();
80-
8170
/**
8271
* EJS template function cache. This can be a LRU object from lru-cache NPM
8372
* module. By default, it is {@link module:utils.cache}, a simple in-process
@@ -318,7 +307,7 @@ function fileLoader(filePath){
318307
*/
319308

320309
function includeFile(path, options) {
321-
var opts = utils.shallowCopy(createObj(null), options);
310+
var opts = utils.shallowCopy(utils.createNullProtoObjWherePossible(), options);
322311
opts.filename = getIncludePath(path, opts);
323312
if (typeof options.includer === 'function') {
324313
var includerResult = options.includer(path, opts.filename);
@@ -424,8 +413,8 @@ exports.compile = function compile(template, opts) {
424413
*/
425414

426415
exports.render = function (template, d, o) {
427-
var data = d || createObj(null);
428-
var opts = o || createObj(null);
416+
var data = d || utils.createNullProtoObjWherePossible();
417+
var opts = o || utils.createNullProtoObjWherePossible();
429418

430419
// No options object -- if there are optiony names
431420
// in the data, copy them to options
@@ -496,7 +485,7 @@ exports.renderFile = function () {
496485
opts.filename = filename;
497486
}
498487
else {
499-
data = createObj(null);
488+
data = utils.createNullProtoObjWherePossible();
500489
}
501490

502491
return tryHandleCache(opts, data, cb);
@@ -518,8 +507,8 @@ exports.clearCache = function () {
518507
};
519508

520509
function Template(text, opts) {
521-
opts = opts || createObj(null);
522-
var options = createObj(null);
510+
opts = opts || utils.createNullProtoObjWherePossible();
511+
var options = utils.createNullProtoObjWherePossible();
523512
this.templateText = text;
524513
/** @type {string | null} */
525514
this.mode = null;
@@ -705,14 +694,14 @@ Template.prototype = {
705694
// Adds a local `include` function which allows full recursive include
706695
var returnedFn = opts.client ? fn : function anonymous(data) {
707696
var include = function (path, includeData) {
708-
var d = utils.shallowCopy(createObj(null), data);
697+
var d = utils.shallowCopy(utils.createNullProtoObjWherePossible(), data);
709698
if (includeData) {
710699
d = utils.shallowCopy(d, includeData);
711700
}
712701
return includeFile(path, opts)(d);
713702
};
714703
return fn.apply(opts.context,
715-
[data || createObj(null), escapeFn, include, rethrow]);
704+
[data || utils.createNullProtoObjWherePossible(), escapeFn, include, rethrow]);
716705
};
717706
if (opts.filename && typeof Object.defineProperty === 'function') {
718707
var filename = opts.filename;

lib/utils.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,29 @@ exports.cache = {
183183
exports.hyphenToCamel = function (str) {
184184
return str.replace(/-[a-z]/g, function (match) { return match[1].toUpperCase(); });
185185
};
186+
187+
/**
188+
* Returns a null-prototype object in runtimes that support it
189+
*
190+
* @return {Object} Object, prototype will be set to null where possible
191+
* @static
192+
* @private
193+
*/
194+
exports.createNullProtoObjWherePossible = (function () {
195+
if (typeof Object.create == 'function') {
196+
return function () {
197+
return Object.create(null);
198+
};
199+
}
200+
if (!({__proto__: null} instanceof Object)) {
201+
return function () {
202+
return {__proto__: null};
203+
};
204+
}
205+
// Not possible, just pass through
206+
return function () {
207+
return {};
208+
};
209+
})();
210+
211+

test/ejs.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,24 +1183,26 @@ suite('identifier validation', function () {
11831183
test('invalid outputFunctionName', function() {
11841184
assert.throws(function() {
11851185
ejs.compile('<p>yay</p>', {outputFunctionName: 'x;console.log(1);x'});
1186-
}, /outputFunctionName is not a valid JS identifier/)
1186+
}, /outputFunctionName is not a valid JS identifier/);
11871187
});
11881188

11891189
test('invalid localsName', function() {
11901190
var locals = Object.create(null);
1191+
void(locals); // For linting;
11911192
assert.throws(function() {
11921193
ejs.compile('<p>yay</p>', {
11931194
localsName: 'function(){console.log(1);return locals;}()'});
1194-
}, /localsName is not a valid JS identifier/)
1195+
}, /localsName is not a valid JS identifier/);
11951196
});
11961197

11971198
test('invalid destructuredLocals', function() {
11981199
var locals = {};
1200+
void(locals); // For linting;
11991201
assert.throws(function() {
12001202
ejs.compile('<p>yay</p>', {
12011203
destructuredLocals: [
12021204
'console.log(1); //'
12031205
]});
1204-
}, /destructuredLocals\[0\] is not a valid JS identifier/)
1206+
}, /destructuredLocals\[0\] is not a valid JS identifier/);
12051207
});
1206-
});
1208+
});

0 commit comments

Comments
 (0)