|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- var regStr = "{{(.+)}}";
- var localRegex = new RegExp(regStr);
- var globalRegex = new RegExp(regStr, "g");
-
- function expectType(type, val) {
- if (typeof val !== type)
- throw new TypeError("Expected "+type+", got "+typeof val);
- }
-
- function expectInstance(obj, val) {
- if (!(val instanceof obj)) {
- var regex = /function (.+)\(/;
- var expectedName = obj.toString().match(regex)[1];
-
- try {
- var realName = val.constructor.toString().match(regex)[1];
- } catch (err) {
- var realName = "undefined";
- }
-
- throw new TypeError("Expected "+expectedName+", got "+realName);
- }
- }
-
- function hasMultipleStatements(str) {
- return (str.indexOf(";") !== -1)
- }
-
- function Func(args) {
- return Function.apply(this, args);
- }
- Func.prototype = Function.prototype;
-
- function Templish(str, vals) {
- expectType("string", str);
- expectInstance(Array, 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));
- }
-
- Templish.prototype.exec = function(vals, cb) {
- expectInstance(Object, vals);
- expectType("function", 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(null, 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(null, str);
- }
-
- module.exports = Templish;
|