fs.readFile(fileName, "utf8", function(err, buffer) { // Pass up any errors. if (err) { return next(err); } // Send back the compiled template. var template = combyne(String(buffer)); // Find all extend. var extend = visitCombyne(template.tree.nodes, function(node) { return node.type === "ExtendExpression"; }).map(function(node) { return node.value; }); // Find all partials. var partials = visitCombyne(template.tree.nodes, function(node) { return node.type === "PartialExpression" && noParse !== node.value; }).map(function(node) { return node.value; }); // Find all filters. var filters = visitCombyne(template.tree.nodes, function(node) { return node.filters && node.filters.length; }).map(function(node) { return node.filters.map(function(filter) { return filter.value; }).join(" "); }); // Flatten the array. if (filters.length) { filters = filters.join(" ").split(" "); } // Map all extend to functions. extend = extend.map(function(render) { return function(callback) { var name = render.template; var renderPath = path.join(dirname, name + ext); // The last argument of this call is the noparse option that specifies // the virtual partial should not be loaded. processTemplate.call(route, renderPath, data, function(err, render) { if (err) { return callback(err); } template.registerPartial(name, render); callback(err, template); }, render.partial); }; }); // Map all partials to functions. partials = partials.map(function(name) { return function(callback) { // Ignore those that have already been defined globally. if (name in settings._partials) { return callback(); } var partialPath = path.join(dirname, name + ext); processTemplate.call(route, partialPath, data, function(err, partial) { if (err) { return callback(err); } template.registerPartial(name, partial); settings._partials[name] = partial; callback(err, template); }); }; }); // Map all filters to functions. filters = filters.map(function(name) { // Filters cannot be so easily inferred location-wise, so assume they are // preconfigured or exist in a filters directory. return function(callback) { var filtersDir = settings.filtersDir || "filters"; var filtersPath = path.join(dirname, filtersDir, name + ".js"); // Ignore those that have already been defined globally. if (name in settings._filters) { return callback(); } try { var filter = require(filtersPath); // Register the exported function. settings._filters[name] = filter; } catch (ex) { return callback(ex); } callback(null, filter); }; }); // Find all files and map the partials. async.parallel(partials.concat(extend, filters), function(err) { if (err) { return next(err); } // Register all the global partials. Object.keys(settings._partials).forEach(function(name) { var partial = settings._partials[name]; template.registerPartial(name, partial); }); // Register all the global filters. Object.keys(settings._filters).forEach(function(name) { var filter = settings._filters[name]; template.registerFilter(name, filter); }); // Render the template. next(err, template); }); });
var processTemplate = function(templateSource, settings, callback) { var root = settings.root; var template = combyne(templateSource); var extension = settings.extension || '.html'; // Find all extend. var extend = visitCombyne(template.tree.nodes, function(node) { return node.type === 'ExtendExpression'; }).map(function(node) { return node.value; }); // Find all partials. var partials = visitCombyne(template.tree.nodes, function(node) { return node.type === 'PartialExpression' && !extendsCache[node.value]; }).map(function(node) { return node.value; }); // Find all filters. var filters = visitCombyne(template.tree.nodes, function(node) { return node.filters && node.filters.length; }).map(function(node) { return node.filters.map(function(filter) { return filter.value; }).join(' '); }); // Flatten the array. if (filters.length) { filters = filters.join(' ').split(' '); } // Filters cannot be so easily inferred location-wise, so assume they are // preconfigured or exist in a filters directory. var filtersDir = settings.filtersDir || 'filters'; filters.forEach(function(filterName) { // Register the exported function. template._filters[filterName] = path.join(root, filtersDir, filterName); }); // Map all partials to functions. partials.forEach(function(name) { template._partials[name] = path.resolve(path.join(root, name + extension)); }); // Map all extend to functions. extend.forEach(function(render) { var name = render.template; var superTemplate = path.resolve(path.join(root, name + extension)); // Pre-cache this template. extendsCache[render.partial] = true; // Set the partial to the super template. template._partials[name] = superTemplate; }); // Augment the template source to include dependencies. var lines = template.source.split('\n'); partials = Object.keys(template._partials).map(function(name) { return '"' + name + '": require("' + template._partials[name] + '")'; }); filters = Object.keys(template._filters).map(function(name) { return '"' + name + '": require("' + template._filters[name] + '")'; }); // This replaces the partials and filters inline. lines[1] = '_partials: {' + partials.join(',') + '},'; lines[2] = '_filters: {' + filters.join(',') + '},'; // Flatten the template to remove unnecessary `\n` whitespace. template.source = lines.join('\n'); if (this.push) { this.push('module.exports = ' + template.source); } callback.call(this, template); };
xhr.onreadystatechange = function() { if (xhr.readyState === 4) { var template = combyne(xhr.responseText); // Find all extend. var extend = recurse(template.tree.nodes, function(node) { return node.type === 'ExtendExpression'; }).map(function(node) { return node.value; }); // Find all partials. var partials = recurse(template.tree.nodes, function(node) { return node.type === 'PartialExpression' && !extendsCache[node.value]; }).map(function(node) { return node.value; }); // Find all filters. var filters = recurse(template.tree.nodes, function(node) { return node.filters && node.filters.length; }).map(function(node) { return node.filters.map(function(filter) { return filter.value; }).join(' '); }); // Flatten the array. if (filters.length) { filters = filters.join(' ').split(' '); } // Map all filters to functions. filters = filters.map(function(filterName) { // Filters cannot be so easily inferred location-wise, so assume they are // preconfigured or exist in a filters directory. var filtersDir = settings.filtersDir || 'filters'; var filtersPath = root + filtersDir + '/' + filterName; return new Promise(function(resolve) { require([filtersPath + '.js'], function(filter) { // Register the exported function. template.registerFilter(filterName, filter); resolve(filter); }); }); }); // Process as a Lo-Dash template and cache. buildMap[name] = template; // Wait for all filters, then partials, and finally extends to load and // then pass back control. Promise.all(filters).then(function(filters) { // Map all partials to functions. partials = partials.map(function(name) { return new Promise(function(resolve, reject) { // The last argument of this call is the noparse option that // specifies the virtual partial should not be loaded. require([root + name + '.html'], function(render) { template.registerPartial(name, render); resolve(render); }); }); }); return Promise.all(partials); }).then(function() { // Map all extend to functions. var list = extend.map(function(render) { return new Promise(function(resolve, reject) { var name = render.template; // Pre-cache this template. extendsCache[render.partial] = true; // The last argument of this call is the noparse option that // specifies the virtual partial should not be loaded. require([root + name + '.html'], function(tmpl) { tmpl.registerPartial(render.partial, template); template.registerPartial(name, tmpl); resolve(tmpl); }); }); }); return Promise.all(list); }).then(function() { // Return the compiled template. load(template); }); } };