forked from enviPath/enviPy
223 lines
5.2 KiB
JavaScript
223 lines
5.2 KiB
JavaScript
'use strict';
|
|
|
|
var fs = require('fs');
|
|
var path = require('path');
|
|
var assign = require('object-assign');
|
|
var requireGlob = require('require-glob');
|
|
|
|
var toString = Object.prototype.toString;
|
|
|
|
var ESCAPE_CHARACTERS = /[-\/\\^$*+?.()|[\]{}]/g;
|
|
var NON_WORD_CHARACTERS = /\W+/g;
|
|
var PATH_SEPARATOR = '/';
|
|
var PATH_SEPARATORS = /[\\\/]/g;
|
|
var WHITESPACE_CHARACTERS = /\s+/g;
|
|
var WORD_SEPARATOR = '-';
|
|
var TYPE_FUNCTION = 'fun';
|
|
var TYPE_OBJECT = 'obj';
|
|
|
|
// Utilities
|
|
|
|
function escapeRx(str) {
|
|
return str.replace(ESCAPE_CHARACTERS, '\\$&');
|
|
}
|
|
|
|
function getTypeOf(value) {
|
|
return toString
|
|
.call(value)
|
|
.substr(8, 3)
|
|
.toLowerCase();
|
|
}
|
|
|
|
function hookRequire(handlebars) {
|
|
var extLong = require.extensions['.handlebars'];
|
|
var extShort = require.extensions['.hbs'];
|
|
|
|
function extensions(module, filename) {
|
|
var templateString = fs.readFileSync(filename, 'utf8');
|
|
|
|
module.exports = handlebars.compile(templateString);
|
|
}
|
|
|
|
require.extensions['.handlebars'] = extensions;
|
|
require.extensions['.hbs'] = extensions;
|
|
|
|
return function unhookRequire() {
|
|
require.extensions['.handlebars'] = extLong;
|
|
require.extensions['.hbs'] = extShort;
|
|
};
|
|
}
|
|
|
|
// Map Reduce
|
|
|
|
function keygenPartial(options, file) {
|
|
var resolvedFilePath = fs.realpathSync(file.path);
|
|
var resolvedFileBase = fs.realpathSync(file.base);
|
|
|
|
var fullPath = resolvedFilePath.replace(PATH_SEPARATORS, PATH_SEPARATOR);
|
|
var basePath = resolvedFileBase.replace(PATH_SEPARATORS, PATH_SEPARATOR) + PATH_SEPARATOR;
|
|
var shortPath = fullPath.replace(new RegExp('^' + escapeRx(basePath), 'i'), '');
|
|
var extension = path.extname(shortPath);
|
|
|
|
return shortPath
|
|
.substr(0, shortPath.length - extension.length)
|
|
.replace(WHITESPACE_CHARACTERS, WORD_SEPARATOR);
|
|
}
|
|
|
|
function keygenHelper(options, file) {
|
|
return keygenPartial(options, file)
|
|
.replace(NON_WORD_CHARACTERS, WORD_SEPARATOR);
|
|
}
|
|
|
|
function keygenDecorator(options, file) {
|
|
return keygenHelper(options, file);
|
|
}
|
|
|
|
function reducer(options, obj, fileObj) {
|
|
var value = fileObj.exports;
|
|
|
|
if (!value) {
|
|
return obj;
|
|
}
|
|
|
|
if (getTypeOf(value.register) === TYPE_FUNCTION) {
|
|
value = value.register(options.handlebars, options);
|
|
|
|
if (getTypeOf(value) === TYPE_OBJECT) {
|
|
return assign(obj, value);
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
if (getTypeOf(value) === TYPE_OBJECT) {
|
|
return assign(obj, value);
|
|
}
|
|
|
|
obj[options.keygen(fileObj)] = value;
|
|
|
|
return obj;
|
|
}
|
|
|
|
function resolveValue(options, value) {
|
|
if (!value) {
|
|
return {};
|
|
}
|
|
|
|
if (getTypeOf(value) === TYPE_FUNCTION) {
|
|
value = value(options.handlebars, options);
|
|
|
|
if (getTypeOf(value) === TYPE_OBJECT) {
|
|
return value;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
if (getTypeOf(value) === TYPE_OBJECT) {
|
|
return reducer(options, {}, { exports: value });
|
|
}
|
|
|
|
return requireGlob.sync(value, options);
|
|
}
|
|
|
|
// Wax
|
|
|
|
function HandlebarsWax(handlebars, options) {
|
|
var defaults = {
|
|
handlebars: handlebars,
|
|
bustCache: true,
|
|
cwd: process.cwd(),
|
|
compileOptions: null,
|
|
templateOptions: null,
|
|
parsePartialName: keygenPartial,
|
|
parseHelperName: keygenHelper,
|
|
parseDecoratorName: keygenDecorator,
|
|
parseDataName: null
|
|
};
|
|
|
|
this.handlebars = handlebars;
|
|
this.config = assign(defaults, options);
|
|
this.context = Object.create(null);
|
|
}
|
|
|
|
HandlebarsWax.prototype.partials = function (partials, options) {
|
|
options = assign({}, this.config, options);
|
|
options.keygen = options.parsePartialName;
|
|
options.reducer = options.reducer || reducer;
|
|
|
|
var unhookRequire = hookRequire(options.handlebars);
|
|
|
|
options.handlebars.registerPartial(
|
|
resolveValue(options, partials)
|
|
);
|
|
|
|
unhookRequire();
|
|
|
|
return this;
|
|
};
|
|
|
|
HandlebarsWax.prototype.helpers = function (helpers, options) {
|
|
options = assign({}, this.config, options);
|
|
options.keygen = options.parseHelperName;
|
|
options.reducer = options.reducer || reducer;
|
|
|
|
options.handlebars.registerHelper(
|
|
resolveValue(options, helpers)
|
|
);
|
|
|
|
return this;
|
|
};
|
|
|
|
HandlebarsWax.prototype.decorators = function (decorators, options) {
|
|
options = assign({}, this.config, options);
|
|
options.keygen = options.parseDecoratorName;
|
|
options.reducer = options.reducer || reducer;
|
|
|
|
options.handlebars.registerDecorator(
|
|
resolveValue(options, decorators)
|
|
);
|
|
|
|
return this;
|
|
};
|
|
|
|
HandlebarsWax.prototype.data = function (data, options) {
|
|
options = assign({}, this.config, options);
|
|
options.keygen = options.parseDataName;
|
|
|
|
assign(this.context, resolveValue(options, data));
|
|
|
|
return this;
|
|
};
|
|
|
|
HandlebarsWax.prototype.compile = function (template, compileOptions) {
|
|
var config = this.config;
|
|
var context = this.context;
|
|
|
|
compileOptions = assign({}, config.compileOptions, compileOptions);
|
|
|
|
if (getTypeOf(template) !== TYPE_FUNCTION) {
|
|
template = this.handlebars.compile(template, compileOptions);
|
|
}
|
|
|
|
return function (data, templateOptions) {
|
|
templateOptions = assign({}, config.templateOptions, templateOptions);
|
|
templateOptions.data = assign({}, templateOptions.data);
|
|
|
|
// {{@root.foo}} and {{@root._parent.foo}}
|
|
templateOptions.data.root = assign({ _parent: context }, templateOptions.data.root || context);
|
|
|
|
// {{foo}} and {{_parent.foo}}
|
|
return template(assign({ _parent: context }, context, data), templateOptions);
|
|
};
|
|
};
|
|
|
|
// API
|
|
|
|
function handlebarsWax(handlebars, config) {
|
|
return new HandlebarsWax(handlebars, config);
|
|
}
|
|
|
|
module.exports = handlebarsWax;
|
|
module.exports.HandlebarsWax = HandlebarsWax;
|