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
JavaScript
;
/**
* 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;