Comparing version 0.1.1 to 1.0.4
@@ -1,161 +0,82 @@ | ||
var _ = require('underscore'); | ||
'use strict'; | ||
function builtins() { | ||
}; | ||
var utils = require('./utils'), | ||
_ = require('lodash'); | ||
builtins.prototype.__isDefined = function(name) { | ||
return _.isFunction(this[name]); | ||
}; | ||
exports.range = _.bind(_.range, _); | ||
builtins.prototype.range = function(start, stop, step) { | ||
if(arguments.length <= 1) { | ||
stop = start || 0; | ||
start = 0; | ||
} | ||
step = arguments[2] || 1; | ||
var length = Math.max(Math.ceil((stop - start) / step), 0); | ||
var idx = 0; | ||
var arr = new Array(length); | ||
while(idx < length) { | ||
arr[idx++] = start; | ||
start += step; | ||
} | ||
return arr; | ||
exports.lower = function(s) { | ||
console.assert(_.isString(s)); | ||
return s.toLowerCase(); | ||
}; | ||
builtins.prototype.lower = function(str) { | ||
if(_.isString(str)) { | ||
return str.toLowerCase(); | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported string type: ' + typeof str); | ||
} | ||
}; | ||
builtins.prototype.upper = function(str) { | ||
if(_.isString(str)) { | ||
return str.toUpperCase(); | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported string type: ' + typeof str); | ||
} | ||
exports.upper = function(s) { | ||
console.assert(_.isString(s)); | ||
return s.toUpperCase(); | ||
}; | ||
builtins.prototype.join = function(x, delim) { | ||
if(!_.isString(delim)) { | ||
throw new Error('InvalidTypeError - unsupported delimiter type: ' + typeof delim); | ||
} | ||
exports.join = function(x, delim) { | ||
console.assert(_.isString(delim)); | ||
console.assert(_.isString(x) || _.isArray(x)); | ||
if(_.isArray(x)) { | ||
return x.join(delim); | ||
} else if(_.isString(x)) { | ||
return x.split('').join(delim); | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported collection type: ' + typeof x); | ||
} | ||
return _.isString(x) ? | ||
x.split('').join(delim) : | ||
x.join(delim); | ||
}; | ||
builtins.prototype.len = function(x) { | ||
try { | ||
return x.length; | ||
} catch(err) { | ||
throw new Error('InvalidTypeError - unsupported collection type: ' + typeof x); | ||
} | ||
}; | ||
exports.len = _.bind(_.size, _); | ||
builtins.prototype.reverse = function(x) { | ||
if(_.isArray(x)) { | ||
var len = x.length; | ||
var rev = new Array(len); | ||
for(var i=len-1; i>=0; --i) { rev[i] = x[len-i-1]; } | ||
return rev; | ||
} else if(_.isString(x)) { | ||
exports.reverse = function(x) { | ||
console.assert(_.isString(x) || _.isArray(x)); | ||
if(_.isString(x)) { | ||
return x.split('').reverse().join(''); | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported collection type: ' + typeof x); | ||
return _.clone(x).reverse(); | ||
} | ||
}; | ||
builtins.prototype.sort = function(x, reverse) { | ||
if(_.isArray(x)) { | ||
var clone = x.slice(); | ||
clone.sort(); | ||
if(!!reverse) { clone.reverse(); } | ||
return clone; | ||
} else if(_.isString(x)) { | ||
var clone = x.split(''); | ||
clone.sort(); | ||
if(!!reverse) { clone.reverse(); } | ||
return clone.join(''); | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported collection type: ' + typeof x); | ||
} | ||
exports.sort = function(x) { | ||
console.assert(_.isString(x) || _.isArray(x)); | ||
return _.isString(x) ? | ||
_.sortBy(x).join('') : | ||
_.sortBy(x); | ||
}; | ||
builtins.prototype.isArray = function(x) { | ||
return _.isArray(x); | ||
}; | ||
exports.isArray = _.bind(_.isArray, _); | ||
exports.isObject = _.bind(_.isPlainObject, _); | ||
exports.isBoolean = _.bind(_.isBoolean, _); | ||
exports.isString = _.bind(_.isString, _); | ||
builtins.prototype.isObject = function(x) { | ||
return _.isObject(x); | ||
exports.slice = function(x, start, stop) { | ||
console.assert(_.isString(x) || _.isArray(x)); | ||
return x.slice(start, stop); | ||
}; | ||
builtins.prototype.slice = function(x, start, stop) { | ||
if(_.isArray(x) || _.isString(x)) { | ||
return x.slice(start, stop); | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported collection type: ' + typeof x); | ||
} | ||
}; | ||
exports.get = function(x, p) { | ||
console.assert(_.isString(x) || _.isArray(x) || _.isPlainObject(x)); | ||
builtins.prototype.getAt = function(x, idx) { | ||
if(!_.isNumber(idx)) { | ||
throw new Error('InvalidTypeError - index must be a number: ' + typeof idx); | ||
} | ||
if(_.isArray(x) || _.isString(x)) { | ||
return x[idx]; | ||
if(_.isString(x) || _.isArray(x)) { | ||
console.assert(_.isNumber(p) && !_.isNaN(p) && (p >= 0) && (p < x.length)); | ||
return x[p]; | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported collection type: ' + typeof x); | ||
var v = utils.getValueByPath(x, p); | ||
console.assert(!_.isUndefined(v)); | ||
return v; | ||
} | ||
}; | ||
builtins.prototype.split = function(str, delim) { | ||
if(!_.isString(delim)) { | ||
throw new Error('InvalidTypeError - delim must be a string: ' + typeof delim); | ||
} | ||
if(_.isString(str)) { | ||
return str.split(delim); | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported string type: ' + typeof str); | ||
} | ||
exports.split = function(s, delim) { | ||
console.assert(_.isString(s)); | ||
console.assert(_.isString(delim)); | ||
return s.split(delim); | ||
}; | ||
builtins.prototype.int = function(str) { | ||
if(_.isString(str)) { | ||
return parseInt(str); | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported string type: ' + typeof str); | ||
} | ||
}; | ||
exports.int = _.bind(parseInt, null); | ||
exports.float = _.bind(parseFloat, null); | ||
builtins.prototype.float = function(str) { | ||
if(_.isString(str)) { | ||
return parseFloat(str); | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported string type: ' + typeof str); | ||
} | ||
exports.str = function(x) { | ||
return _.isString(x) ? x : JSON.stringify(x); | ||
}; | ||
builtins.prototype.str = function(x) { | ||
if(_.isString(x) || _.isArray(x) || _.isNumber(x)) { | ||
return x.toString(); | ||
} else { | ||
throw new Error('InvalidTypeError - unsupported type: ' + typeof x); | ||
} | ||
}; | ||
exports = module.exports = new builtins(); | ||
exports.math = Math; |
412
lib/wash.js
@@ -1,13 +0,7 @@ | ||
var assert = require('assert'), | ||
builtins = require('./builtins'), | ||
_ = require('underscore'); | ||
'use strict'; | ||
function escapeStr(str) { | ||
return str.replace(/\\/gm, '\\\\').replace(/\r?\n/gm, '\\n').replace(/\"/gm, '\\"').replace(/\t/gm, '\\t'); | ||
} | ||
var builtins = require('./builtins'), | ||
utils = require('./utils'), | ||
_ = require('lodash'); | ||
function escapeRegex(str){ | ||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'); | ||
} | ||
var evalOpenTag = '{{'; | ||
@@ -71,95 +65,57 @@ var evalCloseTag = '}}'; | ||
var evalTagRegex = new RegExp(escapeRegex(evalOpenTag) + '([^]*?)' + escapeRegex(evalCloseTag)); | ||
var actionTagRegex = new RegExp(escapeRegex(actionOpenTag) + '(\\s*(\\w+)([^]*)?)' + escapeRegex(actionCloseTag)); | ||
var actionTagNameRegex = new RegExp('\\s*(\\w+)[^]*'); | ||
var tagCaptureRegex = new RegExp('('+escapeRegex(evalOpenTag) + '[^]*?' + escapeRegex(evalCloseTag) | ||
+'|'+escapeRegex(actionOpenTag) + '[^]*?' + escapeRegex(actionCloseTag)+')', 'gm'); | ||
var evalTagRegex = new RegExp(utils.escapeRegex(evalOpenTag) + '([^]*?)' + utils.escapeRegex(evalCloseTag)); | ||
var actionTagRegex = new RegExp(utils.escapeRegex(actionOpenTag) + '(\\s*(\\w+)([^]*)?)' + utils.escapeRegex(actionCloseTag)); | ||
//var actionTagNameRegex = new RegExp('\\s*(\\w+)[^]*'); | ||
var tagCaptureRegex = new RegExp('('+utils.escapeRegex(evalOpenTag) + '[^]*?' + utils.escapeRegex(evalCloseTag) + | ||
'|'+utils.escapeRegex(actionOpenTag) + '[^]*?' + utils.escapeRegex(actionCloseTag)+')', 'gm'); | ||
var operators = ['+', '-', '*', '/', '==', '!=', '>=', '<=', '>', '<', '||', '&&', '!']; | ||
// operators + "string" + comman, parenthesis | ||
// operators + "string" + comman, parenthesis, brackets | ||
// if, elif, else, endif | ||
// for, in, endfor | ||
var tokenSplitRegex = /(\+(?!\=)|\-(?!\=)|\*(?!\=)|\/(?!\=)|\=\=(?!\=)|\!\=(?!\=)|\>\=(?!\=)|\<\=(?!\=)|\>(?!\=|\>|\<)|\<(?!\=|\<|\>)|\|\||\&\&|\!(?!\=)|\".+?\"|\(|\)|,|\bif\b|\belse\b|\belif\b|\bendif\b|\bfor\b|\bin\b|\bendfor\b)/g; | ||
var tokenSplitRegex = /(\+(?!=)|\-(?!=)|\*(?!=)|\/(?!=)|==(?!=)|!=(?!=)|>=(?!=)|<=(?!=)|>(?!=|>|<)|<(?!=|<|>)|\|\||&&|!(?!=)|".+?"|\(|\)|\[|]|,|\bif\b|\belse\b|\belif\b|\bendif\b|\bfor\b|\bin\b|\bendfor\b)/g; | ||
var defaultOptions = { | ||
throwsOnErrors: false, | ||
outputCompiledCode: false, | ||
throwOnError: false, | ||
outputPrecompiledSourceToConsole: false, | ||
outputErrorToConsole: false, | ||
maximumIterations: -1 | ||
}; | ||
var options = {}; | ||
for(var d in defaultOptions) { | ||
options[d] = defaultOptions[d]; | ||
} | ||
// tokenize and remove empty ones | ||
function _tokenize(expr) { | ||
console.assert(_.isString(expr)); | ||
function Precompiled(code) { | ||
this.code = code; | ||
return _.filter(_.map(expr.split(tokenSplitRegex), function(t) { return t.trim(); })); | ||
} | ||
Precompiled.prototype.render = function(context) { | ||
context = context || {}; | ||
function _safeEval(expr, shouldThrow) { | ||
console.assert(_.isString(expr)); | ||
try { | ||
var _func = new Function('__ctx', '__builtin', this.code); | ||
if(expr.length === 0) { return ''; } | ||
try { | ||
return _func(context, builtins); | ||
} catch(e) { | ||
//console.log('runtime', e); | ||
if(options.throwsOnErrors) { throw e; } | ||
else { return ''; } | ||
} | ||
} catch(e) { | ||
//console.log('compile-time', e); | ||
if(options.throwsOnErrors) { throw e; } | ||
else { return ''; } | ||
} | ||
}; | ||
var tokens = expr.split('.'); | ||
function Wash(source) { | ||
this.source = source; | ||
this._code = ''; | ||
this._localVars = []; | ||
this._loop_counter = 0; | ||
} | ||
var safetyTest = '('; | ||
_.each(tokens, function(e, i) { | ||
var p = tokens.slice(0, i + 1); | ||
safetyTest += '__ctx.' + p.join('.') + ' !== undefined'; | ||
if(i < tokens.length - 1) { safetyTest += ' && '; } | ||
}); | ||
safetyTest += ')'; | ||
Wash.prototype._tokenize = function(expr) { | ||
// tokenize and remove empty tokens | ||
var tokens = expr.split(tokenSplitRegex); | ||
var reduced = []; | ||
for(var i=0, len=tokens.length; i<len; ++i) { | ||
var trimmed = tokens[i].trim(); | ||
if(trimmed.length) { reduced.push(trimmed); } | ||
if(shouldThrow) { | ||
return '((' + safetyTest + ')?(__ctx.' + expr + '):assert(false))'; | ||
} else { | ||
return '((' + safetyTest + ')?(__ctx.' + expr + '):"")'; | ||
} | ||
return reduced; | ||
}; | ||
} | ||
Wash.prototype._evalTokenSafe = function(expr) { | ||
if(expr.length === 0) { | ||
//console.log('_evalTokenSafe() "" -> ""'); | ||
return ''; | ||
} | ||
function _findSub(tokens, openIdx, openChar, closeChar) { | ||
console.assert(tokens[openIdx] === openChar); | ||
var tokens = expr.split('.'); | ||
var tokenTest = '('; | ||
_.each(tokens, function(e, i) { | ||
var p = tokens.slice(0, i+1); | ||
tokenTest += '__ctx.' + p.join('.') + ' !== undefined'; | ||
if(i < tokens.length - 1) { tokenTest += ' && '; } | ||
}); | ||
tokenTest += ')'; | ||
var output = '((' + tokenTest + ')?(__ctx.' + expr + '):"")'; | ||
//console.log('_evalTokenSafe() "%s" -> "%s"', expr, output); | ||
return output; | ||
}; | ||
Wash.prototype._findSub = function(tokens, openIdx, openChar, closeChar) { | ||
assert(tokens[openIdx] === openChar, 'tokens[openIdx] != openChar?'); | ||
var level = 1; | ||
for(var j=openIdx+1, len=tokens.length; j<len; ++j) { | ||
for(var j = openIdx+1, len = tokens.length; j < len; ++j) { | ||
if(tokens[j] === openChar) { | ||
@@ -174,38 +130,99 @@ level += 1; | ||
return -1; | ||
} | ||
function _isLiteral(token) { | ||
// operators, string literal, true, false, number literals, commas | ||
return _.contains(operators, token) || | ||
/^".*"$|^true$|^false$|^-?\d*\.?\d+$|^,$/.test(token); | ||
} | ||
function Precompiled(code, options) { | ||
var self = this; | ||
self.code = code; | ||
self.options = options || {}; | ||
utils.deepDefaults(self.options, defaultOptions); | ||
} | ||
Precompiled.prototype.render = function(context) { | ||
var self = this; | ||
context = context || {}; | ||
var fn = null; | ||
try { | ||
/* jshint -W054 */ | ||
fn = new Function('__ctx', '__builtins', self.code); | ||
} catch(e) { | ||
if(self.options.outputErrorToConsole) { | ||
console.error('Precompiled.render() compile error: '); | ||
console.error(e.stack || e); | ||
} | ||
if(self.options.throwOnError) { throw e; } | ||
else { return ''; } | ||
} | ||
try { | ||
return fn(context, builtins); | ||
} catch(e) { | ||
if(self.options.outputErrorToConsole) { | ||
console.error('Precompiled.render() rendering error: '); | ||
console.error(e.stack || e); | ||
} | ||
if(self.options.throwOnError) { throw e; } | ||
else { return ''; } | ||
} | ||
}; | ||
function Wash(source, options) { | ||
var self = this; | ||
self.source = source; | ||
self.options = options || {}; | ||
_.each(_.keys(self.options), function(k) { | ||
console.assert(!_.isUndefined(defaultOptions[k]), 'Unknown option: ' + k); | ||
}); | ||
utils.deepDefaults(self.options, defaultOptions); | ||
self._code = ''; | ||
self._localVars = []; | ||
self._loop_counter = 0; | ||
} | ||
Wash.prototype._evalTokens = function(tokens) { | ||
var self = this; | ||
var outs = ''; | ||
for(var i=0,len=tokens.length; i<len; ++i) { | ||
for(var i = 0, len = tokens.length; i < len; ++i) { | ||
var token = tokens[i]; | ||
// operators, string literal, true, false, number literals, comman | ||
if(_.contains(operators, token) || /^\".*\"$|^true$|^false$|^-?\d*\.?\d+$|^\,$/.test(token)) { | ||
console.assert((token !== '[') && (token !== ']')); | ||
if(_isLiteral(token)) { | ||
outs += token; | ||
} else if(token === '(') { | ||
var closeIdx = this._findSub(tokens, i, '(', ')'); | ||
if(closeIdx > i) { | ||
outs += '(' + this._evalTokens(tokens.slice(i+1, closeIdx)) + ')'; | ||
i = closeIdx; | ||
var closeParen = _findSub(tokens, i, '(', ')'); | ||
if(closeParen > i) { | ||
outs += '(' + self._evalTokens(tokens.slice(i + 1, closeParen)) + ')'; | ||
i = closeParen; | ||
} else { | ||
outs += token; | ||
} | ||
} else if(builtins.__isDefined(token)) { | ||
outs += '__builtin.' + token; | ||
} else { | ||
var first; | ||
var dot = token.indexOf('.'); | ||
if(dot < 0) { | ||
first = token; | ||
var builtin = utils.getValueByPath(builtins, '.' + token); | ||
if(builtin) { | ||
outs += '__builtins.' + token; | ||
} else { | ||
first = token.slice(0, dot); | ||
var dot = token.indexOf('.'); | ||
var first = (dot < 0) ? token : token.slice(0, dot); | ||
if(_.contains(self._localVars, first)) { | ||
outs += token; | ||
} else { | ||
outs += _safeEval(token, self.options.throwOnError); | ||
} | ||
} | ||
if(_.contains(this._localVars, first)) { | ||
outs += token; | ||
} else { | ||
outs += this._evalTokenSafe(token); | ||
} | ||
} | ||
@@ -218,45 +235,48 @@ } | ||
Wash.prototype._parseForTag = function(params) { | ||
var loopId = ++this._loop_counter; | ||
var self = this; | ||
var loopId = ++self._loop_counter; | ||
var it = params[0]; | ||
var iterable = this._evalTokens(params.slice(2)); | ||
this._localVars.push(it); | ||
self._localVars.push(it); | ||
this._code += 'var __cnt_' + loopId + '=0;\n' | ||
+ 'var __iterable_' + loopId + '=(' + iterable + ');\n' | ||
+ 'for(var __key_' + loopId + ' in __iterable_' + loopId + '){\n'; | ||
self._code += 'var __cnt_' + loopId + '=0;\n' + | ||
'var __iterable_' + loopId + '=(' + iterable + ');\n' + | ||
'for(var __key_' + loopId + ' in __iterable_' + loopId + '){\n'; | ||
if(options.maximumIterations >= 0) { | ||
this._code += 'if(__cnt_' + loopId + '>=' + options.maximumIterations+') { break; };\n'; | ||
if(self.options.maximumIterations >= 0) { | ||
self._code += 'if(__cnt_' + loopId + '>=' + self.options.maximumIterations + ') { break; };\n'; | ||
} | ||
this._code += 'var ' + it + '={\n' | ||
+ 'key:__key_' + loopId + ',\n' | ||
+ 'value:__iterable_' + loopId + '[__key_' + loopId + '],\n' | ||
+ 'index:(__cnt_' + loopId + '++) };\n'; | ||
self._code += 'var ' + it + '={\n' + 'key:__key_' + loopId + ',\n' + | ||
'value:__iterable_' + loopId + '[__key_' + loopId + '],\n' + | ||
'index:(__cnt_' + loopId + '++) };\n'; | ||
}; | ||
Wash.prototype._parseTag = function(name, params) { | ||
var self = this; | ||
switch(name) { | ||
case 'if': | ||
var predExpr = this._evalTokens(params); | ||
this._code += 'if('+predExpr+'){\n'; | ||
var predIf = self._evalTokens(params); | ||
self._code += 'if(' + predIf + '){\n'; | ||
break; | ||
case 'elif': | ||
var predExpr = this._evalTokens(params); | ||
this._code += '}else if('+predExpr+'){\n'; | ||
var predElif= self._evalTokens(params); | ||
self._code += '}else if(' + predElif + '){\n'; | ||
break; | ||
case 'else': | ||
this._code += '}else{\n'; | ||
self._code += '}else{\n'; | ||
break; | ||
case 'endif': | ||
this._code += '}\n'; | ||
self._code += '}\n'; | ||
break; | ||
case 'for': | ||
this._parseForTag(params); | ||
self._parseForTag(params); | ||
break; | ||
case 'endfor': | ||
this._localVars.pop(); | ||
this._code += '}\n'; | ||
self._localVars.pop(); | ||
self._code += '}\n'; | ||
break; | ||
@@ -267,46 +287,42 @@ } | ||
Wash.prototype.precompile = function() { | ||
this._code += '"use strict";\nvar __out="";\n'; | ||
var self = this; | ||
self._code += '"use strict";\nvar __out="";\n'; | ||
var tokens = this.source.split(tagCaptureRegex); | ||
//console.log(tokens); | ||
var tagLevels = {}; | ||
for(var t in tags) { | ||
tagLevels[tags[t].openTag] = 0; | ||
} | ||
_.each(tags, function(tag) { | ||
tagLevels[tag.openTag] = 0; | ||
}); | ||
for(var i=0,len=tokens.length; i<len; ++i) { | ||
_.each(tokens, function(token) { | ||
if(token.length === 0) { return; } | ||
try { | ||
var token = tokens[i]; | ||
if(token.length === 0) { continue; } | ||
var match, expr; | ||
var match; | ||
if((match = evalTagRegex.exec(token)) && (tagLevels['raw'] <= 0)) { | ||
var expr = match[1].trim(); | ||
if(expr.length) { | ||
var output = this._evalTokens(this._tokenize(expr)); | ||
if(output.length) { | ||
this._code += '__out+=(' + output + ');\n'; | ||
if((match = evalTagRegex.exec(token)) && (tagLevels.raw <= 0)) { | ||
expr = match[1].trim(); | ||
if(expr) { | ||
var output = self._evalTokens(_tokenize(expr)); | ||
if(output) { | ||
self._code += '__out+=(' + output + ');\n'; | ||
} | ||
} | ||
} else if((match = actionTagRegex.exec(token))) { | ||
var expr = match[1].trim(); | ||
if(expr.length) { | ||
expr = match[1].trim(); | ||
if(expr) { | ||
var tagName = match[2]; | ||
var tagParams = this._tokenize(match[3] || ''); | ||
console.assert(tags[tagName], 'Unknown tag: ' + tagName); | ||
if(!tags[tagName]) { | ||
throw new Error('Template syntax error - unknown tag: ' + tagName); | ||
} | ||
var tagParams = _tokenize(match[3] || ''); | ||
var tagInfo = tags[tagName]; | ||
console.assert(tagInfo.requireParams || (tagParams.length === 0), | ||
'Redundant tag params: ' + tagName + ' ' + tagParams); | ||
if(!tagInfo.requireParams && (tagParams.length > 0)) { | ||
throw new Error('Template syntax error - redundant tag params: ' + tagName + ' ' + tagParams); | ||
} | ||
if(tagLevels['raw'] <= 0) { | ||
this._parseTag(tagName, tagParams); | ||
if(tagLevels.raw <= 0) { | ||
self._parseTag(tagName, tagParams); | ||
} else if(tagInfo.openTag !== 'raw') { | ||
this._code += '__out+="' + escapeStr(token) + '";\n'; | ||
self._code += '__out+="' + utils.escapeStr(token) + '";\n'; | ||
} | ||
@@ -317,37 +333,53 @@ | ||
} else { | ||
this._code += '__out+="' + escapeStr(token) + '";\n'; | ||
self._code += '__out+="' + utils.escapeStr(token) + '";\n'; | ||
} | ||
} catch(err) { | ||
if(options.throwsOnErrors) { throw err; } | ||
if(self.options.outputErrorToConsole) { | ||
console.error('Wash.precompile() eval error: '); | ||
console.error(err.stack || err); | ||
} | ||
if(self.options.throwOnError) { throw err; } | ||
} | ||
} | ||
}); | ||
for(var tagName in tagLevels) { | ||
var l = tagLevels[tagName]; | ||
if(l > 0) { | ||
if(options.throwsOnErrors) { | ||
throw new Error('Template syntax error - no closing tag: ' + tagName); | ||
} else { | ||
this._code = 'var __out = ""'; | ||
_.each(tagLevels, function(level, tagName) { | ||
if(level > 0) { | ||
if(self.options.outputErrorToConsole) { | ||
console.error('Wash.precompile() no closing tag: ' + tagName); | ||
} | ||
} else if(l < 0) { | ||
if(options.throwsOnErrors) { | ||
throw new Error('Template syntax error - redundant closing tag: ' + tagName); | ||
} else { | ||
this._code = 'var __out = ""'; | ||
console.assert(!self.options.throwOnError, 'No closing tag: ' + tagName); | ||
self._code = 'var __out = "";'; | ||
} else if(level < 0) { | ||
if(self.options.outputErrorToConsole) { | ||
console.error('Wash.precompile() redundant closing tag: ' + tagName); | ||
} | ||
console.assert(!self.options.throwOnError, 'Redundant closing tag: ' + tagName); | ||
self._code = 'var __out = "";'; | ||
} | ||
} | ||
}); | ||
this._code += 'return __out;\n'; | ||
self._code += 'return __out;\n'; | ||
if(options.outputCompiledCode) { | ||
console.log(this._code); | ||
if(self.options.outputPrecompiledSourceToConsole) { | ||
console.log('Wash.precompile() compiled source: '); | ||
console.log(self._code); | ||
} | ||
return new Precompiled(this._code); | ||
return new Precompiled(self._code, self.options); | ||
}; | ||
Wash.prototype.render = function(context) { | ||
var self = this; | ||
var precompiled = self.precompile(); | ||
return precompiled.render(context); | ||
}; | ||
exports = module.exports = Wash; | ||
exports.precompile = function(source) { | ||
var wash = new Wash(source); | ||
var wash = new Wash(source, defaultOptions); | ||
return wash.precompile(); | ||
@@ -358,3 +390,3 @@ }; | ||
if(!(source instanceof Precompiled)) { | ||
var wash = new Wash(source); | ||
var wash = new Wash(source, defaultOptions); | ||
source = wash.precompile(source); | ||
@@ -364,34 +396,2 @@ } | ||
return source.render(context); | ||
}; | ||
exports.save = function(precompiled) { | ||
assert(precompiled instanceof Precompiled, 'input parameter is not a "Precompiled" object.'); | ||
return precompiled.code; | ||
}; | ||
exports.load = function(saved) { | ||
return new Precompiled(saved, [], []); | ||
}; | ||
exports.resetOptions = function() { | ||
for(var d in defaultOptions) { | ||
options[d] = defaultOptions[d]; | ||
} | ||
}; | ||
exports.setOption = function(name, value) { | ||
if(!options.hasOwnProperty(name)) { | ||
throw new Error('invalid option name: ' + name); | ||
} | ||
options[name] = value; | ||
}; | ||
exports.getOption = function(name) { | ||
if(!options.hasOwnProperty(name)) { | ||
throw new Error('invalid option name: ' + name); | ||
} | ||
return options[name]; | ||
}; |
{ | ||
"name": "wash", | ||
"description": "a safe template rendering engine", | ||
"version": "0.1.1", | ||
"version": "1.0.4", | ||
"main": "index", | ||
"author": { | ||
"author": { | ||
"name" : "Daniel Kang", | ||
@@ -12,3 +12,3 @@ "email" : "me@daniel.gs", | ||
"licenses" : [ | ||
{ | ||
{ | ||
"type" : "MIT", | ||
@@ -19,7 +19,7 @@ "url" : "https://raw.github.com/d5/wash/master/LICENSE" | ||
"dependencies": { | ||
"underscore": "1.5.0" | ||
"lodash": "2.4.1" | ||
}, | ||
"devDependencies": { | ||
"mocha": "1.12.0", | ||
"expect.js": "0.2.0" | ||
"jshint": "2.5.2", | ||
"mocha": "1.20.x" | ||
}, | ||
@@ -35,4 +35,4 @@ "repository": { | ||
"scripts": { | ||
"test": "node_modules/.bin/mocha --reporter spec" | ||
"test": "node_modules/.bin/jshint lib && node_modules/.bin/jshint test && node_modules/.bin/mocha test" | ||
} | ||
} | ||
} |
@@ -64,8 +64,4 @@ # Wash | ||
## Wash in Production | ||
- [gist.sh](http://gist.sh): _(currently in beta phase)_ | ||
## License | ||
[MIT license](https://raw.github.com/d5/wash/master/LICENSE) |
@@ -1,8 +0,4 @@ | ||
require('./util'); | ||
'use strict'; | ||
describe('eval', function() { | ||
beforeEach(function() { | ||
reset(); | ||
}); | ||
describe('empty', function() { | ||
@@ -9,0 +5,0 @@ expect('', ''); |
@@ -1,8 +0,4 @@ | ||
require('./util'); | ||
'use strict'; | ||
describe('eval', function() { | ||
beforeEach(function() { | ||
reset(); | ||
}); | ||
describe('built-ins', function() { | ||
@@ -37,4 +33,3 @@ describe('len', function() { | ||
expect('{{ join(range(3)) }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ join(range(3)) }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ join(range(3)) }}', ''); | ||
}); | ||
@@ -47,8 +42,5 @@ | ||
expect('{{ reverse() }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ reverse() }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ reverse() }}', ''); | ||
expectError('{{ reverse(ten) }}', ''); | ||
expect('{{ reverse(ten) }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ reverse(ten) }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ reverse(foo) + foo }}', 'ooffoo'); | ||
@@ -63,15 +55,6 @@ }); | ||
expect('{{ sort(range(3), true) }}', '2,1,0'); | ||
expect('{{ sort(arr, true) }}', '4,3,2,1,0'); | ||
expect('{{ sort(rarr, true) }}', '9,8,4,3,2'); | ||
expect('{{ sort(hello, true) }}', 'roollledWH, '); | ||
expectError('{{ sort() }}', ''); | ||
expectError('{{ sort(ten) }}', ''); | ||
expect('{{ sort() }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ sort() }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ sort(ten) }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ sort(ten) }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ sort(hello) + hello }}', ' ,HWdellloorHello, World'); | ||
expect('{{ sort(hello,true) + hello }}', 'roollledWH, Hello, World'); | ||
}); | ||
@@ -90,7 +73,4 @@ | ||
expect('{{ slice(5) }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ slice(5) }}', function() { opt('throwsOnErrors', true); }); | ||
expect('{{ slice() }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ slice() }}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{{ slice(5) }}', ''); | ||
expectError('{{ slice() }}', ''); | ||
}); | ||
@@ -107,3 +87,3 @@ | ||
describe('isObject', function() { | ||
expect('{{ isObject(arr) }}', 'true'); | ||
expect('{{ isObject(arr) }}', 'false'); | ||
expect('{{ isObject(foo) }}', 'false'); | ||
@@ -115,12 +95,13 @@ expect('{{ isObject(a) }}', 'true'); | ||
describe('getAt', function() { | ||
expect('{{ getAt(arr, 2) }}', '2'); | ||
expect('{{ getAt("abcde", 3) }}', 'd'); | ||
expect('{{ getAt(a.b.c, 1) }}', 'b'); | ||
describe('get', function() { | ||
expect('{{ get(arr, 2) }}', '2'); | ||
expect('{{ get("abcde", 3) }}', 'd'); | ||
expect('{{ get(a.b.c, 1) }}', 'b'); | ||
expect('{{ getAt(arr, "2") }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ getAt(arr, "2") }}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{{ get(arr, "2") }}', ''); | ||
expectError('{{ get(a, 0) }}', ''); | ||
expect('{{ getAt(a, 0) }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ getAt(a, 0) }}', function() { opt('throwsOnErrors', true); }); | ||
expect('{{ get(a, ".b.c") }}', 'abc'); | ||
expect('{{ get(a.b, ".c") }}', 'abc'); | ||
expect('{{ get(a.b.c, 1) }}', 'b'); | ||
}); | ||
@@ -135,10 +116,5 @@ | ||
expect('{{ split("1,2,3", 1) }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ split("1,2,3", 1) }}', function() { opt('throwsOnErrors', true); }); | ||
expect('{{ split(arr, ",") }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ split(arr, ",") }}', function() { opt('throwsOnErrors', true); }); | ||
expect('{{ split(func1, ",") }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ split(func1, ",") }}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{{ split("1,2,3", 1) }}', ''); | ||
expectError('{{ split(arr, ",") }}', ''); | ||
expectError('{{ split(func1, ",") }}', ''); | ||
}); | ||
@@ -151,5 +127,2 @@ | ||
expect('{{ int("0.34") }}', '0'); | ||
expect('{{ int(arr) }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ int(arr) }}', function() { opt('throwsOnErrors', true); }); | ||
}); | ||
@@ -162,5 +135,2 @@ | ||
expect('{{ float("0.34") }}', '0.34'); | ||
expect('{{ float(arr) }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ float(arr) }}', function() { opt('throwsOnErrors', true); }); | ||
}); | ||
@@ -172,9 +142,7 @@ | ||
expect('{{ str(ten) }}', '10'); | ||
expect('{{ str(arr) }}', '0,1,2,3,4'); | ||
expect('{{ str(arr) }}', '[0,1,2,3,4]'); | ||
expect('{{ str(func1) }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ str(func1)) }}', function() { opt('throwsOnErrors', true); }); | ||
expect('{{ str(func1) }}', 'undefined'); | ||
expect('{{ str(a) }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ str(a)) }}', function() { opt('throwsOnErrors', true); }); | ||
expect('{{ str(a) }}', '{\"b\":{\"c\":\"abc\"}}'); | ||
}); | ||
@@ -188,6 +156,10 @@ | ||
describe('not builtins', function() { | ||
expect('{{ len2(foo) }}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{{ len2(foo) }}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{{ len2(foo) }}', ''); | ||
}); | ||
describe('some math functions', function() { | ||
expect('{{ math.min(4, 5) }}', '4'); | ||
expect('{{ math.max(4, 5) }}', '5'); | ||
}); | ||
}); | ||
}); |
@@ -1,8 +0,4 @@ | ||
require('./util'); | ||
'use strict'; | ||
describe('eval', function() { | ||
beforeEach(function() { | ||
reset(); | ||
}); | ||
describe('function', function() { | ||
@@ -18,12 +14,8 @@ describe('call', function() { | ||
describe('global functions', function() { | ||
expect('{{ Math.abs(-123) }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ Math.abs(-123) }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ process.memoryUsage() }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ process.memoryUsage() }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ JSON.parse("{}") }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ JSON.parse("{}") }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ parseInt("123") }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ parseInt("123") }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ Math.abs(-123) }}', ''); | ||
expectError('{{ process.memoryUsage() }}', ''); | ||
expectError('{{ JSON.parse("{}") }}', ''); | ||
expectError('{{ parseInt("123") }}', ''); | ||
}); | ||
}); | ||
}); |
@@ -1,8 +0,4 @@ | ||
require('./util'); | ||
'use strict'; | ||
describe('eval', function() { | ||
beforeEach(function() { | ||
reset(); | ||
}); | ||
describe('empty', function() { | ||
@@ -51,13 +47,9 @@ expect('{{}}', ''); | ||
expect('{{ \'foo\' }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ \'foo\' }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ \'foo\' }}', ''); | ||
}); | ||
describe('syntax error', function() { | ||
expect('{{ () }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ () }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ true false }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ true false }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ "foo" "bar" }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ "foo" "bar" }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ () }}', ''); | ||
expectError('{{ true false }}', ''); | ||
expectError('{{ "foo" "bar" }}', ''); | ||
}); | ||
@@ -108,4 +100,3 @@ }); | ||
expect('{{ "foo" == "bar" }}', 'false'); | ||
expect('{{ 1 === 2 }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ 1 === 2 }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ 1 === 2 }}', ''); | ||
}); | ||
@@ -119,4 +110,3 @@ | ||
expect('{{ "foo" != "bar" }}', 'true'); | ||
expect('{{ 1 !== 2 }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ 1 !== 2 }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ 1 !== 2 }}', ''); | ||
}); | ||
@@ -128,4 +118,3 @@ | ||
expect('{{ 3 > 2 }}', 'true'); | ||
expect('{{ 1 >> 2 }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ 1 >> 2 }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ 1 >> 2 }}', ''); | ||
}); | ||
@@ -137,4 +126,3 @@ | ||
expect('{{ 3 >= 2 }}', 'true'); | ||
expect('{{ 1 >>= 2 }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ 1 >>= 2 }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ 1 >>= 2 }}', ''); | ||
}); | ||
@@ -146,4 +134,3 @@ | ||
expect('{{ 3 < 2 }}', 'false'); | ||
expect('{{ 1 << 2 }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ 1 << 2 }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ 1 << 2 }}', ''); | ||
}); | ||
@@ -155,4 +142,3 @@ | ||
expect('{{ 3 <= 2 }}', 'false'); | ||
expect('{{ 1 <== 2 }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ 1 <== 2 }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ 1 <== 2 }}', ''); | ||
}); | ||
@@ -164,4 +150,3 @@ | ||
expect('{{ false && false }}', 'false'); | ||
expect('{{ true &&& true }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ true &&& true }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ true &&& true }}', ''); | ||
}); | ||
@@ -173,4 +158,3 @@ | ||
expect('{{ false || false }}', 'false'); | ||
expect('{{ true ||| true }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ true ||| true }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ true ||| true }}', ''); | ||
}); | ||
@@ -182,15 +166,11 @@ | ||
expect('{{ !!true }}', 'true'); | ||
expect('{{ true ! true }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ true ! true }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ true !! true }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ true !! true }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ true ! true }}', ''); | ||
expectError('{{ true !! true }}', ''); | ||
}); | ||
describe('other no-supports', function() { | ||
expect('{{ 1 <> 2 }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ 1 <> 2 }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ 1 !! 2 }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ 1 !! 2 }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ 1 <> 2 }}', ''); | ||
expectError('{{ 1 !! 2 }}', ''); | ||
}); | ||
}); | ||
}); |
@@ -1,9 +0,5 @@ | ||
require('./util'); | ||
'use strict'; | ||
describe('eval', function() { | ||
beforeEach(function() { | ||
reset(); | ||
}); | ||
describe('variables', function() { | ||
describe('variables', function() { | ||
expect('{{ foo }}', 'foo'); | ||
@@ -29,22 +25,18 @@ expect('{{ bar }}', 'Bar'); | ||
expect('{{ a. b .c }}', 'abc'); | ||
expect('{{ a..b }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ a..b }}', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ a.b..c }}', '', function() { opt('throwsOnErrors', false) }); | ||
expectException('{{ a.b..c }}', function() { opt('throwsOnErrors', true) }); | ||
expectError('{{ a..b }}', ''); | ||
expectError('{{ a.b..c }}', ''); | ||
}); | ||
describe('global variables', function() { | ||
expect('{{ Math.E }}', '', function() { opt('throwsOnErrors', false) }); | ||
expect('{{ Math.E }}', '', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ process.version }}', '', function() { opt('throwsOnErrors', false) }); | ||
expect('{{ process.version }}', '', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ __ctx }}', '', function() { opt('throwsOnErrors', false) }); | ||
expect('{{ __ctx }}', '', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ __builtin }}', '', function() { opt('throwsOnErrors', false) }); | ||
expect('{{ __builtin }}', '', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ NaN }}', '', function() { opt('throwsOnErrors', false) }); | ||
expect('{{ NaN }}', '', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ undefined }}', '', function() { opt('throwsOnErrors', false) }); | ||
expect('{{ undefined }}', '', function() { opt('throwsOnErrors', true) }); | ||
expect('{{ Math.E }}', ''); | ||
expect('{{ process.version }}', ''); | ||
expect('{{ __ctx }}', ''); | ||
expect('{{ __builtin }}', ''); | ||
expect('{{ NaN }}', ''); | ||
expect('{{ undefined }}', ''); | ||
}); | ||
describe('partial error', function() { | ||
expectError('{{ notDefined }} still {{ foo }}', ' still foo'); | ||
}); | ||
}); |
@@ -1,14 +0,11 @@ | ||
var t = require('../lib/wash'), | ||
expect = require('expect.js'); | ||
'use strict'; | ||
var wash = require('../lib/wash'); | ||
describe('precompile', function() { | ||
beforeEach(function() { | ||
reset(); | ||
}); | ||
it('simplest', function() { | ||
it('simplest', function() { | ||
var source = '{{ foo }}'; | ||
var ctx = { foo: 'bar' }; | ||
var precompiled = t.precompile(source); | ||
expect(t.render(source, ctx)).to.equal(t.render(precompiled, ctx)); | ||
var precompiled = wash.precompile(source); | ||
assert.strictEqual(wash.render(source, ctx), wash.render(precompiled, ctx)); | ||
}); | ||
@@ -19,14 +16,5 @@ | ||
var ctx = { foo: 5 }; | ||
var precompiled = t.precompile(source); | ||
expect(t.render(source, ctx)).to.equal(t.render(precompiled, ctx)); | ||
var precompiled = wash.precompile(source); | ||
assert.strictEqual(wash.render(source, ctx), wash.render(precompiled, ctx)); | ||
}); | ||
it('save and load', function() { | ||
var source = '{% for i in range(foo) %}{{ i }}{% endfor %}'; | ||
var ctx = { foo: 5 }; | ||
var precompiled = t.precompile(source); | ||
var saved = t.save(precompiled); | ||
var loaded = t.load(saved); | ||
expect(t.render(precompiled, ctx)).to.equal(t.render(loaded, ctx)); | ||
}); | ||
}); |
@@ -1,24 +0,15 @@ | ||
require('./util'); | ||
'use strict'; | ||
describe('safety', function() { | ||
beforeEach(function() { | ||
reset(); | ||
}); | ||
describe('call', function() { | ||
expectException('{{ arr.join.call(arr, ",") }}'); | ||
expectError('{{ arr.join.call(arr, ",") }}', ''); | ||
}); | ||
describe('apply', function() { | ||
expectException('{{ arr.concat.apply(arr, rarr) }}'); | ||
expectError('{{ arr.concat.apply(arr, rarr) }}', ''); | ||
}); | ||
describe('String', function() { | ||
//expect(''); | ||
}); | ||
describe('Array', function() { | ||
// arr.prototype ==> "" | ||
expect('{{ arr.prototype }}', ''); | ||
expectException('{{ arr.prototype.join(",") }}'); | ||
expectError('{{ arr.prototype.join(",") }}', ''); | ||
expect('{% for i in arr.prototype %}{{ i.value }}{% endfor %}', ''); | ||
@@ -30,3 +21,3 @@ }); | ||
expect('{{ __builtin }}', ''); | ||
expectException('{{ __builtin.len("123") }}'); | ||
expectError('{{ __builtin.len("123") }}', ''); | ||
}); | ||
@@ -38,7 +29,7 @@ | ||
expect('{{ __ctx.foo }}', ''); | ||
expectException('{{ __ctx.func1() }}'); | ||
expectError('{{ __ctx.func1() }}', ''); | ||
}); | ||
describe('while', function() { | ||
expectException('{{ while(true) {} }}'); | ||
expectError('{{ while(true) {} }}', ''); | ||
}); | ||
@@ -45,0 +36,0 @@ |
@@ -1,8 +0,4 @@ | ||
require('./util'); | ||
'use strict'; | ||
describe('for', function() { | ||
beforeEach(function() { | ||
reset(); | ||
}); | ||
describe('array', function() { | ||
@@ -40,36 +36,28 @@ expect('{% for i in arr %}{{ i.value }}{% endfor %}', '01234'); | ||
describe('max iterations', function () { | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', '0123456789', function() { opt('maximumIterations', -1); }); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', '0123456789', function() { opt('maximumIterations', 10); }); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', '01234', function() { opt('maximumIterations', 5); }); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', '01', function() { opt('maximumIterations', 2); }); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', '', function() { opt('maximumIterations', 0); }); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', '0123456789', function() { opt('maximumIterations', -1); }); | ||
expect('{% for i in "abcde" %}{{ i.value }}{% endfor %}', 'ab', function() { opt('maximumIterations', 2); }); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', { maximumIterations: -1 }, '0123456789'); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', { maximumIterations: 10 }, '0123456789'); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', { maximumIterations: 5 }, '01234'); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', { maximumIterations: 2 }, '01'); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', { maximumIterations: 0 }, ''); | ||
expect('{% for i in range(10) %}{{ i.value }}{% endfor %}', { maximumIterations: -1 }, '0123456789'); | ||
expect('{% for i in "abcde" %}{{ i.value }}{% endfor %}', { maximumIterations: 2 }, 'ab'); | ||
}); | ||
describe('errors', function() { | ||
expect('{% for i in %}{{ i.value }}{% endfor %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% for i in %}{{ i.value }}{% endfor %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% for i in %}{{ i.value }}{% endfor %}', ''); | ||
expect('{% for in range(4) %}{{ i.value }}{% endfor %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% for in range(4) %}{{ i.value }}{% endfor %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% for in range(4) %}{{ i.value }}{% endfor %}', ''); | ||
expect('{% for in %}{{ i.value }}{% endfor %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% for in %}{{ i.value }}{% endfor %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% for in %}{{ i.value }}{% endfor %}', ''); | ||
expect('{% for i range(4) %}{{ i.value }}{% endfor %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% for i range(4) %}{{ i.value }}{% endfor %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% for i range(4) %}{{ i.value }}{% endfor %}', ''); | ||
expect('{% for(i in range(4)) %}{{ i.value }}{% endfor %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% for(i in range(4)) %}{{ i.value }}{% endfor %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% for(i in range(4)) %}{{ i.value }}{% endfor %}', ''); | ||
expect('{% for (i) in range(4) %}{{ i.value }}{% endfor %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% for (i) in range(4) %}{{ i.value }}{% endfor %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% for (i) in range(4) %}{{ i.value }}{% endfor %}', ''); | ||
expect('{% for range(3) in range(4) %}{{ i.value }}{% endfor %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% for range(3) in range(4) %}{{ i.value }}{% endfor %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% for range(3) in range(4) %}{{ i.value }}{% endfor %}', ''); | ||
expect('{% for i in range(4) %}{% for j in range(3) %}{{ "" + i.value + j.value }}{% endfor %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% for i in range(4) %}{% for j in range(3) %}{{ "" + i.value + j.value }}{% endfor %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% for i in range(4) %}{% for j in range(3) %}{{ "" + i.value + j.value }}{% endfor %}', ''); | ||
}); | ||
}); |
@@ -1,8 +0,4 @@ | ||
require('./util'); | ||
'use strict'; | ||
describe('if', function() { | ||
beforeEach(function() { | ||
reset(); | ||
}); | ||
describe('basic', function() { | ||
@@ -59,11 +55,8 @@ expect('{% if true %}1{% endif %}', '1'); | ||
describe('errors', function() { | ||
expect('{% if true %}{% if true %}1{% endif %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% if true %}{% if true %}1{% endif %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% if true %}{% if true %}1{% endif %}', ''); | ||
expect('{% if %}1{% endif %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% if %}1{% endif %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% if %}1{% endif %}', ''); | ||
expect('{% if true %}1{% endif what %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% if true %}1{% endif what %}', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% if true %}1{% endif what %}', ''); | ||
}); | ||
}); |
@@ -1,8 +0,4 @@ | ||
require('./util'); | ||
'use strict'; | ||
describe('raw', function() { | ||
beforeEach(function() { | ||
reset(); | ||
}); | ||
describe('basic', function() { | ||
@@ -26,8 +22,6 @@ expect('{% raw %}foo{% endraw %}', 'foo'); | ||
describe('errors', function() { | ||
expect('{% raw %}foo', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% raw %}foo', function() { opt('throwsOnErrors', true); }); | ||
expectError('{% raw %}foo', ''); | ||
expect('{% raw %}{% raw %}foo{% endraw %}', '', function() { opt('throwsOnErrors', false); }); | ||
expectException('{% raw %}{% raw %}foo{% endraw %}', function() { opt('throwsOnErrors', true); }); | ||
}) | ||
expectError('{% raw %}{% raw %}foo{% endraw %}', ''); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
26
1
50565
1098
67
+ Addedlodash@2.4.1
+ Addedlodash@2.4.1(transitive)
- Removedunderscore@1.5.0
- Removedunderscore@1.5.0(transitive)