UNPKG

adapter-template

Version:

Adapters to standardise the interfaces on the plethora of available templating engines.

188 lines (146 loc) 5.13 kB
exports.name = 'adapter-base-render'; var _ = require('lodash'); var frontMatter = require('front-matter'); var searchFile = require('./searchFile'); exports.attach = function(/* options */){ var self = this; /** * This plugin requires that a template engine plugin has already * been loaded: */ if (!self.engine){ throw new Error('A template engine is required.'); } /** * If there is no render function then create one: */ if (!self.render){ self.render = function (str, _options, callback){ var options = _.cloneDeep(_options); /** * If there is any front matter then see if it contains a layout template: */ if (frontMatter.test(str)) { var content = frontMatter(str); if (content.attributes && content.attributes.layout) { /** * If we do have a layout then we pass the content of this current * file as the special local variable 'content' and then run it * through renderFile(): */ var tempOptions = _.cloneDeep(options); options.locals = options.locals || {}; options.locals.content = content.body; self.renderFile(content.attributes.layout + '.html', options, function(err, html) { self.render(html, tempOptions, callback); }) } } else { // try{ var context = self.engine.newContext(); /** * Note that there's a bug in the library that doesn't allow us to pass * the locals to newContext(), hence looping through the keys: */ if (options.locals){ Object.keys(options.locals).forEach(function (local){ context.setLocals(local, options.locals[local]); }); delete options.locals; } if (options.meta){ context.setLocals('page', options.meta); delete options.meta; } /** * Attach the relevant filter functions: */ var facade = require('adapter-filters'); var filters = facade(self.filters, options); Object.keys(filters).forEach(function (filter){ context.setFilter(filter, filters[ filter ]); }); if ('filters' in options){ Object.keys(options.filters).forEach(function (filter){ context.setFilter(filter, options.filters[ filter ]); }); delete options.filters; } /** * Set up a callback for the include directory: */ var includeDirList = options.includeDir || process.cwd(); delete options.includeDir; var path = require('path'); var fs = require('fs'); if (!Array.isArray(includeDirList)) { includeDirList = [includeDirList]; } var newList = []; includeDirList.forEach(function(includeDir) { newList.push(path.join(includeDir, 'liquid')); newList.push(includeDir); }); context.onInclude(function (name, callback) { var extname = path.extname(name) === '' ? '.liquid' : ''; searchFile(name + extname, newList, function(err, data) { if (err) { return callback('Failed to find partial: ' + err); } callback(null, self.engine.parse(data)); }); }); /** * The custom tag functions need to have their results pushed back * through the parser, so set up a shim before calling the provided * callback: */ var compileOptions = { customTags: {} }; if (options.customTags){ var tagFunctions = options.customTags; Object.keys(options.customTags).forEach(function (customTag){ /*Tell jshint there's no problem with having this function in the loop */ /*jshint -W083 */ compileOptions.customTags[customTag] = function (context, name, body){ var tpl = tagFunctions[name](body.trim()); context.astStack.push(self.engine.parse(tpl)); }; /*jshint +W083 */ }); delete options.customTags; } var tmpl = self.engine.compile(str, compileOptions); for (var k in options){ context.setLocals(k, options[k]); } tmpl(context, callback); // }catch(err){ // callback(err); // } } }; } /** * If the render function that has been provided by the engine is * synchronous then we need to wrap it: */ if (self.languageConfig.sync){ var syncFn = self.render; self.render = function (str, options, callback){ callback(null, syncFn(str, options)); }; } /** * If the locals passed in need moving to a new location then do it: */ if (self.languageConfig.moveLocals){ var renderFn = self.render; self.render = function (str, options, callback){ var context = {}; context[self.languageConfig.moveLocals] = options; renderFn(str, context, callback); }; } };