To practice with regular expressions, I wrote this basic template engine in JavaScript in addition to a simple test case to make sure it works correctly.
I am wondering if there is any improvements I can do or if I am correctly following JavaScript coding style and conventions. Thanks in advance.
In short,
- {{= expression}} --> evaluates expression (context is optional)
- {{0}} --> evaluates based on given array index
- {{name}} --> evaluates based on given json values
Template code (does not require any dependency):
(function() {
this.amirTemplateEngine = function() {
var self = this;
var _tokensToReplace, _values, _array;
// evaluate in-line expressions
self.evaluateString = function(string, options) {
_tokensToReplace = string.match(new RegExp(/({{=[^}]*}})/g)) || [];
_tokensToReplace.map(function(token) {
string = string.replace(token, (function() {
return eval(token.replace("{{=", "").replace("}}", ""));
}).call(options && options.context ? options.context : self));
});
return string;
};
// replace given object
self.replaceGivenObject = function(string, options) {
_values = options && options.values ? options.values : {};
_tokensToReplace = string.match(new RegExp(/({{[ ]*[^}.]+[ ]*}})/g)) || [];
_tokensToReplace.map(function(token) {
string = string.replace(token, _values[token.replace(" ", "").replace("{{", "").replace("}}", "")]);
});
return string;
};
// replace given array index
self.replaceGivenArray = function(string, options) {
_array = options && options.array ? options.array : {};
_tokensToReplace = string.match(new RegExp(/({{[ ]*[0-9]+[ ]*}})/g)) || [];
_tokensToReplace.map(function(token) {
string = string.replace(token, _array[parseInt(token.replace(" ", "").replace("{{", "").replace("}}", ""))]);
});
return string;
};
// helper function
self.format = function(string, options) {
// evaluate expressions
string = self.evaluateString(string, options);
// if options.array is defined, then evaluate template
string = self.replaceGivenArray(string, options);
// if options.values is defined, then evaluate template
string = self.replaceGivenObject(string, options);
return string;
};
// for chainability
return self;
};
})();
Testing the code (making sure output is correct):
var template = require('./amir-template-engine');
(function() {
var self = this;
something = "something else!";
var template = "\
<h2 class='{{= (true).toString()}}'>{{0}} {{1}} {{2}}</h2>\
<p>{{= 4 > 0 ? 'good' : 'bad'}}</p>\
<p>{{= something }}</p>\
<p>{{name}}</p>\
";
var result = "\
<h2 class='true'>seyed amir hossein</h2>\
<p>good</p>\
<p>something else!</p>\
<p>amir</p>\
";
var templateObj = new amirTemplateEngine();
testResult = templateObj.format(template, {
array: ["seyed", "amir", "hossein"],
values: {
name: "amir"
},
context: self
}) == result;
console.log("Test is" + (testResult ? "" : " NOT") + " passing!");
})();