Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adding global autoescape option. Changed template.init to take an obj…

…ect. Adding underscore.js as a dependency.
  • Loading branch information...
commit 0f916ce3e1b8e472277396dc4bf86daf005a25dd 1 parent 858477f
@paularmstrong authored
View
30 index.js
@@ -9,17 +9,23 @@ var fs = require("fs"),
parser = require("parser"),
widgets = require("widgets"),
filters = require('filters'),
+ helpers = require('helpers'),
+
+ _ = require('underscore'),
+
+ config = {
+ autoescape: true,
+ root: '/',
+ debug: false
+ },
CACHE = {},
- DEBUG = false,
- ROOT = "/",
fromString, fromFile, createTemplate;
// Call this before using the templates
-exports.init = function (root, debug) {
- DEBUG = debug;
- ROOT = root;
+exports.init = function (options) {
+ config = _.extend(config, options);
};
createTemplate = function (data, id) {
@@ -40,18 +46,18 @@ createTemplate = function (data, id) {
render;
// The template token tree before compiled into javascript
- template.tokens = parser.parse.call(template, data, tags);
+ template.tokens = parser.parse.call(template, data, tags, config.autoescape);
// The raw template code - can be inserted into other templates
// We don't need this in production
code = parser.compile.call(template);
- if (DEBUG) {
+ if (config.debug) {
template.code = code;
}
// The compiled render function - this is all we need
- render = new Function("__context", "__parents", "__filters", "__widgets",
+ render = new Function("__context", "__parents", "__filters", "__widgets", '__escape',
[ '__parents = __parents ? __parents.slice() : [];'
// Prevents circular includes (which will crash node without warning)
, 'for (var i=0, j=__parents.length; i<j; ++i) {'
@@ -68,7 +74,7 @@ createTemplate = function (data, id) {
);
template.render = function (context, parents) {
- return render.call(this, context, parents, filters, widgets);
+ return render.call(this, context, parents, filters, widgets, helpers.escaper);
};
return template;
@@ -84,11 +90,11 @@ fromFile = function (filepath) {
filepath = filepath.substr(1);
}
- if (filepath in CACHE && !DEBUG) {
+ if (filepath in CACHE && !config.debug) {
return CACHE[filepath];
}
- var data = fs.readFileSync(ROOT + "/" + filepath, 'utf8');
+ var data = fs.readFileSync(config.root + "/" + filepath, 'utf8');
// TODO: see what error readFileSync returns and warn about it
if (data) {
CACHE[filepath] = createTemplate(data, filepath);
@@ -102,7 +108,7 @@ fromFile = function (filepath) {
fromString = function (string) {
var hash = crypto.createHash('md5').update(string).digest('hex');
- if (!(hash in CACHE && !DEBUG)) {
+ if (!(hash in CACHE && !config.debug)) {
CACHE[hash] = createTemplate(string, hash);
}
View
10 lib/helpers.js
@@ -162,4 +162,12 @@ exports.isLiteral = isLiteral;
exports.isValidName = isValidName;
exports.isValidShortName = isValidShortName;
exports.isValidBlockName = isValidBlockName;
-exports.isStringLiteral = isStringLiteral;
+exports.isStringLiteral = isStringLiteral;
+
+exports.escaper = function (input) {
+ if (typeof input === 'string') {
+ return input.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
+ } else {
+ return input;
+ }
+};
View
17 lib/parser.js
@@ -1,5 +1,6 @@
var helpers = require('./helpers'),
filters = require('./filters'),
+ _ = require('underscore'),
check = helpers.check,
@@ -17,8 +18,9 @@ exports.TOKEN_TYPES = {
VAR: VAR_TOKEN
};
-exports.parse = function (data, tags) {
+exports.parse = function (data, tags, autoescape) {
var rawtokens = data.trim().replace(/(^\n+)|(\n+$)/, "").split(/(\{%.*?%\}|\{\{.*?\}\}|\{#.*?#\})/),
+ escape = !!autoescape,
stack = [[]],
index = 0,
i = 0, j = rawtokens.length,
@@ -53,7 +55,8 @@ exports.parse = function (data, tags) {
token = {
type: VAR_TOKEN,
name: varname,
- filters: filters
+ filters: filters,
+ escape: escape
};
} else if (logicRegexp.test(token)) {
parts = token.replace(/^\{% *| *%\}$/g, "").split(" ");
@@ -110,7 +113,7 @@ function wrapFilter(variable, filter) {
return output;
}
-function wrapFilters(variable, filters, context) {
+function wrapFilters(variable, filters, context, escape) {
var output = helpers.escape(variable, context);
if (filters && filters.length > 0) {
@@ -119,6 +122,10 @@ function wrapFilters(variable, filters, context) {
});
}
+ if (escape) {
+ output = '__escape.apply(this, [' + output + '])';
+ }
+
return output;
}
@@ -182,9 +189,9 @@ exports.compile = function compile(indent, parentBlock) {
varOutput = token.name;
return code.push(
'if (' + check(varOutput) + ') {'
- , ' __output.push(' + wrapFilters(varOutput, token.filters) + ');'
+ , ' __output.push(' + wrapFilters(varOutput, token.filters, null, token.escape) + ');'
, '} else if (' + check(varOutput, '__context') + ') {'
- , ' __output.push(' + wrapFilters(varOutput, token.filters, '__context') + ');'
+ , ' __output.push(' + wrapFilters(varOutput, token.filters, '__context', token.escape) + ');'
, '}'
);
}
View
4 package.json
@@ -8,7 +8,9 @@
"contributors": [
"Paul Armstrong <paul@paularmstrongdesigns.com>"
],
- "dependencies": {},
+ "dependencies": {
+ "underscore": "1.1.7"
+ },
"devDependencies": {
"nodelint": "0.4.0",
"nodeunit": "0.5.3"
View
16 tests/parser.test.js
@@ -73,33 +73,33 @@ exports.Comments = testCase({
exports.Variable = testCase({
'basic variable': function (test) {
var output = parser.parse('{{ foobar }}');
- test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', filters: [] }], output, 'with spaces');
+ test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', filters: [], escape: false }], output, 'with spaces');
output = parser.parse('{{foobar}}');
- test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', filters: [] }], output, 'without spaces');
+ test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', filters: [], escape: false }], output, 'without spaces');
test.done();
},
'dot-notation variable': function (test) {
var output = parser.parse('{{ foo.bar }}');
- test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foo.bar', filters: [] }], output);
+ test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foo.bar', filters: [], escape: false }], output);
test.done();
},
'variable with filter': function (test) {
var output = parser.parse('{{ foobar|awesome }}');
- test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', filters: [{ name: 'awesome', args: [] }] }], output, 'filter by name');
+ test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', escape: false, filters: [{ name: 'awesome', args: [] }] }], output, 'filter by name');
output = parser.parse('{{ foobar|awesome("param", 2) }}');
- test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', filters: [{ name: 'awesome', args: ['param', 2] }] }], output, 'filter with params');
+ test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', escape: false, filters: [{ name: 'awesome', args: ['param', 2] }] }], output, 'filter with params');
test.done();
},
'multiple filters': function (test) {
var output = parser.parse('{{ foobar|baz(1)|rad|awesome("param", 2) }}');
- test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', filters: [
+ test.deepEqual([{ type: parser.TOKEN_TYPES.VAR, name: 'foobar', escape: false, filters: [
{ name: 'baz', args: [1] },
{ name: 'rad', args: [] },
{ name: 'awesome', args: ['param', 2] }
@@ -111,8 +111,8 @@ exports.Variable = testCase({
'filters do not carry over': function (test) {
var output = parser.parse('{{ foo|baz }}{{ bar }}');
test.deepEqual([
- { type: parser.TOKEN_TYPES.VAR, name: 'foo', filters: [{ name: 'baz', args: [] }] },
- { type: parser.TOKEN_TYPES.VAR, name: 'bar', filters: [] }
+ { type: parser.TOKEN_TYPES.VAR, name: 'foo', filters: [{ name: 'baz', args: [] }], escape: false },
+ { type: parser.TOKEN_TYPES.VAR, name: 'bar', filters: [], escape: false }
], output);
test.done();
}
View
6 tests/speed.js
@@ -4,7 +4,9 @@ var template = require('../index'),
console.log();
console.log('Starting speed tests...');
-template.init(__dirname, false);
+template.init({
+ root: __dirname + '/templates'
+});
tplS = template.fromString(
"{% for v in array %}"
@@ -19,8 +21,6 @@ tplS = template.fromString(
+ "{% end %}"
);
-template.init(__dirname + '/templates');
-
array = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], { af: "s", baz: "d", d: "f" }, "zeus"];
tplF = template.fromFile("include_base.html");
template.fromFile("included_2.html");
Please sign in to comment.
Something went wrong with that request. Please try again.