mirror of
https://github.com/CryptKeeperZK/ejs.git
synced 2026-01-09 07:27:59 -05:00
Merge pull request #603 from mde/mde-null-proto-where-possible
Move to utils, handle older runtimes, fix tests
This commit is contained in:
27
lib/ejs.js
27
lib/ejs.js
@@ -67,17 +67,6 @@ var _OPTS_PASSABLE_WITH_DATA_EXPRESS = _OPTS_PASSABLE_WITH_DATA.concat('cache');
|
||||
var _BOM = /^\uFEFF/;
|
||||
var _JS_IDENTIFIER = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
|
||||
|
||||
var createObj = function() {
|
||||
if (typeof Object.create !== 'function') {
|
||||
return function (o) {
|
||||
function F() {}
|
||||
F.prototype = o;
|
||||
return new F();
|
||||
};
|
||||
}
|
||||
return Object.create;
|
||||
}();
|
||||
|
||||
/**
|
||||
* EJS template function cache. This can be a LRU object from lru-cache NPM
|
||||
* module. By default, it is {@link module:utils.cache}, a simple in-process
|
||||
@@ -318,7 +307,7 @@ function fileLoader(filePath){
|
||||
*/
|
||||
|
||||
function includeFile(path, options) {
|
||||
var opts = utils.shallowCopy(createObj(null), options);
|
||||
var opts = utils.shallowCopy(utils.createNullProtoObjWherePossible(), options);
|
||||
opts.filename = getIncludePath(path, opts);
|
||||
if (typeof options.includer === 'function') {
|
||||
var includerResult = options.includer(path, opts.filename);
|
||||
@@ -424,8 +413,8 @@ exports.compile = function compile(template, opts) {
|
||||
*/
|
||||
|
||||
exports.render = function (template, d, o) {
|
||||
var data = d || createObj(null);
|
||||
var opts = o || createObj(null);
|
||||
var data = d || utils.createNullProtoObjWherePossible();
|
||||
var opts = o || utils.createNullProtoObjWherePossible();
|
||||
|
||||
// No options object -- if there are optiony names
|
||||
// in the data, copy them to options
|
||||
@@ -496,7 +485,7 @@ exports.renderFile = function () {
|
||||
opts.filename = filename;
|
||||
}
|
||||
else {
|
||||
data = createObj(null);
|
||||
data = utils.createNullProtoObjWherePossible();
|
||||
}
|
||||
|
||||
return tryHandleCache(opts, data, cb);
|
||||
@@ -518,8 +507,8 @@ exports.clearCache = function () {
|
||||
};
|
||||
|
||||
function Template(text, opts) {
|
||||
opts = opts || createObj(null);
|
||||
var options = createObj(null);
|
||||
opts = opts || utils.createNullProtoObjWherePossible();
|
||||
var options = utils.createNullProtoObjWherePossible();
|
||||
this.templateText = text;
|
||||
/** @type {string | null} */
|
||||
this.mode = null;
|
||||
@@ -705,14 +694,14 @@ Template.prototype = {
|
||||
// Adds a local `include` function which allows full recursive include
|
||||
var returnedFn = opts.client ? fn : function anonymous(data) {
|
||||
var include = function (path, includeData) {
|
||||
var d = utils.shallowCopy(createObj(null), data);
|
||||
var d = utils.shallowCopy(utils.createNullProtoObjWherePossible(), data);
|
||||
if (includeData) {
|
||||
d = utils.shallowCopy(d, includeData);
|
||||
}
|
||||
return includeFile(path, opts)(d);
|
||||
};
|
||||
return fn.apply(opts.context,
|
||||
[data || createObj(null), escapeFn, include, rethrow]);
|
||||
[data || utils.createNullProtoObjWherePossible(), escapeFn, include, rethrow]);
|
||||
};
|
||||
if (opts.filename && typeof Object.defineProperty === 'function') {
|
||||
var filename = opts.filename;
|
||||
|
||||
26
lib/utils.js
26
lib/utils.js
@@ -183,3 +183,29 @@ exports.cache = {
|
||||
exports.hyphenToCamel = function (str) {
|
||||
return str.replace(/-[a-z]/g, function (match) { return match[1].toUpperCase(); });
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a null-prototype object in runtimes that support it
|
||||
*
|
||||
* @return {Object} Object, prototype will be set to null where possible
|
||||
* @static
|
||||
* @private
|
||||
*/
|
||||
exports.createNullProtoObjWherePossible = (function () {
|
||||
if (typeof Object.create == 'function') {
|
||||
return function () {
|
||||
return Object.create(null);
|
||||
};
|
||||
}
|
||||
if (!({__proto__: null} instanceof Object)) {
|
||||
return function () {
|
||||
return {__proto__: null};
|
||||
};
|
||||
}
|
||||
// Not possible, just pass through
|
||||
return function () {
|
||||
return {};
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
|
||||
10
test/ejs.js
10
test/ejs.js
@@ -1183,24 +1183,26 @@ suite('identifier validation', function () {
|
||||
test('invalid outputFunctionName', function() {
|
||||
assert.throws(function() {
|
||||
ejs.compile('<p>yay</p>', {outputFunctionName: 'x;console.log(1);x'});
|
||||
}, /outputFunctionName is not a valid JS identifier/)
|
||||
}, /outputFunctionName is not a valid JS identifier/);
|
||||
});
|
||||
|
||||
test('invalid localsName', function() {
|
||||
var locals = Object.create(null);
|
||||
void(locals); // For linting;
|
||||
assert.throws(function() {
|
||||
ejs.compile('<p>yay</p>', {
|
||||
localsName: 'function(){console.log(1);return locals;}()'});
|
||||
}, /localsName is not a valid JS identifier/)
|
||||
}, /localsName is not a valid JS identifier/);
|
||||
});
|
||||
|
||||
test('invalid destructuredLocals', function() {
|
||||
var locals = {};
|
||||
void(locals); // For linting;
|
||||
assert.throws(function() {
|
||||
ejs.compile('<p>yay</p>', {
|
||||
destructuredLocals: [
|
||||
'console.log(1); //'
|
||||
]});
|
||||
}, /destructuredLocals\[0\] is not a valid JS identifier/)
|
||||
}, /destructuredLocals\[0\] is not a valid JS identifier/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user