UNPKG

engine-lodash

Version:

Lo-Dash engine, consolidate.js style but with enhancements. Works with Assemble, express.js, engine-cache or any application that follows consolidate.js conventions.

249 lines (211 loc) 5.81 kB
'use strict'; /** * Module dependencies. */ var fs = require('fs'); var lazy = require('lazy-cache')(require); lazy('ansi-red', 'red'); lazy('delimiter-regex', 'delimiters'); lazy('engine-utils', 'utils'); lazy('lodash', '_'); /** * Lodash support. */ var engine = lazy.utils.fromStringRenderer('lodash'); /** * Expose this instance of lodash. To keep it "lazy" * it must be called necessary to access the instance. */ engine.lodash = function () { return lazy._; }; /** * expose engine `defaults` */ engine.options = { name: 'lodash', dest: {ext: '.html'}, }; /** * Lodash string support. Render the given `str` and invoke the callback `callback(err, str)`. * * ```js * var engine = require('engine-lodash'); * engine.render('<%= name %>', {name: 'Jon'}, function (err, content) { * console.log(content); //=> 'Jon' * }); * ``` * * @param {String} `str` * @param {Object|Function} `options` or callback. * @property {Object} `cache` enable template caching * @property {String} `filename` filename required for caching * @param {Function} `callback` * @api public */ engine.render = function lodashRender(fn, options, cb) { if (typeof options === 'function') { cb = options; options = {}; } options = options || {}; if (typeof fn === 'string') { fn = engine.compile(fn, options); } try { cb(null, engine.renderSync(fn, options)); } catch (err) { return cb(err); } }; /** * Return a compiled function from the given template * `string` and `options`. * * @param {String} `str` Template string to compile. * @param {Object} `options` Options or settings to pass to lodash * @param {Function} `cb` Callback function * @return {Function} */ engine.compile = function lodashCompile(str, options, cb) { if (typeof options === 'function') { cb = options; options = {}; } try { if (typeof cb !== 'function') { cb = function callback(err, fn) { if (err) throw err; return fn; }; } options = options || {}; options.settings = options.settings || {}; var settings = {}; if (options.mixins) { lazy._.mixin(options.mixins); } var picked = lazy._.merge(pick(options), pick(options.settings)); var delims = picked.delims; var opts = picked.opts; var fns = picked.fns; settings.imports = lazy._.merge({}, fns.helpers, fns.imports); settings = lazy._.merge({}, settings, delims); if (options.debugEngine) { inspectHelpers(settings, opts); } return cb(null, lazy._.template(str, settings)); } catch (err) { return cb(err); } }; /** * Render Lo-Dash or underscore templates synchronously. * * ```js * var engine = require('engine-lodash'); * engine.renderSync('<%= name %>', {name: 'Halle'}); * //=> 'Halle' * ``` * * @param {Object} `str` The string to render. * @param {Object} `options` Object of options. * @option {Object} `settings` Settings to pass to Lo-Dash. * @option {Arrary} `delims` Template delimiters, generated by [delimiter-regex] * @option {Object} `imports` Template helpers to pass to Lo-Dash. * @return {String} Rendered string. * @api public */ engine.renderSync = function lodashRenderSync(fn, options) { var context = lazy._.extend({}, options); options = options || {}; if (typeof fn === 'string') { context = lazy._.omit(options, ['helpers', 'imports']); fn = engine.compile(fn, options); } try { return fn(context); } catch (err) { return err; } }; /** * Lodash file support. Render a file at the given `filepath` and callback `callback(err, str)`. * * ```js * var engine = require('engine-lodash'); * engine.renderFile('foo/bar/baz.tmpl', {name: 'Halle'}); * //=> 'Halle' * ``` * * @param {String} `path` * @param {Object|Function} `options` or callback function. * @param {Function} `callback` * @api public */ engine.renderFile = function lodashRenderFile(filepath, options, cb) { if (typeof options === 'function') { cb = options; options = {}; } try { return engine.render(fs.readFileSync(filepath, 'utf8'), options, cb); } catch (err) { return cb(err); } }; /** * Handle custom delimiters */ function delimsObject(delims) { var a = delims[0], b = delims[1]; var res = {}; res.interpolate = lazy.delimiters(a + '=', b); res.evaluate = lazy.delimiters(a, b); res.escape = lazy.delimiters(a + '-', b); return res; } /** * Inspect helpers if `debugEngine` is enabled */ function inspectHelpers(settings, opts) { var helpers = Object.keys(settings.imports); for (var key in opts) { if (helpers.indexOf(key) !== -1) { conflictMessage(settings, opts, key); } } } /** * Conflict report displayed when the same key exists as both * a helper name and the key of a (data) property on the context. */ function conflictMessage(settings, options, key) { console.error(lazy.red('engine-lodash: Error: property "' + key + '" is on both:')); var type = (typeof settings.imports[key]); console.error(lazy.red(' - settings.imports as ' + article(type) + ': ' + type)); type = (typeof options[key]); console.error(lazy.red(' - options as ' + article(type) + ': ' + type)); } function article(word) { var n = /^[aeiou]/.test(word); return n ? 'an' : 'a'; } function pick(obj) { var res = {}; res.delims = lazy._.pick(obj, ['interpolate', 'evaluate', 'escape']); res.opts = lazy._.omit(obj, ['helpers', 'imports']); res.fns = lazy._.pick(obj, ['helpers', 'imports']); if (Array.isArray(obj.delims)) { res.delims = lazy._.merge({}, delimsObject(obj.delims), res.delims); } return res; } /** * Express support. */ engine.__express = engine.renderFile; /** * Expose `engine` */ module.exports = engine;