|
|
@@ -0,0 +1,102 @@ |
|
|
|
var regStr = "{{(.+)}}"; |
|
|
|
var localRegex = new RegExp(regStr); |
|
|
|
var globalRegex = new RegExp(regStr, "g"); |
|
|
|
|
|
|
|
function hasMultipleStatements(str) { |
|
|
|
return (str.indexOf(";") !== -1) |
|
|
|
} |
|
|
|
|
|
|
|
function Func(args) { |
|
|
|
return Function.apply(this, args); |
|
|
|
} |
|
|
|
Func.prototype = Function.prototype; |
|
|
|
|
|
|
|
module.exports = function(str, vals) { |
|
|
|
str = str.replace(/\s+/g, " ").replace(/}}/g, "}}\n"); |
|
|
|
this.string = str; |
|
|
|
this.vals = vals; |
|
|
|
this.subs = []; |
|
|
|
|
|
|
|
var matches = str.match(globalRegex); |
|
|
|
|
|
|
|
if (!matches) |
|
|
|
return; |
|
|
|
|
|
|
|
matches.forEach(function(m) { |
|
|
|
var str = m.match(localRegex)[1]; |
|
|
|
|
|
|
|
//Add user defined arguments |
|
|
|
var args = []; |
|
|
|
vals.forEach(function(v) { |
|
|
|
args.push(v); |
|
|
|
}); |
|
|
|
|
|
|
|
//We also need a callback function, for async things |
|
|
|
args.push("cb"); |
|
|
|
|
|
|
|
//We want to automatically return if there's only one statement |
|
|
|
if (hasMultipleStatements(str)) |
|
|
|
args.push(str); |
|
|
|
else |
|
|
|
args.push("return ("+str+")"); |
|
|
|
|
|
|
|
this.subs.push({ |
|
|
|
func: new Func(args), |
|
|
|
match: m+"\n" |
|
|
|
}); |
|
|
|
}.bind(this)); |
|
|
|
} |
|
|
|
|
|
|
|
module.exports.prototype.exec = function(vals, cb) { |
|
|
|
var str = this.string; |
|
|
|
|
|
|
|
//Prepare generic arguments |
|
|
|
var args = []; |
|
|
|
for (var i in vals) { |
|
|
|
var index = this.vals.indexOf(i); |
|
|
|
|
|
|
|
if (index === -1) |
|
|
|
throw new Error("Error: argument "+i+" doesn't exist"); |
|
|
|
|
|
|
|
args[index] = vals[i]; |
|
|
|
} |
|
|
|
|
|
|
|
var numArgs = args.length; |
|
|
|
|
|
|
|
//Keep track of how many callbacks we're waiting for |
|
|
|
var cbsRemaining = this.subs.length; |
|
|
|
|
|
|
|
//Replace |
|
|
|
this.subs.forEach(function(sub, i) { |
|
|
|
|
|
|
|
//Create a callback function for each substitute |
|
|
|
args[numArgs] = function(err, res) { |
|
|
|
if (err) |
|
|
|
throw err; |
|
|
|
|
|
|
|
str = str.replace(sub.match, res); |
|
|
|
|
|
|
|
//If this is the last callback to be executed, |
|
|
|
//call back with the resulting string |
|
|
|
if (cbsRemaining <= 0) |
|
|
|
cb(str); |
|
|
|
cbsRemaining -= 1; |
|
|
|
} |
|
|
|
|
|
|
|
var ret = sub.func.apply(null, args); |
|
|
|
|
|
|
|
//If the substitute's function returns anything, we use that directly, |
|
|
|
//but if it doesn't, we wait for a callback |
|
|
|
if (ret !== undefined) { |
|
|
|
str = str.replace(sub.match, ret); |
|
|
|
if (cbsRemaining <= 0) |
|
|
|
cb(str); |
|
|
|
cbsRemaining -= 1; |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
//If there's no asynchronous functions to wait for, |
|
|
|
//just call back immediately |
|
|
|
if (cbsRemaining === 0) |
|
|
|
return cb(str); |
|
|
|
} |