var render = (function () { var exports = {}; var fs = require('fs'); var _ = require('node_modules/underscore/underscore.js'); var Handlebars = require('handlebars'); function template_dir() { return __dirname + '/../../static/templates/'; } exports.init = function () { Handlebars.templates = {}; }; exports.make_sure_all_templates_have_been_compiled = function () { var files = exports.template_finder.get_all(); _.each(files, function (file) { if (!Handlebars.templates[file.name]) { throw "The file " + file.url + " has no test coverage."; } }); }; exports.render_template = function (name, args) { exports.compile_template(name); return global.templates.render(name, args); }; exports.compile_template = function (name) { var included_fns = exports.find_included_partials(name); _.each(included_fns, function (fn) { exports.compile_template(fn); }); if (Handlebars.templates === undefined) { Handlebars.templates = {}; } if (_.has(Handlebars.template, name)) { // we already compile the template return; } var file = exports.template_finder.get(name); var data = fs.readFileSync(file.url).toString(); Handlebars.templates[name] = Handlebars.compile(data); }; // list all files in a directory and it's subdirectories in a recursive sync way. exports.walk = function (dir, filelist) { filelist = filelist || []; // grab files one level deep. var files = fs.readdirSync(dir); // for each file, check if it's a directory. If so, continue recursion. // if not add to the file list. files.forEach(function (file) { if (fs.statSync(dir + "/" + file).isDirectory()) { filelist = exports.walk(dir + "/" + file, filelist); } else { filelist.push({ url: dir + "/" + file, name: file, }); } }); // return all recursively found files. return filelist; }; exports.template_finder = (function () { // This class lets you find template files in our file system. // It may be slightly overkill for our flat directory system; // it might make more sense to just do something more like // this: get_template_dir() + name + '.handlebars' var self = {}; // get all files and then map them into friendlier names. var all_files = exports.walk(template_dir()); var files = all_files .filter(function (file) { return (/\.handlebars$/).test(file.name); }) .map(function (file) { return { url: file.url, name: file.name.replace(/\.handlebars$/, ""), }; }); self.get = function (name) { var file = files.find(function (file) { return file.name === name; }); assert(file); return file; }; self.get_all = function () { return files; }; return self; }()); exports.find_included_partials = function (name) { var file = exports.template_finder.get(name); assert(file); var template = fs.readFileSync(file.url, "utf8"); var lst = []; // match partial tags. // this uses String.prototype.replace which is kind of hacky but // it is the only JS function IIRC that allows you to match all // instances of a pattern AND return capture groups. template.replace(/\{\{\s*partial\s*"(.+?)"/ig, function (match, $1) { lst.push($1); }); return lst; }; return exports; }()); module.exports = render;