function helpers(groups, options) {
if (typeof groups === 'string') {
groups = [groups];
} else if (!Array.isArray(groups)) {
options = groups;
groups = null;
}
options = options || {};
var hbs = options.handlebars || options.hbs || require('handlebars');
define(module.exports, 'handlebars', hbs);
if (groups) {
groups.forEach(function(key) {
hbs.registerHelper(lib[key]);
});
} else {
forIn(lib, function(group, key) {
hbs.registerHelper(group);
});
}
return hbs.helpers;
}n/a
function proxy(name, alias) {
var key = alias;
// camel-case the module `name` if `alias` is not defined
if (typeof key !== 'string') {
key = camelcase(name);
}
// create a getter to lazily invoke the module the first time it's called
function getter() {
return cache[key] || (cache[key] = requireFn(name));
}
// trip the getter if `process.env.UNLAZY` is defined
if (unlazy(process.env)) {
getter();
}
set(proxy, key, getter);
return getter;
}n/a
function micromatch(files, patterns, opts) {
if (!files || !patterns) return [];
opts = opts || {};
if (typeof opts.cache === 'undefined') {
opts.cache = true;
}
if (!Array.isArray(patterns)) {
return match(files, patterns, opts);
}
var len = patterns.length, i = 0;
var omit = [], keep = [];
while (len--) {
var glob = patterns[i++];
if (typeof glob === 'string' && glob.charCodeAt(0) === 33 /* ! */) {
omit.push.apply(omit, match(files, glob.slice(1), opts));
} else {
keep.push.apply(keep, match(files, glob, opts));
}
}
return utils.diff(keep, omit);
}n/a
function relative(a, b, stat) {
if (typeof a !== 'string') {
throw new TypeError('relative expects a string.');
}
if (a == '' && !b) return a;
var len = arguments.length;
if (len === 1) {
b = a; a = process.cwd(); stat = null;
}
if (len === 2 && typeof b === 'boolean') {
b = a; a = process.cwd(); stat = true;
}
if (len === 2 && typeof b === 'object') {
stat = b; b = a; a = process.cwd();
}
var origB = b;
// see if a slash exists before normalizing
var slashA = endsWith(a, '/');
var slashB = endsWith(b, '/');
a = unixify(a);
b = unixify(b);
// if `a` had a slash, add it back
if (slashA) { a = a + '/'; }
if (isFile(a, stat)) {
a = path.dirname(a);
}
var res = path.relative(a, b);
if (res === '') {
return '.';
}
// if `b` originally had a slash, and the path ends
// with `b` missing a slash, then re-add the slash.
var noslash = trimEnd(origB, '/');
if (slashB && (res === noslash || endsWith(res, noslash))) {
res = res + '/';
}
return res;
}n/a
after = function (array, n) {
if (utils.isUndefined(array)) return '';
return array.slice(n);
}n/a
arrayify = function (value) {
return value ? (Array.isArray(value) ? value : [value]) : [];
}...
helpers.css = function(array, options) {
if (arguments.length < 2) {
options = array;
array = [];
}
var styles = utils.arrayify(array);
var assets = '';
if (this && this.options) {
assets = this.options.assets || '';
}
if (options.hash.href) {
...before = function (array, n) {
if (utils.isUndefined(array)) return '';
return array.slice(0, -n);
}n/a
eachIndex = function (array, options) {
var result = '';
for (var i = 0; i < array.length; i++) {
result += options.fn({item: array[i], index: i});
}
return result;
}n/a
filter = function (array, value, options) {
var content = '';
var results = [];
// filter on a specific property
var prop = options.hash && options.hash.property;
if (prop) {
results = utils.filter(array, function(val) {
return utils.get(val, prop) === value;
});
} else {
// filter on a string value
results = utils.filter(array, function(v) {
return value === v;
});
}
if (results && results.length > 0) {
for (var i = 0; i < results.length; i++) {
content += options.fn(results[i]);
}
return content;
}
return options.inverse(this);
}...
helpers.filter = function(array, value, options) {
var content = '';
var results = [];
// filter on a specific property
var prop = options.hash && options.hash.property;
if (prop) {
results = utils.filter(array, function(val) {
return utils.get(val, prop) === value;
});
} else {
// filter on a string value
results = utils.filter(array, function(v) {
return value === v;
...first = function (array, n) {
if (utils.isUndefined(array)) return '';
if (!utils.isNumber(n)) {
return array[0];
}
return array.slice(0, n);
}n/a
forEach = function (array, options) {
var data = utils.createFrame(options, options.hash);
var len = array.length;
var buffer = '';
var i = -1;
while (++i < len) {
var item = array[i];
data.index = i;
item.index = i + 1;
item.total = len;
item.isFirst = i === 0;
item.isLast = i === (len - 1);
buffer += options.fn(item, {data: data});
}
return buffer;
}...
options = options || {};
var hbs = options.handlebars || options.hbs || require('handlebars');
define(module.exports, 'handlebars', hbs);
if (groups) {
groups.forEach(function(key) {
hbs.registerHelper(lib[key]);
});
} else {
forIn(lib, function(group, key) {
hbs.registerHelper(group);
});
}
...inArray = function (array, value, options) {
if (utils.indexOf(array, value) > -1) {
return options.fn(this);
}
return options.inverse(this);
}n/a
isArray = function (value) {
return Array.isArray(value);
}...
/**
* Expose helpers
*/
module.exports = function helpers(groups, options) {
if (typeof groups === 'string') {
groups = [groups];
} else if (!Array.isArray(groups)) {
options = groups;
groups = null;
}
options = options || {};
var hbs = options.handlebars || options.hbs || require('handlebars');
...join = function (array, sep) {
if (utils.isUndefined(array)) return '';
sep = typeof sep !== 'string'
? ', '
: sep;
return array.join(sep);
}...
*/
helpers.join = function(array, sep) {
if (utils.isUndefined(array)) return '';
sep = typeof sep !== 'string'
? ', '
: sep;
return array.join(sep);
};
/**
* Returns the last item, or last `n` items of an array.
* Opposite of [first](#first).
*
* ```handlebars
...last = function (array, n) {
if (!utils.isNumber(n)) {
return array[array.length - 1];
}
return array.slice(-n);
}n/a
lengthEqual = function (array, length, options) {
if (array.length === length) {
return options.fn(this);
}
return options.inverse(this);
}n/a
map = function (array, fn) {
if (utils.isUndefined(array)) return '';
if (typeof array === 'string' && /[[]/.test(array)) {
array = utils.tryParse(array) || [];
}
var len = array.length;
var res = new Array(len);
var i = -1;
while (++i < len) {
res[i] = fn(array[i], i, array);
}
return res;
}...
* @param {String} `directory`
* @return {Array}
* @api public
*/
helpers.readdir = function(dir, filter) {
var files = fs.readdirSync(dir);
files = files.map(function(fp) {
return path.join(dir, fp);
});
if (utils.isOptions(filter)) {
return files;
}
if (typeof filter === 'function') {
return filter(files);
...some = function (arr, cb, options) {
cb = utils.iterator(cb, this);
if (arr == null) {
return options.inverse(this);
}
var len = arr.length, i = -1;
while (++i < len) {
if (cb(arr[i], i, arr)) {
return options.fn(this);
}
}
return options.inverse(this);
}n/a
sort = function (arr, options) {
if (utils.isUndefined(arr)) return '';
if (utils.get(options, 'hash.reverse')) {
return arr.sort().reverse();
}
return arr.sort();
}...
* @param {String|Function} `key` The object key to sort by, or sorting function.
* @api public
*/
helpers.sort = function(arr, options) {
if (utils.isUndefined(arr)) return '';
if (utils.get(options, 'hash.reverse')) {
return arr.sort().reverse();
}
return arr.sort();
};
/**
* Sort an `array`. If an array of objects is passed,
* you may optionally pass a `key` to sort on as the second
...sortBy = function (arr) {
if (utils.isUndefined(arr)) return '';
var args = [].slice.call(arguments);
args.pop(); // remove hbs options object
if (typeof args[0] === 'string' && /[[]/.test(args[0])) {
args[0] = utils.tryParse(args[0]) || [];
}
if (utils.isUndefined(args[1])) {
return args[0].sort();
}
return utils.sortBy.apply(null, args);
}n/a
withAfter = function (array, idx, options) {
array = array.slice(idx);
var result = '';
var len = array.length, i = -1;
while (++i < len) {
result += options.fn(array[i]);
}
return result;
}n/a
withBefore = function (array, idx, options) {
array = array.slice(0, -idx);
var result = '';
var len = array.length, i = -1;
while (++i < len) {
result += options.fn(array[i]);
}
return result;
}n/a
withFirst = function (arr, idx, options) {
if (utils.isUndefined(arr)) return '';
arr = utils.result(arr);
if (!utils.isUndefined(idx)) {
idx = parseFloat(utils.result(idx));
}
if (utils.isUndefined(idx)) {
options = idx;
return options.fn(arr[0]);
}
arr = arr.slice(0, idx);
var len = arr.length, i = -1;
var result = '';
while (++i < len) {
result += options.fn(arr[i]);
}
return result;
}n/a
withLast = function (array, idx, options) {
if (utils.isUndefined(array)) return '';
array = utils.result(array);
if (!utils.isUndefined(idx)) {
idx = parseFloat(utils.result(idx));
}
if (utils.isUndefined(idx)) {
options = idx;
return options.fn(array[array.length - 1]);
}
array = array.slice(-idx);
var len = array.length, i = -1;
var result = '';
while (++i < len) {
result += options.fn(array[i]);
}
return result;
}n/a
withSort = function (array, prop, options) {
if (utils.isUndefined(array)) return '';
var result = '';
if (utils.isUndefined(prop)) {
options = prop;
array = array.sort();
if (utils.get(options, 'hash.reverse')) {
array = array.reverse();
}
for (var i = 0, len = array.length; i < len; i++) {
result += options.fn(array[i]);
}
return result;
}
array.sort(function(a, b) {
a = utils.get(a, prop);
b = utils.get(b, prop);
return a > b ? 1 : (a < b ? -1 : 0);
});
if (utils.get(options, 'hash.reverse')) {
array = array.reverse();
}
var alen = array.length, j = -1;
while (++j < alen) {
result += options.fn(array[j]);
}
return result;
}n/a
function embed(fp, ext) {
ext = typeof ext !== 'string' ? path.extname(fp).slice(1) : ext;
var code = fs.readFileSync(fp, 'utf8');
if (ext === 'markdown' || ext === 'md') {
ext = 'markdown';
// if the string is markdown, escape backticks
code = code.split('`').join('`');
}
return utils.block(code, ext).trim() + '\n';
}n/a
gist = function (id) {
return utils.tag('script', {src: 'https://gist.github.com/' + id + '.js'});
}n/a
function jsFiddle(options) {
var attr = object.merge({}, options, options.hash);
delete attr.name;
delete attr.hash;
delete attr.data;
if (typeof attr.id === 'undefined') {
throw new Error('jsfiddle helper expects an `id`');
}
attr.id = 'http://jsfiddle.net/' + attr.id;
attr.width = attr.width || '100%';
attr.height = attr.height || '300';
attr.skin = attr.skin || '/presentation/';
attr.tabs = (attr.tabs || 'result,js,html,css') + attr.skin;
attr.src = attr.id + '/embedded/' + attr.tabs;
attr.allowfullscreen = attr.allowfullscreen || 'allowfullscreen';
attr.frameborder = attr.frameborder || '0';
delete attr.tabs;
delete attr.skin;
delete attr.id;
return utils.tag('iframe', attr);
}n/a
isEmpty = function (collection, options) {
if (options == null) {
options = collection;
return options.fn(this);
}
if (Array.isArray(collection) && !collection.length) {
return options.fn(this);
}
var keys = Object.keys(collection);
if (typeof collection === 'object' && !keys.length) {
return options.fn(this);
}
return options.inverse(this);
}n/a
iterate = function (context, options) {
if (Array.isArray(context)) {
return forEach.apply(forEach, arguments);
} else if (utils.isObject(context)) {
return forOwn.apply(forOwn, arguments);
}
return options.inverse(this);
}n/a
length = function (value) {
if (utils.isUndefined(value)) return '';
if (typeof value === 'string' && /[[]/.test(value)) {
value = utils.tryParse(value) || [];
}
if (utils.isObject(value)) {
value = Object.keys(value);
}
return value.length;
}n/a
and = function (a, b, options) {
if (a && b) {
return options.fn(this);
}
return options.inverse(this);
}n/a
compare = function (a, operator, b, options) {
/*eslint eqeqeq: 0*/
if (arguments.length < 4) {
throw new Error('handlebars Helper {{compare}} expects 4 arguments');
}
var result;
switch (operator) {
case '==':
result = a == b;
break;
case '===':
result = a === b;
break;
case '!=':
result = a != b;
break;
case '!==':
result = a !== b;
break;
case '<':
result = a < b;
break;
case '>':
result = a > b;
break;
case '<=':
result = a <= b;
break;
case '>=':
result = a >= b;
break;
case 'typeof':
result = typeof a === b;
break;
default: {
throw new Error('helper {{compare}}: invalid operator: `' + operator + '`');
}
}
if (result === false) {
return options.inverse(this);
}
return options.fn(this);
}n/a
contains = function (collection, value, startIndex, options) {
if (typeof startIndex === 'object') {
options = startIndex;
startIndex = undefined;
}
if (utils.contains(collection, value, startIndex)) {
return options.fn(this);
}
return options.inverse(this);
}...
*/
helpers.contains = function(collection, value, startIndex, options) {
if (typeof startIndex === 'object') {
options = startIndex;
startIndex = undefined;
}
if (utils.contains(collection, value, startIndex)) {
return options.fn(this);
}
return options.inverse(this);
};
/**
* Block helper that renders a block if `a` is **greater than** `b`.
...eq = function (a, b, options) {
if (arguments.length === 2) {
options = b;
b = options.hash.compare;
}
if (a === b) {
return options.fn(this);
}
return options.inverse(this);
}n/a
gt = function (a, b, options) {
if (arguments.length === 2) {
options = b;
b = options.hash.compare;
}
if (a > b) {
return options.fn(this);
}
return options.inverse(this);
}n/a
gte = function (a, b, options) {
if (arguments.length === 2) {
options = b;
b = options.hash.compare;
}
if (a >= b) {
return options.fn(this);
}
return options.inverse(this);
}n/a
has = function (value, pattern, options) {
if (arguments.length === 2) {
return pattern.inverse(this);
}
if (arguments.length === 1) {
return value.inverse(this);
}
if ((Array.isArray(value) || isString(value)) && isString(pattern)) {
if (value.indexOf(pattern) > -1) {
return options.fn(this);
}
}
if (isObject(value) && isString(pattern) && pattern in value) {
return options.fn(this);
}
return options.inverse(this);
}n/a
ifEven = function (num, options) {
return utils.isEven(num)
? options.fn(this)
: options.inverse(this);
}n/a
ifNth = function (a, b, options) {
if (utils.isNumber(a) && utils.isNumber(b) && b % a === 0) {
return options.fn(this);
}
return options.inverse(this);
}n/a
ifOdd = function (val, options) {
return utils.isOdd(val)
? options.fn(this)
: options.inverse(this);
}n/a
is = function (a, b, options) {
if (arguments.length === 2) {
options = b;
b = options.hash.compare;
}
if (a === b) {
return options.fn(this);
}
return options.inverse(this);
}n/a
isnt = function (a, b, options) {
if (arguments.length === 2) {
options = b;
b = options.hash.compare;
}
if (a !== b) {
return options.fn(this);
}
return options.inverse(this);
}n/a
lt = function (a, b, options) {
if (arguments.length === 2) {
options = b;
b = options.hash.compare;
}
if (a < b) {
return options.fn(this);
}
return options.inverse(this);
}n/a
lte = function (a, b, options) {
if (arguments.length === 2) {
options = b;
b = options.hash.compare;
}
if (a <= b) {
return options.fn(this);
}
return options.inverse(this);
}n/a
neither = function (a, b, options) {
if (!a && !b) {
return options.fn(this);
}
return options.inverse(this);
}n/a
or = function () {
var len = arguments.length - 1;
var options = arguments[len];
for (var i = 0; i < len; i++) {
if (arguments[i]) {
return options.fn(this);
}
}
return options.inverse(this);
}n/a
unlessEq = function (context, options) {
if (context === options.hash.compare) {
return options.inverse(this);
}
return options.fn(this);
}n/a
unlessGt = function (context, options) {
if (context > options.hash.compare) {
return options.inverse(this);
}
return options.fn(this);
}n/a
unlessGteq = function (context, options) {
if (context >= options.hash.compare) {
return options.inverse(this);
}
return options.fn(this);
}n/a
unlessLt = function (context, options) {
if (context < options.hash.compare) {
return options.inverse(this);
}
return options.fn(this);
}n/a
unlessLteq = function (context, options) {
if (context <= options.hash.compare) {
return options.inverse(this);
}
return options.fn(this);
}n/a
function momentHelper(str, pattern, options) {
// if no args are passed, return a formatted date
if (str == null && pattern == null) {
moment.locale('en');
return moment().format('MMMM DD, YYYY');
}
var opts = {lang: 'en', date: new Date()};
opts = extend({}, opts, str, pattern, options);
opts = extend({}, opts, opts.hash);
// set the language to use
moment.locale(opts.lang);
if (opts.datejs === false) {
return moment(new Date(str)).format(pattern);
}
// if both args are strings, this could apply to either lib.
// so instead of doing magic we'll just ask the user to tell
// us if the args should be passed to date.js or moment.
if (typeof str === 'string' && typeof pattern === 'string') {
return moment(date(str)).format(pattern);
}
// If handlebars, expose moment methods as hash properties
if (opts.hash) {
if (opts.context) {
extend(opts.hash, opts.context);
}
var res = moment(str);
for (var key in opts.hash) {
if (res[key]) {
return res[key](opts.hash[key]);
} else {
console.log('moment.js does not support "' + key + '"');
}
}
}
if (typeOf(str) === 'object') {
return moment(str).format(pattern);
}
// if only a string is passed, assume it's a date pattern ('YYYY')
if (typeof str === 'string' && !pattern) {
return moment().format(str);
}
return moment(str).format(pattern);
}n/a
fileSize = function (num) {
var bytes = parseInt(num, 10);
if (!utils.isNumber(bytes)) {
console.error('helper {{fileSize}} cannot parse: "' + num + '"');
return num.toString(); // Graceful degradation
}
// KB is technically a Kilobit, but it seems more readable.
var metric = ['byte', 'bytes', 'KB', 'MB', 'GB'];
var res;
if (bytes === 0) {
return '0 bytes';
} else {
// Base 1000 (rather than 1024) matches Mac OS X
res = Math.floor(Math.log(bytes) / Math.log(1000));
// No decimals for anything smaller than 1 MB
num = (bytes / Math.pow(1000, Math.floor(res))).toFixed(res < 2 ? 0 : 1);
if (bytes === 1) {
res = -1; // special case: 1 byte (singular)
}
}
return num + ' ' + metric[res + 1];
}n/a
read = function (filepath) {
return fs.readFileSync(filepath, 'utf8');
}n/a
readdir = function (dir, filter) {
var files = fs.readdirSync(dir);
files = files.map(function(fp) {
return path.join(dir, fp);
});
if (utils.isOptions(filter)) {
return files;
}
if (typeof filter === 'function') {
return filter(files);
}
if (utils.isRegex(filter)) {
var re = utils.toRegex(filter);
return files.filter(function(fp) {
return re.test(fp);
});
}
if (utils.isGlob(filter)) {
var isMatch = utils.mm.matcher(filter);
return files.filter(function(fp) {
return isMatch(fp);
});
}
if (['isFile', 'isDirectory'].indexOf(filter) !== -1) {
return files.filter(function(fp) {
var stat = fs.statSync(fp);
return stat[filter]();
});
}
return files;
}n/a
css = function (array, options) {
if (arguments.length < 2) {
options = array;
array = [];
}
var styles = utils.arrayify(array);
var assets = '';
if (this && this.options) {
assets = this.options.assets || '';
}
if (options.hash.href) {
styles = utils.arrayify(options.hash.href);
}
return styles.map(function(item) {
var ext = path.extname(item);
var fp = path.join(assets, item);
if (ext === '.less') {
return '<link type="text/css" rel="stylesheet/less" href="' + fp + '">';
}
return '<link type="text/css" rel="stylesheet" href="' + fp + '">';
}).join('\n');
}n/a
ellipsis = function (str, limit) {
if (str && typeof str === 'string') {
if (str.length <= limit) {
return str;
}
return helpers.truncate(str, limit) + '…';
}
}n/a
js = function (context) {
if (utils.typeOf(context) === 'object') {
var attr = html.toAttributes(context.hash);
return '<script' + attr + '></script>';
}
if (utils.typeOf(context) === 'string') {
return '<script src="' + context + '"></script>';
}
context = utils.arrayify(context);
return context.map(function(fp) {
return (path.extname(fp) === '.coffee')
? utils.tag('script', {type: 'text/coffeescript', src: fp})
: utils.tag('script', {src: fp});
}).join('\n');
}n/a
ol = function (context, options) {
return ('<ol ' + (parseAttr(options.hash)) + '>') + context.map(function(item) {
if (typeof item !== 'string') {
item = options.fn(item);
}
return '<li>' + item + '</li>';
}).join('\n') + '</ol>';
}n/a
sanitize = function (str) {
return html.sanitize(str);
}...
*
* @param {String} `str` The string of HTML to sanitize.
* @return {String}
* @api public
*/
helpers.sanitize = function(str) {
return html.sanitize(str);
};
/**
* Truncate a string by removing all HTML tags and limiting the result
* to the specified `length`. Aslo see [ellipsis](#ellipsis).
*
* ```js
...thumbnailImage = function (context) {
var figure = '';
var image = '';
var link = context.full || false;
var imageAttributes = {
alt: context.alt,
src: context.thumbnail,
width: context.size.width,
height: context.size.height
};
var figureAttributes = { id: 'image-' + context.id };
var linkAttributes = { href: link, rel: 'thumbnail' };
if (context.classes) {
if (context.classes.image) {
imageAttributes.class = context.classes.image.join(' ');
}
if (context.classes.figure) {
figureAttributes.class = context.classes.figure.join(' ');
}
if (context.classes.link) {
linkAttributes.class = context.classes.link.join(' ');
}
}
figure += '<figure ' + parseAttr(figureAttributes) + '>\n';
image += '<img ' + parseAttr(imageAttributes) + '>\n';
if (link) {
figure += '<a ' + parseAttr(linkAttributes) + '>\n' + image + '</a>\n';
} else {
figure += image;
}
if (context.caption) {
figure += '<figcaption>' + context.caption + '</figcaption>\n';
}
figure += '</figure>';
return figure;
}n/a
truncate = function (str, limit, suffix) {
if (str && typeof str === 'string') {
var ch = typeof suffix === 'string' ? suffix : '';
if (str.length > limit) {
return html.sanitize(str).slice(0, limit - ch.length) + ch;
}
return str;
}
}...
*/
helpers.ellipsis = function(str, limit) {
if (str && typeof str === 'string') {
if (str.length <= limit) {
return str;
}
return helpers.truncate(str, limit) + '…';
}
};
/**
* Generate one or more `<script></script>` tags with paths/urls to
* javascript or coffeescript files.
*
...ul = function (context, options) {
return ('<ul ' + (parseAttr(options.hash)) + '>') + context.map(function(item) {
if (typeof item !== 'string') {
item = options.fn(item);
}
return '<li>' + item + '</li>';
}).join('\n') + '</ul>';
}n/a
i18n = function (prop, context, options) {
if (utils.isOptions(context)) {
options = context;
context = {};
}
if (typeof prop !== 'string') {
throw new Error('{{i18n}} helper expected "key" to be a string');
}
var opts = utils.merge({}, this, options.hash);
// account for `options` being passed on the context
if (opts.options) {
opts = utils.merge({}, opts, opts.options);
delete opts.options;
}
var lang = opts.language || opts.lang;
if (typeof lang !== 'string') {
throw new Error('{{i18n}} helper expected "language" parameter to be a string');
}
var value = utils.get(opts, lang);
if (typeof value === 'undefined') {
throw new Error('{{i18n}} helper cannot find language "' + lang + '"');
}
var result = utils.get(value, prop);
if (typeof result === 'undefined') {
throw new Error('{{i18n}} helper cannot find property "' + prop + '" for language "' + lang + '"');
}
return result;
}n/a
inflect = function (count, singular, plural, include) {
var word = (count > 1 || count === 0) ? plural : singular;
if (utils.isUndefined(include) || include === false) {
return word;
} else {
return String(count) + ' ' + word;
}
}n/a
ordinalize = function (val) {
var num = Math.abs(Math.round(val));
var res = num % 100;
if (utils.indexOf([11, 12, 13], res) >= 0) {
return '' + val + 'th';
}
switch (num % 10) {
case 1:
return '' + val + 'st';
case 2:
return '' + val + 'nd';
case 3:
return '' + val + 'rd';
default: {
return '' + val + 'th';
}
}
}n/a
function inspect_(context, options) {
context = JSON.stringify(context, null, 2);
var ext = options && options.hash && options.hash.ext || 'html';
return switchOutput(ext, context);
}n/a
function bold_() {
arguments[0] = chalk.bold(arguments[0]);
console.log.apply(console, arguments);
}n/a
function debug_(val) {
var args = [].slice.call(arguments);
console.log();
console.log('=================================');
console.log('context: %j', this);
console.log();
if (!isUndefined(val)) {
console.log.apply(console, ['value: %j'].concat(val));
}
console.log('=================================');
console.log();
return;
}n/a
function error_() {
arguments[0] = chalk.red(arguments[0]);
console.error.apply(console, arguments);
}...
* @api public
*/
helpers.fileSize = function(num) {
var bytes = parseInt(num, 10);
if (!utils.isNumber(bytes)) {
console.error('helper {{fileSize}} cannot parse: "' + num + '
x22;');
return num.toString(); // Graceful degradation
}
// KB is technically a Kilobit, but it seems more readable.
var metric = ['byte', 'bytes', 'KB', 'MB', 'GB'];
var res;
...function info_() {
arguments[0] = chalk.cyan(arguments[0]);
console.log.apply(console, arguments);
}n/a
function log_() {
console.log.apply(console, arguments);
}...
var metric = ['byte', 'bytes', 'KB', 'MB', 'GB'];
var res;
if (bytes === 0) {
return '0 bytes';
} else {
// Base 1000 (rather than 1024) matches Mac OS X
res = Math.floor(Math.log(bytes) / Math.log(1000));
// No decimals for anything smaller than 1 MB
num = (bytes / Math.pow(1000, Math.floor(res))).toFixed(res < 2 ? 0 : 1);
if (bytes === 1) {
res = -1; // special case: 1 byte (singular)
}
...function warn_() {
arguments[0] = chalk.yellow(arguments[0]);
console.warn.apply(console, arguments);
}n/a
function helper(context, options) {
if (typeof context === 'string') {
var opts = merge({}, config, options);
var md = new Remarkable(opts);
return md.render(context);
}
if (isObject(context) && typeof context.fn === 'function') {
options = context;
context = {};
}
options = merge({ html: true, breaks: true }, config, options);
options = merge({}, options, options.markdown, options.hash);
if (options.hasOwnProperty('lang')) {
options.langPrefix = options.lang;
}
var md = new Remarkable(options);
var ctx = merge({}, options, this.context, context);
return md.render(options.fn(ctx));
}n/a
md = function (name, options, cb) {
if (typeof options === 'function') {
cb = options;
options = {};
}
if (typeof cb !== 'function') {
return helper.sync.apply(this, arguments);
}
if (typeof this === 'undefined' || typeof this.app === 'undefined') {
throw new Error('md async helper expects `app` to be exposed on the context');
}
var opts = extend({cwd: process.cwd()}, this.options, options);
opts = extend({}, opts, opts.hash);
var md = markdown(opts);
var filepath = path.resolve(opts.cwd, name);
var view;
var str = '';
if (exists(filepath)) {
// create a collection to ensure middleware is consistent
this.app.create('mdfiles');
str = fs.readFileSync(filepath, 'utf8');
view = this.app.mdfile(filepath, {path: filepath, content: str});
} else {
view = this.app.find(name);
}
if (typeof view === 'undefined') {
cb(null, '');
return;
}
view.content = ent.decode(md.render(view.content));
this.app.render(view, this.context, function(err, res) {
if (err) return cb(err);
cb(null, res.content);
});
}n/a
match = function () {
var args = utils.getArgs(this, arguments);
return utils.mm.match.apply(utils.mm, args);
}...
* @return {String}
* @api public
*/
helpers.titleize = function(str) {
if (str && typeof str === 'string') {
var title = str.replace(/[ \-_]+/g, ' ');
var words = title.match(/\w+/g);
var len = words.length;
var res = [];
var i = 0;
while (len--) {
var word = words[i++];
res.push(exports.capitalize(word));
}
...isMatch = function () {
var args = utils.getArgs(this, arguments);
return utils.mm.isMatch.apply(utils.mm, args);
}n/a
mm = function () {
var args = utils.getArgs(this, arguments);
return utils.mm.apply(utils.mm, args);
}n/a
add = function (a, b) {
return a + b;
}n/a
avg = function () {
var args = utils.flatten([].concat.apply([], arguments));
// remove handlebars options object
args.pop();
return exports.sum(args) / args.length;
}n/a
ceil = function (value) {
return Math.ceil(value);
}...
**Params**
* `value` **{Number}**
### [{{ceil}}](lib/math.js#L76)
Get the `Math.ceil()` of the given value.
**Params**
* `value` **{Number}**
### [{{round}}](lib/math.js#L87)
...divide = function (a, b) {
return a / b;
}n/a
floor = function (value) {
return Math.floor(value);
}...
**Params**
* `a` **{Number}**: factor
* `b` **{Number}**: multiplier
### [{{floor}}](lib/math.js#L65)
Get the `Math.floor()` of the given value.
**Params**
* `value` **{Number}**
### [{{ceil}}](lib/math.js#L76)
...multiply = function (a, b) {
return a * b;
}n/a
round = function (value) {
return Math.round(value);
}...
*
* @param {String} `val` The value to ordinalize.
* @return {String} The ordinalized number
* @api public
*/
helpers.ordinalize = function(val) {
var num = Math.abs(Math.round(val));
var res = num % 100;
if (utils.indexOf([11, 12, 13], res) >= 0) {
return '' + val + 'th';
}
switch (num % 10) {
...subtract = function (a, b) {
return a - b;
}n/a
sum = function () {
var args = utils.flatten([].concat.apply([], arguments));
var i = args.length, sum = 0;
while (i--) {
if (!utils.isNumber(args[i])) {
continue;
}
sum += (+args[i]);
}
return sum;
}...
* @api public
*/
helpers.avg = function() {
var args = utils.flatten([].concat.apply([], arguments));
// remove handlebars options object
args.pop();
return exports.sum(args) / args.length;
};
...default = function (value, defaultValue) {
return value == null
? defaultValue
: value;
}n/a
noop = function (options) {
return options.fn(this);
}n/a
option = function (prop) {
var opts = (this && this.options) || {};
return utils.get(opts, prop);
}n/a
withHash = function (options) {
if (options.hash && Object.keys(options.hash).length) {
return options.fn(options.hash);
} else {
return options.inverse(this);
}
}n/a
addCommas = function (num) {
return num.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
}n/a
phoneNumber = function (num) {
num = num.toString();
return '(' + num.substr(0, 3) + ') '
+ num.substr(3, 3) + '-'
+ num.substr(6, 4);
}n/a
random = function (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}...
* @param {Number} `max`
* @contributor Tim Douglas <https://github.com/timdouglas>
* @return {String}
* @api public
*/
helpers.random = function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
/**
* Abbreviate numbers to the given number of `precision`. This is for
* general numbers, not size in bytes.
*
* @param {Number} `number`
...toAbbr = function (number, precision) {
if (!utils.isNumber(number)) {
number = 0;
}
if (utils.isUndefined(precision)) {
precision = 2;
}
number = +number;
// 2 decimal places => 100, 3 => 1000, etc.
precision = Math.pow(10, precision);
var abbr = ['k', 'm', 'b', 't', 'q'];
var len = abbr.length - 1;
while (len >= 0) {
var size = Math.pow(10, (len + 1) * 3);
if (size <= (number + 1)) {
number = Math.round(number * precision / size) / precision;
number += abbr[len];
break;
}
len--;
}
return number;
}n/a
toExponential = function (number, digits) {
if (!utils.isNumber(number)) {
number = 0;
}
if (utils.isUndefined(digits)) {
digits = 0;
}
number = +number;
return number.toExponential(digits);
}...
if (!utils.isNumber(number)) {
number = 0;
}
if (utils.isUndefined(digits)) {
digits = 0;
}
number = +number;
return number.toExponential(digits);
};
/**
* Formats the given number using fixed-point notation.
*
* @param {Number} `number`
* @param {Number} `digits` Optional. The number of digits to use after the decimal point; this may be a value between 0 and 20,
inclusive, and implementations may optionally support a larger range of values. If this argument is omitted, it is treated as 0.
...toFixed = function (number, digits) {
if (!utils.isNumber(number)) {
number = 0;
}
if (utils.isUndefined(digits)) {
digits = 0;
}
number = +number;
return number.toFixed(digits);
}...
if (bytes === 0) {
return '0 bytes';
} else {
// Base 1000 (rather than 1024) matches Mac OS X
res = Math.floor(Math.log(bytes) / Math.log(1000));
// No decimals for anything smaller than 1 MB
num = (bytes / Math.pow(1000, Math.floor(res))).toFixed(res < 2 ? 0 : 1);
if (bytes === 1) {
res = -1; // special case: 1 byte (singular)
}
}
return num + ' ' + metric[res + 1];
};
...toFloat = function (number) {
return parseFloat(number);
}n/a
toInt = function (number) {
return parseInt(number, 10);
}n/a
toPrecision = function (number, precision) {
if (!utils.isNumber(number)) {
number = 0;
}
if (utils.isUndefined(precision)) {
precision = 1;
}
number = +number;
return number.toPrecision(precision);
}...
if (!utils.isNumber(number)) {
number = 0;
}
if (utils.isUndefined(precision)) {
precision = 1;
}
number = +number;
return number.toPrecision(precision);
};
...JSONparse = function (str, options) {
return options.fn(JSON.parse(str));
}n/a
JSONstringify = function (obj, indent) {
if (!utils.isNumber(indent)) {
indent = 0;
}
return JSON.stringify(obj, null, indent);
}n/a
extend = function () {
var args = [].slice.call(arguments);
var last = args[args.length - 1];
if (last && utils.isObject(last) && last.hash) {
last = last.hash;
args.pop(); // remove handlebars options object
args.push(last);
}
var len = args.length;
var context = {};
var i = -1;
while (++i < len) {
var obj = args[i];
if (utils.isObject(obj)) {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
context[key] = obj[key];
}
}
}
}
return context;
}...
helpers.pick = function(props, context, options) {
var keys = array.arrayify(props);
var len = keys.length, i = -1;
var result = {};
while (++i < len) {
result = helpers.extend(result, utils.getObject(context, keys[i]));
}
if (options.fn) {
if (Object.keys(result).length) {
return options.fn(result);
} else {
return options.inverse(context);
...forIn = function (obj, options) {
if (!utils.isOptions(options)) {
return obj.inverse(this);
}
var data = utils.createFrame(options, options.hash);
var result = '';
for (var key in obj) {
data.key = key;
result += options.fn(obj[key], {data: data});
}
return result;
}n/a
forOwn = function (obj, options) {
if (!utils.isOptions(options)) {
return obj.inverse(this);
}
var data = utils.createFrame(options, options.hash);
var result = '';
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
data.key = key;
result += options.fn(obj[key], {data: data});
}
}
return result;
}n/a
get = function (prop, context, options) {
var val = utils.get(context, prop);
if (options && options.fn) {
return val ? options.fn(val) : options.inverse(context);
}
return val;
}...
var content = '';
var results = [];
// filter on a specific property
var prop = options.hash && options.hash.property;
if (prop) {
results = utils.filter(array, function(val) {
return utils.get(val, prop) === value;
});
} else {
// filter on a string value
results = utils.filter(array, function(v) {
return value === v;
});
...getObject = function (prop, context) {
return utils.getObject(context, prop);
}...
* @param {String} `prop` The property to get, optionally using dot notation for nested properties.
* @param {Object} `context` The context object
* @return {String}
* @api public
*/
helpers.getObject = function(prop, context) {
return utils.getObject(context, prop);
};
/**
* Return true if `key` is an own, enumerable property
* of the given `context` object.
*
* ```handlebars
...hasOwn = function (context, key) {
return hasOwn.call(context, key);
}n/a
isObject = function (value) {
return value && typeof value === 'object'
&& !Array.isArray(value);
}...
* @block
* @api public
*/
helpers.iterate = function(context, options) {
if (Array.isArray(context)) {
return forEach.apply(forEach, arguments);
} else if (utils.isObject(context)) {
return forOwn.apply(forOwn, arguments);
}
return options.inverse(this);
};
/**
* Returns the length of the given collection. When using a string literal in the
...merge = function (context) {
var args = [].slice.call(arguments);
var last = args[args.length - 1];
if (last && typeof last === 'object' && last.hash) {
last = last.hash;
args.pop(); // remove handlebars options object
args.push(last);
}
context = utils.merge.apply(utils.merge, args);
return context;
}...
*
* @param {Object} `params`
* @return {String}
* @api public
*/
helpers.jsfiddle = function jsFiddle(options) {
var attr = object.merge({}, options, options.hash);
delete attr.name;
delete attr.hash;
delete attr.data;
if (typeof attr.id === 'undefined') {
throw new Error('jsfiddle helper expects an `id`');
}
...parseJSON = function (str, options) {
return options.fn(JSON.parse(str));
}n/a
pick = function (props, context, options) {
var keys = array.arrayify(props);
var len = keys.length, i = -1;
var result = {};
while (++i < len) {
result = helpers.extend(result, utils.getObject(context, keys[i]));
}
if (options.fn) {
if (Object.keys(result).length) {
return options.fn(result);
} else {
return options.inverse(context);
}
}
return result;
}n/a
stringify = function (obj, indent) {
if (!utils.isNumber(indent)) {
indent = 0;
}
return JSON.stringify(obj, null, indent);
}...
* @api public
*/
helpers.JSONstringify = function(obj, indent) {
if (!utils.isNumber(indent)) {
indent = 0;
}
return JSON.stringify(obj, null, indent);
};
/**
* Alias for JSONstringify. this will be
* deprecated in a future release
*/
...toPath = function () {
var prop = [];
for (var i = 0; i < arguments.length; i++) {
if (typeof arguments[i] === "string" || typeof arguments[i] === "number") {
prop.push(arguments[i]);
}
}
return prop.join('.');
}n/a
absolute = function (filepath, options) {
var context = utils.merge({}, this, options);
var ctx = utils.merge({}, context.root, context, context._parent, context.hash);
var cwd = ctx.cwd || process.cwd();
return path.resolve(cwd, filepath);
}n/a
basename = function (filepath) {
return path.basename(filepath);
}...
* ```
* @param {String} `ext`
* @return {String}
* @api public
*/
helpers.basename = function(filepath) {
return path.basename(filepath);
};
/**
* Get the "stem" from the given `filepath`.
*
* ```handlebars
* {{stem "docs/toc.md"}}
...dirname = function (filepath) {
return path.dirname(filepath);
}...
* ```
* @param {String} `ext`
* @return {String}
* @api public
*/
helpers.dirname = function(filepath) {
return path.dirname(filepath);
};
/**
* Get the relative filepath from `a` to `b`.
*
* ```handlebars
* {{relative a b}}
...extname = function (filepath) {
return path.extname(filepath);
}...
* @param {String} `fp` filepath to the file to embed.
* @param {String} `language` Optionally specify the language to use for syntax highlighting.
* @return {String}
* @api public
*/
helpers.embed = function embed(fp, ext) {
ext = typeof ext !== 'string' ? path.extname(fp).slice(1) : ext;
var code = fs.readFileSync(fp, 'utf8');
if (ext === 'markdown' || ext === 'md') {
ext = 'markdown';
// if the string is markdown, escape backticks
code = code.split('`').join('`');
}
return utils.block(code, ext).trim() + '\n';
...relative = function (a, b) {
return utils.relative(a, b);
}...
* @param {String} `a`
* @param {String} `b`
* @return {String}
* @api public
*/
helpers.relative = function(a, b) {
return utils.relative(a, b);
};
/**
* Get the file extension from the given `filepath`.
*
* ```handlebars
* {{basename "docs/toc.md"}}
...segments = function (fp, a, b) {
return utils.normalize(fp).split('/').slice(a, b).join('/');
}n/a
stem = function (filepath) {
return path.basename(filepath, path.extname(filepath));
}n/a
camelcase = function (str) {
return utils.changecase(str, function(ch) {
return ch.toUpperCase();
});
}n/a
capitalize = function (str) {
if (str && typeof str === 'string') {
return str.charAt(0).toUpperCase()
+ str.slice(1);
}
}...
* @return {String}
* @api public
*/
helpers.capitalizeAll = function(str) {
if (str && typeof str === 'string') {
return str.replace(/\w\S*/g, function(word) {
return exports.capitalize(word);
});
}
};
/**
* Center a string using non-breaking spaces
*
...capitalizeAll = function (str) {
if (str && typeof str === 'string') {
return str.replace(/\w\S*/g, function(word) {
return exports.capitalize(word);
});
}
}n/a
center = function (str, spaces) {
if (str && typeof str === 'string') {
var space = '';
var i = 0;
while (i < spaces) {
space += ' ';
i++;
}
return space + str + space;
}
}n/a
chop = function (str) {
return utils.chop(str);
}...
* @name .chop
* @param {String} `string` The string to chop.
* @return {String}
* @api public
*/
helpers.chop = function(str) {
return utils.chop(str);
};
/**
* dash-case the characters in `string`. Replaces non-word
* characters and periods with hyphens.
*
* ```js
...dashcase = function (str) {
return utils.changecase(str, function(ch) {
return '-' + ch;
});
}n/a
dotcase = function (str) {
return utils.changecase(str, function(ch) {
return '.' + ch;
});
}n/a
hyphenate = function (str) {
if (str && typeof str === 'string') {
return str.split(' ').join('-');
}
}n/a
isString = function (value) {
return utils.isString(value);
}...
* ```
* @param {String} `value`
* @return {Boolean}
* @api public
*/
helpers.isString = function(value) {
return utils.isString(value);
};
/**
* Lowercase all characters in the given string.
*
* ```handlebars
* {{lowercase "Foo BAR baZ"}}
...lowercase = function (str) {
if (str && typeof str === 'string') {
return str.toLowerCase();
}
}n/a
occurrences = function (str, substring) {
if (str && typeof str === 'string') {
var len = substring.length;
var pos = 0;
var n = 0;
while ((pos = str.indexOf(substring, pos))) {
if (pos > -1) {
n++;
pos += len;
} else {
break;
}
}
return n;
}
}n/a
pascalcase = function (str) {
str = utils.changecase(str, function(ch) {
return ch.toUpperCase();
});
return str.charAt(0).toUpperCase()
+ str.slice(1);
}n/a
pathcase = function (str) {
return utils.changecase(str, function(ch) {
return '/' + ch;
});
}n/a
plusify = function (str) {
if (str && typeof str === 'string') {
return str.split(' ').join('+');
}
}n/a
replace = function (str, a, b) {
if (str && typeof str === 'string') {
if (!a || typeof a !== 'string') return str;
if (!b || typeof b !== 'string') b = '';
return str.split(a).join(b);
}
}...
*
* @param {Number} `num`
* @return {Number}
* @api public
*/
helpers.addCommas = function(num) {
return num.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
};
/**
* Convert a string or number to a formatted phone number.
*
* @param {Number|String} `num` The phone number to format, e.g. `8005551212`
* @return {Number} Formatted phone number: `(800) 555-1212`
...reverse = function (str) {
if (str && typeof str === 'string') {
return str.split('').reverse().join('');
}
}...
* @param {String|Function} `key` The object key to sort by, or sorting function.
* @api public
*/
helpers.sort = function(arr, options) {
if (utils.isUndefined(arr)) return '';
if (utils.get(options, 'hash.reverse')) {
return arr.sort().reverse();
}
return arr.sort();
};
/**
* Sort an `array`. If an array of objects is passed,
* you may optionally pass a `key` to sort on as the second
...sentence = function (str) {
if (str && typeof str === 'string') {
var re = /((?:\S[^\.\?\!]*)[\.\?\!]*)/g;
return str.replace(re, function(txt) {
return txt.charAt(0).toUpperCase()
+ txt.substr(1).toLowerCase();
});
}
}n/a
snakecase = function (str) {
return utils.changecase(str, function(ch) {
return '_' + ch;
});
}n/a
split = function (str, ch) {
if (!helpers.isString(str)) return '';
if (typeof ch !== 'string') ch = ',';
return str.split(ch);
}...
helpers.embed = function embed(fp, ext) {
ext = typeof ext !== 'string' ? path.extname(fp).slice(1) : ext;
var code = fs.readFileSync(fp, 'utf8');
if (ext === 'markdown' || ext === 'md') {
ext = 'markdown';
// if the string is markdown, escape backticks
code = code.split('`').join('`');
}
return utils.block(code, ext).trim() + '\n';
};
/**
* Embed a GitHub Gist using only the id of the Gist
*
...startsWith = function (prefix, str, options) {
var args = [].slice.call(arguments);
options = args.pop();
if (str && typeof str === 'string') {
if (str.indexOf(prefix) === 0) {
return options.fn(this);
}
}
if (typeof options.inverse === 'function') {
return options.inverse(this);
}
return '';
}n/a
titleize = function (str) {
if (str && typeof str === 'string') {
var title = str.replace(/[ \-_]+/g, ' ');
var words = title.match(/\w+/g);
var len = words.length;
var res = [];
var i = 0;
while (len--) {
var word = words[i++];
res.push(exports.capitalize(word));
}
return res.join(' ');
}
}n/a
trim = function (str) {
if (!helpers.isString(str)) return '';
return str.trim();
}...
ext = typeof ext !== 'string' ? path.extname(fp).slice(1) : ext;
var code = fs.readFileSync(fp, 'utf8');
if (ext === 'markdown' || ext === 'md') {
ext = 'markdown';
// if the string is markdown, escape backticks
code = code.split('`').join('`');
}
return utils.block(code, ext).trim() + '\n';
};
/**
* Embed a GitHub Gist using only the id of the Gist
*
* ```handlebars
* {{gist "12345"}}
...uppercase = function (str, options) {
if (str && typeof str === 'string') {
return str.toUpperCase();
} else {
options = str;
}
if (typeof options === 'object' && options.fn) {
return options.fn(this).toUpperCase();
}
return '';
}n/a
decodeURI = function (str) {
return decodeURIComponent(str);
}n/a
encodeURI = function (str) {
return encodeURIComponent(str);
}n/a
stripProtocol = function (str) {
var parsed = url.parse(str);
delete parsed.protocol;
return parsed.format();
}n/a
stripQuerystring = function (url) {
return url.split('?')[0];
}n/a
urlParse = function (str) {
return url.parse(str);
}n/a
urlResolve = function (base, href) {
return url.resolve(base, href);
}n/a
function proxy(name, alias) {
var key = alias;
// camel-case the module `name` if `alias` is not defined
if (typeof key !== 'string') {
key = camelcase(name);
}
// create a getter to lazily invoke the module the first time it's called
function getter() {
return cache[key] || (cache[key] = requireFn(name));
}
// trip the getter if `process.env.UNLAZY` is defined
if (unlazy(process.env)) {
getter();
}
set(proxy, key, getter);
return getter;
}n/a
arrayify = function (val) {
return val ? (Array.isArray(val) ? val : [val]) : [];
}...
helpers.css = function(array, options) {
if (arguments.length < 2) {
options = array;
array = [];
}
var styles = utils.arrayify(array);
var assets = '';
if (this && this.options) {
assets = this.options.assets || '';
}
if (options.hash.href) {
...function pre(str, lang) {
if (typeof str !== 'string') {
throw new TypeError('markdown-pre expects a string.');
}
var code = '';
code += '```' + (typeof lang === 'string' ? lang : '');
code += '\n';
code += str;
code += '\n';
code += '```';
return code;
}...
ext = typeof ext !== 'string' ? path.extname(fp).slice(1) : ext;
var code = fs.readFileSync(fp, 'utf8');
if (ext === 'markdown' || ext === 'md') {
ext = 'markdown';
// if the string is markdown, escape backticks
code = code.split('`').join('`');
}
return utils.block(code, ext).trim() + '\n';
};
/**
* Embed a GitHub Gist using only the id of the Gist
*
* ```handlebars
* {{gist "12345"}}
...changecase = function (str, fn) {
if (!utils.isString(str)) return '';
if (str.length === 1) {
return str.toLowerCase();
}
str = utils.chop(str).toLowerCase();
if (typeof fn !== 'function') {
fn = utils.identity;
}
var re = /[-_.\W\s]+(\w|$)/g;
return str.replace(re, function(_, ch) {
return fn(ch);
});
}...
* `string` **{String}**: The string to change.
* `returns` **{String}**
**Example**
```js
utils.changecase('fooBarBaz');
//=> 'foo bar baz'
utils.changecase('fooBarBaz' '-');
//=> 'foo-bar-baz'
```
### [{{random}}](lib/utils/index.js#L137)
...chop = function (str) {
if (!utils.isString(str)) return '';
var re = /^[-_.\W\s]+|[-_.\W\s]+$/g;
return str.trim().replace(re, '');
}...
* @name .chop
* @param {String} `string` The string to chop.
* @return {String}
* @api public
*/
helpers.chop = function(str) {
return utils.chop(str);
};
/**
* dash-case the characters in `string`. Replaces non-word
* characters and periods with hyphens.
*
* ```js
...contains = function (val, obj, start) {
var len = val ? val.length : 0;
var idx = start < 0
? Math.max(0, len + start)
: start;
var res = false;
var i = 0;
start = idx || 0;
if (Array.isArray(val)) {
res = utils.indexOf(val, obj, start) > -1;
} else if (utils.isNumber(len)) {
res = (typeof val === 'string'
? val.indexOf(obj, start)
: utils.indexOf(val, obj, start)) > -1;
} else {
utils.iterator(val, function(ele) {
if (start < i++) {
return !(res = (ele === obj));
}
});
}
return res;
}...
*/
helpers.contains = function(collection, value, startIndex, options) {
if (typeof startIndex === 'object') {
options = startIndex;
startIndex = undefined;
}
if (utils.contains(collection, value, startIndex)) {
return options.fn(this);
}
return options.inverse(this);
};
/**
* Block helper that renders a block if `a` is **greater than** `b`.
...function createFrame(data) {
if (!utils.isObject(data)) {
throw new TypeError('createFrame expects data to be an object');
}
var extend = utils.extend;
var frame = extend({}, data);
frame._parent = data;
utils.define(frame, 'extend', function(data) {
extend(this, data);
});
if (arguments.length > 1) {
var args = [].slice.call(arguments, 1);
var len = args.length, i = -1;
while (++i < len) {
frame.extend(args[i] || {});
}
}
return frame;
}...
* @param {Array} `array`
* @return {String}
* @block
* @api public
*/
helpers.forEach = function(array, options) {
var data = utils.createFrame(options, options.hash);
var len = array.length;
var buffer = '';
var i = -1;
while (++i < len) {
var item = array[i];
data.index = i;
...function filter(arr, fn, thisArg) {
if (arr == null) {
return [];
}
if (typeof fn !== 'function') {
throw new TypeError('expected callback to be a function');
}
var iterator = makeIterator(fn, thisArg);
var len = arr.length;
var res = arr.slice();
var i = -1;
while (len--) {
if (!iterator(arr[len], i++)) {
res.splice(len, 1);
}
}
return res;
}...
helpers.filter = function(array, value, options) {
var content = '';
var results = [];
// filter on a specific property
var prop = options.hash && options.hash.property;
if (prop) {
results = utils.filter(array, function(val) {
return utils.get(val, prop) === value;
});
} else {
// filter on a string value
results = utils.filter(array, function(v) {
return value === v;
...function flatten(arr) {
return flat(arr, []);
}...
* @name .sum
* @param {Array} `array` Array of numbers to add up.
* @return {Number}
* @api public
*/
helpers.sum = function() {
var args = utils.flatten([].concat.apply([], arguments));
var i = args.length, sum = 0;
while (i--) {
if (!utils.isNumber(args[i])) {
continue;
}
sum += (+args[i]);
}
...function forOwn(obj, fn, thisArg) {
forIn(obj, function(val, key) {
if (hasOwn.call(obj, key)) {
return fn.call(thisArg, obj[key], key, obj);
}
});
}n/a
get = function (obj, prop, a, b, c) {
if (!isObject(obj) || !prop) {
return obj;
}
prop = toString(prop);
// allowing for multiple properties to be passed as
// a string or array, but much faster (3-4x) than doing
// `[].slice.call(arguments)`
if (a) prop += '.' + toString(a);
if (b) prop += '.' + toString(b);
if (c) prop += '.' + toString(c);
if (prop in obj) {
return obj[prop];
}
var segs = prop.split('.');
var len = segs.length;
var i = -1;
while (obj && (++i < len)) {
var key = segs[i];
while (key[key.length - 1] === '\\') {
key = key.slice(0, -1) + '.' + segs[++i];
}
obj = obj[key];
}
return obj;
}...
var content = '';
var results = [];
// filter on a specific property
var prop = options.hash && options.hash.property;
if (prop) {
results = utils.filter(array, function(val) {
return utils.get(val, prop) === value;
});
} else {
// filter on a string value
results = utils.filter(array, function(v) {
return value === v;
});
...getArgs = function (app, args) {
var opts = utils.merge({}, app && app.options);
if (!Array.isArray(args)) {
args = [].slice.call(args);
}
var last = args[args.length - 1];
// merge `options.hash` into the options
if (utils.isOptions(last)) {
var hbsOptions = args.pop();
opts = utils.get(opts, hbsOptions.name) || opts;
opts = utils.merge({}, opts, hbsOptions.hash);
// if the last arg is an object, merge it
// into the options
} else if (utils.isObject(last)) {
opts = utils.merge({}, opts, args.pop());
}
args.push(opts);
return args;
}...
* @param {Array|String} `patterns` One or more glob patterns.
* @param {Object} `options`
* @return {Array} Array of matches
* @api public
*/
helpers.mm = function() {
var args = utils.getArgs(this, arguments);
return utils.mm.apply(utils.mm, args);
};
/**
* Returns an array of files that match the given glob pattern.
* Options may be passed on the hash or on `this.options`.
*
...function getObject(obj, prop) {
if (!prop) return obj;
if (!obj) return {};
var segs = String(prop).split(/[[.\]]/).filter(Boolean);
var last = segs[segs.length - 1], res = {};
while (prop = segs.shift()) {
obj = obj[prop];
if (!obj) return {};
}
if (isNumber(last)) return [obj];
res[last] = obj;
return res;
}...
* @param {String} `prop` The property to get, optionally using dot notation for nested properties.
* @param {Object} `context` The context object
* @return {String}
* @api public
*/
helpers.getObject = function(prop, context) {
return utils.getObject(context, prop);
};
/**
* Return true if `key` is an own, enumerable property
* of the given `context` object.
*
* ```handlebars
...identity = function (val) {
return val;
}n/a
function indexOf(arr, ele, start) {
start = start || 0;
var idx = -1;
if (arr == null) return idx;
var len = arr.length;
var i = start < 0
? (len + start)
: start;
if (i >= arr.length) {
return -1;
}
while (i < len) {
if (arr[i] === ele) {
return i;
}
i++;
}
return -1;
}...
* @param {Object} `options`
* @return {String}
* @block
* @api public
*/
helpers.inArray = function(array, value, options) {
if (utils.indexOf(array, value) > -1) {
return options.fn(this);
}
return options.inverse(this);
};
/**
* Returns true if `value` is an es5 array.
...isEmpty = function (val) {
if (val === 0 || val === '0') {
return false;
}
if (!val || (Array.isArray(val) && val.length === 0)) {
return true;
}
if (typeof val === 'object' && !Object.keys(val).length) {
return true;
}
return false;
}n/a
function isEven(i) {
if (!isNumber(i)) {
throw new TypeError('is-even expects a number.');
}
return !isOdd(i);
}...
* @param {Object} `options` Handlebars provided options object
* @return {String} Block, or inverse block if specified and falsey.
* @block
* @api public
*/
helpers.ifEven = function(num, options) {
return utils.isEven(num)
? options.fn(this)
: options.inverse(this);
};
/**
* Conditionally renders a block if the remainder is zero when
* `a` operand is divided by `b`. If an inverse block is specified
...function isGlob(str) {
if (typeof str !== 'string' || str === '') {
return false;
}
if (isExtglob(str)) return true;
var regex = /(\\).|([*?]|\[.*\]|\{.*\}|\(.*\|.*\)|^!)/;
var match;
while ((match = regex.exec(str))) {
if (match[2]) return true;
str = str.slice(match.index + match[0].length);
}
return false;
}...
}
if (utils.isRegex(filter)) {
var re = utils.toRegex(filter);
return files.filter(function(fp) {
return re.test(fp);
});
}
if (utils.isGlob(filter)) {
var isMatch = utils.mm.matcher(filter);
return files.filter(function(fp) {
return isMatch(fp);
});
}
if (['isFile', 'isDirectory'].indexOf(filter) !== -1) {
return files.filter(function(fp) {
...function isNumber(num) {
var type = typeOf(num);
if (type === 'string') {
if (!num.trim()) return false;
} else if (type !== 'number') {
return false;
}
return (num - num + 1) >= 0;
}...
* @param {Number} `n` Number of items to return, starting at `0`.
* @return {Array}
* @api public
*/
helpers.first = function(array, n) {
if (utils.isUndefined(array)) return '';
if (!utils.isNumber(n)) {
return array[0];
}
return array.slice(0, n);
};
/**
* Iterates over each item in an array and exposes the current item
...isObject = function (val) {
return val && typeof val === 'object'
&& !Array.isArray(val);
}...
* @block
* @api public
*/
helpers.iterate = function(context, options) {
if (Array.isArray(context)) {
return forEach.apply(forEach, arguments);
} else if (utils.isObject(context)) {
return forOwn.apply(forOwn, arguments);
}
return options.inverse(this);
};
/**
* Returns the length of the given collection. When using a string literal in the
...function isOdd(i) {
if (!isNumber(i)) {
throw new TypeError('is-odd expects a number.');
}
return !!(~~i & 1);
}...
* @param {Object} `options` Handlebars provided options object
* @return {String} Block, or inverse block if specified and falsey.
* @block
* @api public
*/
helpers.ifOdd = function(val, options) {
return utils.isOdd(val)
? options.fn(this)
: options.inverse(this);
};
/**
* Block helper that renders a block if `a` is **equal to** `b`.
* If an inverse block is specified it will be rendered when falsy.
...isOptions = function (val) {
return utils.isObject(val) && val.hasOwnProperty('hash');
}...
*/
helpers.readdir = function(dir, filter) {
var files = fs.readdirSync(dir);
files = files.map(function(fp) {
return path.join(dir, fp);
});
if (utils.isOptions(filter)) {
return files;
}
if (typeof filter === 'function') {
return filter(files);
}
if (utils.isRegex(filter)) {
var re = utils.toRegex(filter);
...isRegex = function (val) {
if (utils.typeOf(val) === 'regexp') {
return true;
}
if (typeof val !== 'string') {
return false;
}
return val.charAt(0) === '/'
&& val.slice(-1) === '\/';
}...
});
if (utils.isOptions(filter)) {
return files;
}
if (typeof filter === 'function') {
return filter(files);
}
if (utils.isRegex(filter)) {
var re = utils.toRegex(filter);
return files.filter(function(fp) {
return re.test(fp);
});
}
if (utils.isGlob(filter)) {
var isMatch = utils.mm.matcher(filter);
...isString = function (val) {
return val && typeof val === 'string';
}...
* ```
* @param {String} `value`
* @return {Boolean}
* @api public
*/
helpers.isString = function(value) {
return utils.isString(value);
};
/**
* Lowercase all characters in the given string.
*
* ```handlebars
* {{lowercase "Foo BAR baZ"}}
...isUndefined = function (val) {
return typeof val === 'undefined'
|| (val.hash != null);
}...
* @param {Array} `array` Collection
* @param {Number} `n` Starting index (number of items to exclude)
* @return {Array} Array exluding `n` items.
* @api public
*/
helpers.after = function(array, n) {
if (utils.isUndefined(array)) return '';
return array.slice(n);
};
/**
* Cast the given `value` to an array.
*
* ```handlebars
...function makeIterator(target, thisArg) {
switch (typeOf(target)) {
case 'undefined':
case 'null':
return noop;
case 'function':
// function is the first to improve perf (most common case)
// also avoid using `Function#call` if not needed, which boosts
// perf a lot in some cases
return (typeof thisArg !== 'undefined') ? function(val, i, arr) {
return target.call(thisArg, val, i, arr);
} : target;
case 'object':
return function(val) {
return deepMatches(val, target);
};
case 'regexp':
return function(str) {
return target.test(str);
};
case 'string':
case 'number':
default: {
return prop(target);
}
}
}...
* @param {Options} Handlebars provided options object
* @return {Array}
* @block
* @api public
*/
helpers.some = function(arr, cb, options) {
cb = utils.iterator(cb, this);
if (arr == null) {
return options.inverse(this);
}
var len = arr.length, i = -1;
while (++i < len) {
if (cb(arr[i], i, arr)) {
return options.fn(this);
...function mixinDeep(target, objects) {
var len = arguments.length, i = 0;
while (++i < len) {
var obj = arguments[i];
if (isObject(obj)) {
forIn(obj, copy, target);
}
}
return target;
}...
*
* @param {Object} `params`
* @return {String}
* @api public
*/
helpers.jsfiddle = function jsFiddle(options) {
var attr = object.merge({}, options, options.hash);
delete attr.name;
delete attr.hash;
delete attr.data;
if (typeof attr.id === 'undefined') {
throw new Error('jsfiddle helper expects an `id`');
}
...function micromatch(files, patterns, opts) {
if (!files || !patterns) return [];
opts = opts || {};
if (typeof opts.cache === 'undefined') {
opts.cache = true;
}
if (!Array.isArray(patterns)) {
return match(files, patterns, opts);
}
var len = patterns.length, i = 0;
var omit = [], keep = [];
while (len--) {
var glob = patterns[i++];
if (typeof glob === 'string' && glob.charCodeAt(0) === 33 /* ! */) {
omit.push.apply(omit, match(files, glob.slice(1), opts));
} else {
keep.push.apply(keep, match(files, glob, opts));
}
}
return utils.diff(keep, omit);
}n/a
function normalizePath(str, stripTrailing) {
if (typeof str !== 'string') {
throw new TypeError('expected a string');
}
str = str.replace(/[\\\/]+/g, '/');
if (stripTrailing !== false) {
str = removeTrailingSeparator(str);
}
return str;
}...
*
* @param {String} `filepath` The file path to split into segments.
* @return {String} Returns a single, joined file path.
* @api public
*/
helpers.segments = function(fp, a, b) {
return utils.normalize(fp).split('/').slice(a, b).join('/');
};
...random = function (min, max) {
return min + Math.floor(Math.random() * (max - min + 1));
}...
* @param {Number} `max`
* @contributor Tim Douglas <https://github.com/timdouglas>
* @return {String}
* @api public
*/
helpers.random = function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
/**
* Abbreviate numbers to the given number of `precision`. This is for
* general numbers, not size in bytes.
*
* @param {Number} `number`
...function relative(a, b, stat) {
if (typeof a !== 'string') {
throw new TypeError('relative expects a string.');
}
if (a == '' && !b) return a;
var len = arguments.length;
if (len === 1) {
b = a; a = process.cwd(); stat = null;
}
if (len === 2 && typeof b === 'boolean') {
b = a; a = process.cwd(); stat = true;
}
if (len === 2 && typeof b === 'object') {
stat = b; b = a; a = process.cwd();
}
var origB = b;
// see if a slash exists before normalizing
var slashA = endsWith(a, '/');
var slashB = endsWith(b, '/');
a = unixify(a);
b = unixify(b);
// if `a` had a slash, add it back
if (slashA) { a = a + '/'; }
if (isFile(a, stat)) {
a = path.dirname(a);
}
var res = path.relative(a, b);
if (res === '') {
return '.';
}
// if `b` originally had a slash, and the path ends
// with `b` missing a slash, then re-add the slash.
var noslash = trimEnd(origB, '/');
if (slashB && (res === noslash || endsWith(res, noslash))) {
res = res + '/';
}
return res;
}...
* @param {String} `a`
* @param {String} `b`
* @return {String}
* @api public
*/
helpers.relative = function(a, b) {
return utils.relative(a, b);
};
/**
* Get the file extension from the given `filepath`.
*
* ```handlebars
* {{basename "docs/toc.md"}}
...result = function (value) {
if (typeof value === 'function') {
return value();
}
return value;
}...
* @return {String}
* @block
* @api public
*/
helpers.withFirst = function(arr, idx, options) {
if (utils.isUndefined(arr)) return '';
arr = utils.result(arr);
if (!utils.isUndefined(idx)) {
idx = parseFloat(utils.result(idx));
}
if (utils.isUndefined(idx)) {
options = idx;
...function arraySort(arr, props, opts) {
if (arr == null) {
return [];
}
if (!Array.isArray(arr)) {
throw new TypeError('array-sort expects an array.');
}
if (arguments.length === 1) {
return arr.sort();
}
var args = flatten([].slice.call(arguments, 1));
// if the last argument appears to be a plain object,
// it's not a valid `compare` arg, so it must be options.
if (typeOf(args[args.length - 1]) === 'object') {
opts = args.pop();
}
return arr.sort(sortBy(args, opts));
}n/a
tag = function (tag, attribs, text) {
if (!isObject(attribs)) {
text = attribs;
attribs = {};
}
if (typeof text === 'undefined') {
text = '';
}
if (typeof text !== 'string') {
throw new TypeError('expected text to be a string');
}
var html = '<' + tag;
for (var key in attribs) {
var val = attribs[key];
if (val === true) {
html += ' ' + key;
}
if (typeof val === 'string') {
html += ' ' + key + '="' + val + '"';
}
}
if (voidElements.hasOwnProperty(tag)) {
return html + '>' + text;
}
return html + '>' + text + '</' + tag + '>';
}...
* ```
* @param {String} `id`
* @return {String}
* @api public
*/
helpers.gist = function(id) {
return utils.tag('script', {src: 'https://gist.github.com/' + id
+ '.js'});
};
/**
* Generate the HTML for a jsFiddle link with the given `params`
*
* ```handlebars
* {{jsfiddle id="0dfk10ks" tabs="true"}}
...toRegex = function (val) {
return new RegExp(val.replace(/^\/|\/$/g, ''));
}...
* `value` **{Object}**
* `returns` **{Boolean}**
**Example**
```js
utils.toRegex('"/foo/"');
//=> /foo/
```
### [{{isRegex}}](lib/utils/index.js#L69)
Returns true if the given value appears to be a
regular expression.
...tryParse = function (str) {
try {
return JSON.parse(str);
} catch (err) {}
return null;
}...
* @return {String}
* @api public
*/
helpers.map = function(array, fn) {
if (utils.isUndefined(array)) return '';
if (typeof array === 'string' && /[[]/.test(array)) {
array = utils.tryParse(array) || [];
}
var len = array.length;
var res = new Array(len);
var i = -1;
while (++i < len) {
res[i] = fn(array[i], i, array);
...function kindOf(val) {
// primitivies
if (typeof val === 'undefined') {
return 'undefined';
}
if (val === null) {
return 'null';
}
if (val === true || val === false || val instanceof Boolean) {
return 'boolean';
}
if (typeof val === 'string' || val instanceof String) {
return 'string';
}
if (typeof val === 'number' || val instanceof Number) {
return 'number';
}
// functions
if (typeof val === 'function' || val instanceof Function) {
return 'function';
}
// array
if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) {
return 'array';
}
// check for instances of RegExp and Date before calling `toString`
if (val instanceof RegExp) {
return 'regexp';
}
if (val instanceof Date) {
return 'date';
}
// other objects
var type = toString.call(val);
if (type === '[object RegExp]') {
return 'regexp';
}
if (type === '[object Date]') {
return 'date';
}
if (type === '[object Arguments]') {
return 'arguments';
}
if (type === '[object Error]') {
return 'error';
}
// buffer
if (typeof Buffer !== 'undefined' && isBuffer(val)) {
return 'buffer';
}
// es6: Map, WeakMap, Set, WeakSet
if (type === '[object Set]') {
return 'set';
}
if (type === '[object WeakSet]') {
return 'weakset';
}
if (type === '[object Map]') {
return 'map';
}
if (type === '[object WeakMap]') {
return 'weakmap';
}
if (type === '[object Symbol]') {
return 'symbol';
}
// typed arrays
if (type === '[object Int8Array]') {
return 'int8array';
}
if (type === '[object Uint8Array]') {
return 'uint8array';
}
if (type === '[object Uint8ClampedArray]') {
return 'uint8clampedarray';
}
if (type === '[object Int16Array]') {
return 'int16array';
}
if (type === '[object Uint16Array]') {
return 'uint16array';
}
if (type === '[object Int32Array]') {
return 'int32array';
}
if (type === '[object Uint32Array]') {
return 'uint32array';
}
if (type === '[object Float32Array]') {
return 'float32array';
}
if (type === '[object Float64Array]') {
return 'float64array';
}
// must be a plain object
return 'object';
}...
*
* @param {Object} `context`
* @return {String}
* @api public
*/
helpers.js = function(context) {
if (utils.typeOf(context) === 'object') {
var attr = html.toAttributes(context.hash);
return '<script' + attr + '></script>';
}
if (utils.typeOf(context) === 'string') {
return '<script src="' + context + '"></script>';
}
...function micromatch(files, patterns, opts) {
if (!files || !patterns) return [];
opts = opts || {};
if (typeof opts.cache === 'undefined') {
opts.cache = true;
}
if (!Array.isArray(patterns)) {
return match(files, patterns, opts);
}
var len = patterns.length, i = 0;
var omit = [], keep = [];
while (len--) {
var glob = patterns[i++];
if (typeof glob === 'string' && glob.charCodeAt(0) === 33 /* ! */) {
omit.push.apply(omit, match(files, glob.slice(1), opts));
} else {
keep.push.apply(keep, match(files, glob, opts));
}
}
return utils.diff(keep, omit);
}n/a
function any(fp, patterns, opts) {
if (!Array.isArray(patterns) && typeof patterns !== 'string') {
throw new TypeError(msg('any', 'patterns', 'a string or array'));
}
patterns = utils.arrayify(patterns);
var len = patterns.length;
fp = utils.unixify(fp, opts);
while (len--) {
var isMatch = matcher(patterns[len], opts);
if (isMatch(fp)) {
return true;
}
}
return false;
}n/a
braceExpand = function (str, options) {
if (typeof str !== 'string') {
throw new Error('braces expects a string');
}
return braces(str, options);
}n/a
braces = function (str, options) {
if (typeof str !== 'string') {
throw new Error('braces expects a string');
}
return braces(str, options);
}n/a
function contains(fp, pattern, opts) {
if (typeof fp !== 'string') {
throw new TypeError(msg('contains', 'pattern', 'a string'));
}
opts = opts || {};
opts.contains = (pattern !== '');
fp = utils.unixify(fp, opts);
if (opts.contains && !utils.isGlob(pattern)) {
return fp.indexOf(pattern) !== -1;
}
return matcher(pattern, opts)(fp);
}...
*/
helpers.contains = function(collection, value, startIndex, options) {
if (typeof startIndex === 'object') {
options = startIndex;
startIndex = undefined;
}
if (utils.contains(collection, value, startIndex)) {
return options.fn(this);
}
return options.inverse(this);
};
/**
* Block helper that renders a block if `a` is **greater than** `b`.
...function expand(pattern, options) {
if (typeof pattern !== 'string') {
throw new TypeError('micromatch.expand(): argument should be a string.');
}
var glob = new Glob(pattern, options || {});
var opts = glob.options;
if (!utils.isGlob(pattern)) {
glob.pattern = glob.pattern.replace(/([\/.])/g, '\\$1');
return glob;
}
glob.pattern = glob.pattern.replace(/(\+)(?!\()/g, '\\$1');
glob.pattern = glob.pattern.split('$').join('\\$');
if (typeof opts.braces !== 'boolean' && typeof opts.nobraces !== 'boolean') {
opts.braces = true;
}
if (glob.pattern === '.*') {
return {
pattern: '\\.' + star,
tokens: tok,
options: opts
};
}
if (glob.pattern === '*') {
return {
pattern: oneStar(opts.dot),
tokens: tok,
options: opts
};
}
// parse the glob pattern into tokens
glob.parse();
var tok = glob.tokens;
tok.is.negated = opts.negated;
// dotfile handling
if ((opts.dotfiles === true || tok.is.dotfile) && opts.dot !== false) {
opts.dotfiles = true;
opts.dot = true;
}
if ((opts.dotdirs === true || tok.is.dotdir) && opts.dot !== false) {
opts.dotdirs = true;
opts.dot = true;
}
// check for braces with a dotfile pattern
if (/[{,]\./.test(glob.pattern)) {
opts.makeRe = false;
opts.dot = true;
}
if (opts.nonegate !== true) {
opts.negated = glob.negated;
}
// if the leading character is a dot or a slash, escape it
if (glob.pattern.charAt(0) === '.' && glob.pattern.charAt(1) !== '/') {
glob.pattern = '\\' + glob.pattern;
}
/**
* Extended globs
*/
// expand braces, e.g `{1..5}`
glob.track('before braces');
if (tok.is.braces) {
glob.braces();
}
glob.track('after braces');
// expand extglobs, e.g `foo/!(a|b)`
glob.track('before extglob');
if (tok.is.extglob) {
glob.extglob();
}
glob.track('after extglob');
// expand brackets, e.g `[[:alpha:]]`
glob.track('before brackets');
if (tok.is.brackets) {
glob.brackets();
}
glob.track('after brackets');
// special patterns
glob._replace('[!', '[^');
glob._replace('(?', '(%~');
glob._replace(/\[\]/, '\\[\\]');
glob._replace('/[', '/' + (opts.dot ? dotfiles : nodot) + '[', true);
glob._replace('/?', '/' + (opts.dot ? dotfiles : nodot) + '[^/]', true);
glob._replace('/.', '/(?=.)\\.', true);
// windows drives
glob._replace(/^(\w):([\\\/]+?)/gi, '(?=.)$1:$2', true);
// negate slashes in exclusion ranges
if (glob.pattern.indexOf('[^') !== -1) {
glob.pattern = negateSlash(glob.pattern);
}
if (opts.globstar !== false && glob.pattern === '**') {
glob.pattern = globstar(opts.dot);
} else {
glob.pattern = balance(glob.pattern, '[', ']');
glob.escape(glob.pattern);
// if the pattern has `**`
if (tok.is.globstar) {
glob.pattern = collapse(glob.pattern, '/**');
glob.pattern = collapse(glob.pattern, '**/');
glob._replace('/**/', '(?:/' + globstar(opts.dot) + '/|/)', true);
glob._replace(/\*{2,}/g, '**');
// 'foo/*'
glob._replace(/(\w+)\*(?!\/)/g, '$1[^/]*?', true);
glob._replace(/\*\*\/\*(\w)/g, globstar(opts.dot) + '\\/' + (opts.dot ? dotfiles : nodot) + '[^/]*?$1', true);
if (opts.dot !== true) {
glob._replace(/\*\*\/(.)/g, '(?:**\\/|)$1');
}
// 'foo/**' or '{**,*}', but not 'foo**'
if (tok.path.dirname !== '' || /,\*\*|\*\*,/.test(glob.orig)) {
glob._replace('**', globstar(opts.dot), true);
}
}
// ends with /*
glob._replace(/\/\*$/, '\\/' + oneStar(opts.dot), true);
// ends with *, no slashes
glob._replace(/(?!\/)\*$/, star, true);
// has 'n*.' (partial wildcard w/ file extension)
glob._replace(/([^\/]+)\*/, '$1' + oneStar(true), true);
// has '*'
glob._replace('*', oneStar(opts.dot), true);
glob._replace('?.', '?\\.', true);
glob._replace('?:', '?:', true);
glob._replace(/\?+/g, function(match) {
var len = match.length;
if (len === 1) {
return qmark;
}
return qmark + '{' ...n/a
function filter(patterns, opts) {
if (!Array.isArray(patterns) && typeof patterns !== 'string') {
throw new TypeError(msg('filter', 'patterns', 'a string or array'));
}
patterns = utils.arrayify(patterns);
var len = patterns.length, i = 0;
var patternMatchers = Array(len);
while (i < len) {
patternMatchers[i] = matcher(patterns[i++], opts);
}
return function(fp) {
if (fp == null) return [];
var len = patternMatchers.length, i = 0;
var res = true;
fp = utils.unixify(fp, opts);
while (i < len) {
var fn = patternMatchers[i++];
if (!fn(fp)) {
res = false;
break;
}
}
return res;
};
}...
helpers.filter = function(array, value, options) {
var content = '';
var results = [];
// filter on a specific property
var prop = options.hash && options.hash.property;
if (prop) {
results = utils.filter(array, function(val) {
return utils.get(val, prop) === value;
});
} else {
// filter on a string value
results = utils.filter(array, function(v) {
return value === v;
...function isMatch(fp, pattern, opts) {
if (typeof fp !== 'string') {
throw new TypeError(msg('isMatch', 'filepath', 'a string'));
}
fp = utils.unixify(fp, opts);
if (utils.typeOf(pattern) === 'object') {
return matcher(fp, pattern);
}
return matcher(pattern, opts)(fp);
}n/a
function makeRe(glob, opts) {
if (utils.typeOf(glob) !== 'string') {
throw new Error(msg('makeRe', 'glob', 'a string'));
}
return utils.cache(toRegex, glob, opts);
}n/a
function match(files, pattern, opts) {
if (utils.typeOf(files) !== 'string' && !Array.isArray(files)) {
throw new Error(msg('match', 'files', 'a string or array'));
}
files = utils.arrayify(files);
opts = opts || {};
var negate = opts.negate || false;
var orig = pattern;
if (typeof pattern === 'string') {
negate = pattern.charAt(0) === '!';
if (negate) {
pattern = pattern.slice(1);
}
// we need to remove the character regardless,
// so the above logic is still needed
if (opts.nonegate === true) {
negate = false;
}
}
var _isMatch = matcher(pattern, opts);
var len = files.length, i = 0;
var res = [];
while (i < len) {
var file = files[i++];
var fp = utils.unixify(file, opts);
if (!_isMatch(fp)) { continue; }
res.push(fp);
}
if (res.length === 0) {
if (opts.failglob === true) {
throw new Error('micromatch.match() found no matches for: "' + orig + '".');
}
if (opts.nonull || opts.nullglob) {
res.push(utils.unescapeGlob(orig));
}
}
// if `negate` was defined, diff negated files
if (negate) { res = utils.diff(files, res); }
// if `ignore` was defined, diff ignored filed
if (opts.ignore && opts.ignore.length) {
pattern = opts.ignore;
opts = utils.omit(opts, ['ignore']);
res = utils.diff(res, micromatch(res, pattern, opts));
}
if (opts.nodupes) {
return utils.unique(res);
}
return res;
}...
* @return {String}
* @api public
*/
helpers.titleize = function(str) {
if (str && typeof str === 'string') {
var title = str.replace(/[ \-_]+/g, ' ');
var words = title.match(/\w+/g);
var len = words.length;
var res = [];
var i = 0;
while (len--) {
var word = words[i++];
res.push(exports.capitalize(word));
}
...function matchKeys(obj, glob, options) {
if (utils.typeOf(obj) !== 'object') {
throw new TypeError(msg('matchKeys', 'first argument', 'an object'));
}
var fn = matcher(glob, options);
var res = {};
for (var key in obj) {
if (obj.hasOwnProperty(key) && fn(key)) {
res[key] = obj[key];
}
}
return res;
}n/a
function matcher(pattern, opts) {
// pattern is a function
if (typeof pattern === 'function') {
return pattern;
}
// pattern is a regex
if (pattern instanceof RegExp) {
return function(fp) {
return pattern.test(fp);
};
}
if (typeof pattern !== 'string') {
throw new TypeError(msg('matcher', 'pattern', 'a string, regex, or function'));
}
// strings, all the way down...
pattern = utils.unixify(pattern, opts);
// pattern is a non-glob string
if (!utils.isGlob(pattern)) {
return utils.matchPath(pattern, opts);
}
// pattern is a glob string
var re = makeRe(pattern, opts);
// `matchBase` is defined
if (opts && opts.matchBase) {
return utils.hasFilename(re, opts);
}
// `matchBase` is not defined
return function(fp) {
fp = utils.unixify(fp, opts);
return re.test(fp);
};
}...
if (utils.isRegex(filter)) {
var re = utils.toRegex(filter);
return files.filter(function(fp) {
return re.test(fp);
});
}
if (utils.isGlob(filter)) {
var isMatch = utils.mm.matcher(filter);
return files.filter(function(fp) {
return isMatch(fp);
});
}
if (['isFile', 'isDirectory'].indexOf(filter) !== -1) {
return files.filter(function(fp) {
var stat = fs.statSync(fp);
...function relative(a, b, stat) {
if (typeof a !== 'string') {
throw new TypeError('relative expects a string.');
}
if (a == '' && !b) return a;
var len = arguments.length;
if (len === 1) {
b = a; a = process.cwd(); stat = null;
}
if (len === 2 && typeof b === 'boolean') {
b = a; a = process.cwd(); stat = true;
}
if (len === 2 && typeof b === 'object') {
stat = b; b = a; a = process.cwd();
}
var origB = b;
// see if a slash exists before normalizing
var slashA = endsWith(a, '/');
var slashB = endsWith(b, '/');
a = unixify(a);
b = unixify(b);
// if `a` had a slash, add it back
if (slashA) { a = a + '/'; }
if (isFile(a, stat)) {
a = path.dirname(a);
}
var res = path.relative(a, b);
if (res === '') {
return '.';
}
// if `b` originally had a slash, and the path ends
// with `b` missing a slash, then re-add the slash.
var noslash = trimEnd(origB, '/');
if (slashB && (res === noslash || endsWith(res, noslash))) {
res = res + '/';
}
return res;
}...
* @param {String} `a`
* @param {String} `b`
* @return {String}
* @api public
*/
helpers.relative = function(a, b) {
return utils.relative(a, b);
};
/**
* Get the file extension from the given `filepath`.
*
* ```handlebars
* {{basename "docs/toc.md"}}
...function toBase(base, fp) {
base = unixify(base);
fp = unixify(fp);
var res = fp.slice(base.length);
if (res.charAt(0) === '/') {
res = res.slice(1);
}
return res;
}n/a