Comparing version 0.0.3 to 0.0.4
177
lib/wash.js
var _ = require('underscore'), | ||
format = require('util').format, | ||
precompiled = require('./precompiled'), | ||
builtins = require('./builtins'); | ||
/* | ||
{{ expr }} | ||
- evaluate expression. | ||
- does NOT allow access to varaibles outside the 'context'. | ||
- does NOT allow function calls outside the built-ins. | ||
- does allow math operators | ||
- does allow parenthesis to override precedences | ||
{% if(expr) %} ... {% endif %} | ||
{% if(expr) %} ... {% else %} ... {% endif %} | ||
{% if(expr) %} ... {% elif(expr) %} ... {% endif %} | ||
{% if(expr) %} ... {% elif(expr) %} ... {% else %} ... {% endif %} | ||
{% for it in iterable %} | ||
{{ it.key }} | ||
{{ it.value }} | ||
{{ it.index }} | ||
{% endloop %} | ||
Built-in functions | ||
range(start, stop, step) | ||
lower(str) | ||
upper(str) | ||
join(list, delim) | ||
len(list) | ||
reverse(list) | ||
sort(list, reverse) | ||
isArray(x) | ||
isObject(x) | ||
slice(arr, start, stop) | ||
*/ | ||
var _loop_counter = 0; | ||
function escapeStr(str) { | ||
@@ -48,28 +13,28 @@ return str.replace(/\\/gm, '\\\\').replace(/\n|\r/gm, '\\n').replace(/\"/gm, '\\"').replace(/\t/gm, '\\t'); | ||
var operators = ['+', '-', '*', '/', '==', '!=', '>=', '<=', '>', '<', '||', '&&', '!']; | ||
var evalRegex = /\{\{.*?\}\}/; | ||
var tagRegex = /\{%.*?%\}/; | ||
var captureRegex = new RegExp('('+evalRegex.source+'|'+tagRegex.source+')', 'gm'); | ||
var opsRegex = new RegExp('(' + _.map(operators, function(op) { return escapeRegex(op); }).join('|') + ')', 'g'); | ||
// eval split = operators + '(' + ')' + '"..."' + ',' | ||
var evalSplitterRegex = /(\+(?!\=)|\-(?!\=)|\*(?!\=)|\/(?!\=)|\=\=(?!\=)|\!\=(?!\=)|\>\=(?!\=)|\<\=(?!\=)|\>(?!\=)|\<(?!\=)|\|\||\&\&|\!(?!\=)|\".+?\"|\(|\)|,|\bif\b|\belse\b|\belif\b|\bendif\b|\bfor\b|\bin\b|\bendfor\b)/g; | ||
var operators = ['+', '-', '*', '/', '==', '!=', '>=', '<=', '>', '<', '||', '&&', '!']; | ||
function tokenize(expr) { | ||
// operators + "string" + comman, parenthesis | ||
// if, elif, else, endif | ||
// for, in, endfor | ||
var tokenSplitRegex = /(\+(?!\=)|\-(?!\=)|\*(?!\=)|\/(?!\=)|\=\=(?!\=)|\!\=(?!\=)|\>\=(?!\=)|\<\=(?!\=)|\>(?!\=)|\<(?!\=)|\|\||\&\&|\!(?!\=)|\".+?\"|\(|\)|,|\bif\b|\belse\b|\belif\b|\bendif\b|\bfor\b|\bin\b|\bendfor\b)/g; | ||
function tokenize(expr) { | ||
// tokenize and remove empty tokens | ||
var tokens = expr.split(evalSplitterRegex); | ||
var t = _.filter(_.map(tokens, function(token) { | ||
return token.trim(); | ||
}), function(token) { | ||
return token !== '' | ||
}); | ||
return t; | ||
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); } | ||
} | ||
return reduced; | ||
} | ||
function evalTokenSafe(expr, defVal) { | ||
defVal = (typeof defVal === 'undefined') ? '' : defVal; | ||
function evalTokenSafe(expr) { | ||
if(expr === '') { return ''; } | ||
if(expr === '') { return defVal; } | ||
expr = expr.split('.'); | ||
@@ -88,32 +53,16 @@ for(var i=0,len=expr.length; i<len; ++i) { | ||
var m = expr; | ||
var build = ''; | ||
build = '(typeof ' + c + ' !== "undefined"'; | ||
var build = '(typeof ' + c + ' !== "undefined"'; | ||
_.each(m, function (v, i) { | ||
if(i === 0) { return; } | ||
build += ' && ' + c + '.' + v + ' !== undefined'; | ||
c += '.' + v; | ||
if(i > 0) { | ||
build += ' && ' + c + '.' + v + ' !== undefined'; | ||
c += '.' + v; | ||
} | ||
}); | ||
build += ')'; | ||
return build; | ||
return build + ')'; | ||
} | ||
return '((' + _safe('__ctx.') + ') ? (' + '__ctx.' + expr.join('.') + ') : "' + defVal + '")'; | ||
return '((' + _safe('__ctx.') + ')?(__ctx.' + expr.join('.') + '):"")'; | ||
} | ||
function isConstant(token) { | ||
if(/^\".*\"$/.test(token)) { | ||
// string | ||
return true; | ||
} else if(!isNaN(token)) { | ||
// number | ||
return true; | ||
} else if(token === 'true' || token === 'false') { | ||
// boolean | ||
return true; | ||
} | ||
return false; | ||
} | ||
function findSub(tokens, idx, openStr, closeStr, nested) { | ||
@@ -153,4 +102,5 @@ nested = (typeof nested === 'undefined') ? true : nested; | ||
this.source = source; | ||
this.compiledCode = []; | ||
this._code = []; | ||
this._localVars = []; | ||
this._loop_counter = 0; | ||
} | ||
@@ -164,6 +114,4 @@ | ||
if(_.contains(operators, token)) { | ||
if(_.contains(operators, token) || /^\".*\"$|^true$|^false$|^-?\d*\.?\d+$/.test(token)) { | ||
outs.push(token); | ||
} else if(isConstant(token)) { | ||
outs.push(token); | ||
} else if(builtins.__containsName(token)) { | ||
@@ -182,3 +130,3 @@ var closeIdx = findSub(tokens, i, '(', ')'); | ||
} else { | ||
outs.push(token); | ||
outs.push(token); | ||
} | ||
@@ -210,6 +158,4 @@ } else { | ||
Wash.prototype._parseForTag = function(tokens) { | ||
var outs = []; | ||
var loopId = ++this._loop_counter; | ||
var loopId = ++_loop_counter; | ||
var it = tokens[1]; | ||
@@ -220,25 +166,12 @@ var iterable = this._evalTokens(tokens.slice(3)); | ||
// {% for it in iterable %} | ||
// -> | ||
// var __random_counter = 0; | ||
// var __random_object = (isArray((x)) ? toObject((x)) : (x); | ||
// for(var __random_key in __random_object) { | ||
// var it = { | ||
// key: __random_key, | ||
// value: __random_object[__random_key], | ||
// index: __random_counter | ||
// }; | ||
// __random__counter += 1; | ||
outs.push(format('var __cnt_%d = 0;\n', loopId)); | ||
outs.push(format('var __iterable_%d = %s;\n', loopId, iterable)) | ||
outs.push(format('var __obj_%d = __builtin.isArray(__iterable_%d) ? __builtin.__toObject(__iterable_%d) : __iterable_%d;\n', loopId, loopId, loopId, loopId)); | ||
outs.push(format('for(var __key_%d in __obj_%d) {\n', loopId, loopId)); | ||
outs.push(format('var %s = {\n', it)); | ||
outs.push(format('key: __key_%d,\n', loopId)); | ||
outs.push(format('value: __obj_%d[__key_%d],\n', loopId, loopId)); | ||
outs.push(format('index: __cnt_%d\n', loopId)); | ||
outs.push(format('};\n')); | ||
outs.push(format('__cnt_%d += 1;\n', loopId)); | ||
return outs.join(''); | ||
this._code.push('var __cnt_' + loopId + '=0;\n'); | ||
this._code.push('var __iterable_' + loopId + '=' + iterable + ';\n'); | ||
this._code.push('var __obj_' + loopId + '=__builtin.isArray(__iterable_' + loopId + ')?__builtin.__toObject(__iterable_' + loopId + '):__iterable_' + loopId + ';\n'); | ||
this._code.push('for(var __key_' + loopId + ' in __obj_' + loopId + '){\n'); | ||
this._code.push('var ' + it + '={\n'); | ||
this._code.push('key:__key_' + loopId + ',\n'); | ||
this._code.push('value:__obj_' + loopId + '[__key_' + loopId + '],\n'); | ||
this._code.push('index:__cnt_' + loopId + '\n'); | ||
this._code.push('};\n'); | ||
this._code.push('__cnt_' + loopId + '+=1;\n'); | ||
}; | ||
@@ -248,3 +181,2 @@ | ||
if(tokens.length) { | ||
var outs = []; | ||
var tagName = tokens[0]; | ||
@@ -255,7 +187,7 @@ | ||
var predExpr = this._evalTokens(tokens.slice(1)); | ||
outs.push('if('+predExpr+') {\n'); | ||
this._code.push('if('+predExpr+'){\n'); | ||
break; | ||
case 'elif': | ||
var predExpr = this._evalTokens(tokens.slice(1)); | ||
outs.push('} else if ('+predExpr+') {\n'); | ||
this._code.push('}else if('+predExpr+'){\n'); | ||
break; | ||
@@ -266,3 +198,3 @@ case 'else': | ||
} | ||
outs.push('} else {\n'); | ||
this._code.push('}else{\n'); | ||
break; | ||
@@ -273,6 +205,6 @@ case 'endif': | ||
} | ||
outs.push('}\n'); | ||
this._code.push('}\n'); | ||
break; | ||
case 'for': | ||
outs.push(this._parseForTag(tokens)); | ||
this._parseForTag(tokens); | ||
break; | ||
@@ -284,3 +216,3 @@ case 'endfor': | ||
this._localVars.pop(); | ||
outs.push('}\n'); | ||
this._code.push('}\n'); | ||
break; | ||
@@ -290,6 +222,2 @@ default: | ||
} | ||
return outs.join(''); | ||
} else { | ||
return ''; | ||
} | ||
@@ -301,3 +229,3 @@ }; | ||
this.compiledCode.push('__out = "";\n'); | ||
this._code.push('__out="";\n'); | ||
@@ -314,3 +242,3 @@ for(var i=0,len=tokens.length; i<len; ++i) { | ||
if(output) { | ||
this.compiledCode.push('__out += ' + output + ';\n'); | ||
this._code.push('__out+=' + output + ';\n'); | ||
} | ||
@@ -321,17 +249,14 @@ } | ||
if(expr) { | ||
var output = this._parseTag(tokenize(expr)); | ||
if(output) { | ||
this.compiledCode.push(output); | ||
} | ||
this._parseTag(tokenize(expr)); | ||
} | ||
} else { | ||
this.compiledCode.push('__out += "'+escapeStr(token)+'";\n'); | ||
this._code.push('__out+="'+escapeStr(token)+'";\n'); | ||
} | ||
} | ||
this.compiledCode.push('return __out;'); | ||
this._code.push('return __out;'); | ||
return new precompiled(this.compiledCode.join('')); | ||
return new precompiled(this._code.join('')); | ||
}; | ||
exports = module.exports = Wash; |
{ | ||
"name": "wash", | ||
"description": "a safe template rendering engine", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"main": "index", | ||
@@ -33,4 +33,4 @@ "author": { | ||
"scripts": { | ||
"test": "node_modules/.bin/mocha tests --reporter spec" | ||
"test": "node_modules/.bin/mocha --reporter spec" | ||
} | ||
} |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
57118
14
1157
2