load-templates
Advanced tools
Comparing version 0.3.2 to 0.4.0
@@ -1,33 +0,4 @@ | ||
--- | ||
tags: ['verb-tag-jscomments'] | ||
--- | ||
# {%= name %} {%= badge("fury") %} | ||
> {%= description %} | ||
This is a template loader, pure and simple, no rendering or caching. | ||
Currently any of the following input configurations will return a normalized template object with the same root properties: | ||
```js | ||
loader.load(['abc/*.hbs']); | ||
loader.load('abc/*.md'); | ||
loader.load({'abc/def.md': {content: 'ghi.', lmn: 'xyz'}); | ||
loader.load({'abc/def.md': {content: 'ghi.'}}, {lmn: 'xyz'}); | ||
loader.load({path: 'abc/def.md', content: 'ghi.'}, {lmn: 'xyz'}); | ||
loader.load({path: 'abc/def.md', content: 'ghi.', lmn: 'xyz'}); | ||
loader.load('abc.md', 'def <%= name %>.'); | ||
loader.load('abc.md', 'def <%= name %>.', {name: 'Jon Schlinkert'}); | ||
``` | ||
**Root properties** | ||
* `path`: file path or key to use for the template. | ||
* `data`: data from the parsed template, e.g. front-matter. | ||
* `locals`: locals pass on one of the loader methods. (keeping locals and data seperate allows you to merge however you need to.) | ||
* `content`: the parsed content of the template | ||
* `orig`: the original content of the template, if parsed | ||
Properties that are not on this list will be moved/copied to the `data` object and retained on `orig`. | ||
## Install | ||
@@ -42,5 +13,13 @@ {%= include("install") %} | ||
## API | ||
{%= jscomments("index.js") %} | ||
## Usage | ||
```js | ||
var loader = require('{%= name %}'); | ||
``` | ||
### Valid formats | ||
See [the docs](./docs.md) for valid formats. WIP. | ||
## Author | ||
@@ -47,0 +26,0 @@ {%= include("author") %} |
689
index.js
@@ -0,36 +1,72 @@ | ||
/*! | ||
* load-templates <https://github.com/jonschlinkert/load-templates> | ||
* | ||
* Copyright (c) 2014 Jon Schlinkert, contributors. | ||
* Licensed under the MIT License | ||
*/ | ||
'use strict'; | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var typeOf = require('kind-of'); | ||
var extend = require('mixin-deep'); | ||
var hasAny = require('has-any'); | ||
var debug = require('debug')('load-templates'); | ||
var hasAnyDeep = require('has-any-deep'); | ||
var omit = require('omit-keys'); | ||
var mapFiles = require('map-files'); | ||
var matter = require('gray-matter'); | ||
var omitEmpty = require('omit-empty'); | ||
var reduce = require('reduce-object'); | ||
var utils = require('./lib/utils'); | ||
var _ = require('lodash'); | ||
/** | ||
* Module dependencies | ||
* If we detected a `path` property directly on the object | ||
* that was passed, this means that the object is not | ||
* formatted with a key (as expected). | ||
* | ||
* ```js | ||
* // before | ||
* loader({path: 'a/b/c.md', content: 'this is foo'}); | ||
* | ||
* // after | ||
* loader('a/b/c.md': {path: 'a/b/c.md', content: 'this is foo'}); | ||
* ``` | ||
* | ||
* @param {String} `path` | ||
* @param {Object} `value` | ||
* @return {Object} | ||
*/ | ||
var _ = require('lodash'); | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var glob = require('globby'); | ||
var isRelative = require('is-relative'); | ||
var arrayify = require('arrayify-compact'); | ||
var extend = _.extend; | ||
function createKeyFromPath(filepath, value) { | ||
var o = {}; | ||
o[filepath] = value; | ||
return o; | ||
} | ||
/** | ||
* Create the `path` property from the string | ||
* passed in the first arg. This is only used | ||
* when the second arg is a string. | ||
* | ||
* ```js | ||
* var loader = require('load-templates'); | ||
* loader('abc', {content: 'this is content'}); | ||
* //=> normalize('abc', {path: 'abc', content: 'this is content'}); | ||
* ``` | ||
* @param {Object} `options` Options to initialize `loader` with | ||
* @option {String} [option] `cwd` Current working directory to use for file paths. | ||
* @option {Function} [option] `parse` Function to use for parsing templates. | ||
* @option {Function} [option] `rename` Renaming function to use on the `key` of each template loaded, `path.basename` is the default. | ||
* @option {Function} [option] `normalize` Function to use for normalizing `file` objects before they are returned. | ||
* @option {Boolean} [option] `norename` Set to `true` to disable the default `rename` function. | ||
* @option {Boolean} [option] `noparse` Set to `true` to disable the default `parse` function. | ||
* @option {Boolean} [option] `nonormalize` Set to `true` to disable the default `normalize` function. | ||
* @api public | ||
* | ||
* @param {Object} a | ||
* @return {Object} | ||
*/ | ||
function loader(options) { | ||
loader.options = extend({ | ||
cwd: process.cwd() | ||
}, options); | ||
return loader; | ||
function createPathFromStringKey(o) { | ||
for (var key in o) { | ||
if (o.hasOwnProperty(key)) { | ||
o[key].path = o[key].path || key; | ||
} | ||
} | ||
return o; | ||
} | ||
@@ -40,243 +76,546 @@ | ||
/** | ||
* Options cache. | ||
* Default function for reading any files resolved. | ||
* | ||
* @type {Object} | ||
* Pass a custom `parseFn` function on the options to change | ||
* how files are parsed. | ||
* | ||
* @param {String} `filepath` | ||
* @param {Object} `options` | ||
* @return {Object} | ||
*/ | ||
loader.options = {}; | ||
function readFn(filepath, options) { | ||
var opts = extend({ enc: 'utf8' }, options); | ||
if (opts.readFn) { | ||
return opts.readFn(filepath, options); | ||
} | ||
return fs.readFileSync(filepath, opts.enc); | ||
} | ||
/** | ||
* Properties expected on the root of a normalized `file` object. | ||
* Default function for parsing any files resolved. | ||
* | ||
* @type {Array} | ||
* Pass a custom `parseFn` function on the options to change | ||
* how files are parsed. | ||
* | ||
* @param {String} `filepath` | ||
* @param {Object} `options` | ||
* @return {Object} | ||
*/ | ||
loader.rootProps = ['data', 'locals', 'content', 'path', 'orig']; | ||
function parseFn(str, options) { | ||
var opts = extend({ autodetect: true }, options); | ||
if (opts.parseFn) { | ||
return opts.parseFn(str, options); | ||
} | ||
opts = omit(options, ['delims']); | ||
return matter(str, opts); | ||
} | ||
/** | ||
* Expand glob patterns, load, read, parse and normalize files from | ||
* file paths, strings, objects, or arrays of these types. | ||
* [parseContent description] | ||
* | ||
* **Examples:** | ||
* @param {[type]} value | ||
* @param {[type]} options | ||
* @return {[type]} | ||
*/ | ||
function parseContent(obj, options) { | ||
debug('parsing content', obj); | ||
var o = extend({}, obj); | ||
if (utils.isString(o.content) && !o.hasOwnProperty('orig')) { | ||
var orig = o.content; | ||
o = parseFn(o.content, options); | ||
o.orig = orig; | ||
} | ||
o._parsed = true; | ||
return o; | ||
} | ||
/** | ||
* Rename the key of a template object. | ||
* | ||
* Filepaths or arrays of glob patterns. | ||
* Pass a custom `renameKey` function on the options to change | ||
* how keys are renamed. | ||
* | ||
* ```js | ||
* var temlates = loader.load(['pages/*.hbs']); | ||
* var posts = loader.load('posts/*.md'); | ||
* ``` | ||
* @param {String} `key` | ||
* @param {Object} `options` | ||
* @return {Object} | ||
*/ | ||
function renameKey(key, options) { | ||
debug('renaming key:', key); | ||
var opts = options || {}; | ||
if (opts.renameKey) { | ||
return opts.renameKey(key, options); | ||
} | ||
return key; | ||
} | ||
/** | ||
* Map files resolved from glob patterns or file paths. | ||
* | ||
* As strings or objects: | ||
* | ||
* @param {String|Array} `patterns` | ||
* @param {Object} `options` | ||
* @return {Object} | ||
*/ | ||
function mapFilesFn(patterns, options) { | ||
debug('mapping files:', patterns); | ||
var files = mapFiles(patterns, extend({ | ||
rename: renameKey, | ||
parse: readFn | ||
}, options)); | ||
return reduce(files, function (acc, value, key) { | ||
debug('reducing file: %s', key, value); | ||
if (utils.isString(value)) { | ||
value = parseFn(value); | ||
value.path = value.path || key; | ||
} | ||
value._parsed = true; | ||
value._mappedFile = true; | ||
acc[key] = value; | ||
return acc; | ||
}, {}); | ||
} | ||
/** | ||
* First arg is a file path or glob pattern. | ||
* | ||
* ```js | ||
* // loader.load(key, value, locals); | ||
* var docs = loader.load({'foo/bar.md': {content: 'this is content.'}}, {foo: 'bar'}); | ||
* | ||
* // loader.load(key, value, locals); | ||
* var post = loader.load('abc.md', 'My name is <%= name %>.', {name: 'Jon Schlinkert'}); | ||
* loader('a/b/c.md', ...); | ||
* loader('a/b/*.md', ...); | ||
* ``` | ||
* | ||
* @param {String|Object|Array} `key` Array, object, string or file paths. | ||
* @param {String|Object} `value` String of content, `file` object with `content` property, or `locals` if the first arg is a file path. | ||
* @param {Object} `options` Options or `locals`. | ||
* @return {Object} Normalized file object. | ||
* @api public | ||
* @param {String} `key` | ||
* @param {Object} `value` | ||
* @return {Object} | ||
*/ | ||
loader.load = function (key, value, options) { | ||
var method = loader[typeOf(key)]; | ||
if (method) { | ||
return method.call(this, key, value, options); | ||
function normalizeFiles(patterns, locals, options) { | ||
debug('normalizing patterns: %s', patterns); | ||
var files = mapFilesFn(patterns, options); | ||
var locs = {}; | ||
var opts = {}; | ||
if (locals && utils.isObject(locals)) { | ||
locs = utils.pickLocals(locals); | ||
opts = utils.pickOptions(locals); | ||
} | ||
}; | ||
if (options && utils.isObject(options)) { | ||
opts = _.merge({}, opts, options); | ||
} | ||
if (files && Object.keys(files).length === 0) { | ||
return null; | ||
} | ||
return reduce(files, function (acc, value, key) { | ||
debug('reducing normalized file: %s', key); | ||
extend(opts, options); | ||
value.options = utils.flattenOptions(opts); | ||
value.locals = utils.flattenLocals(locs); | ||
acc[key] = value; | ||
return acc; | ||
}, {}); | ||
} | ||
/** | ||
* Expand glob patterns, load, read, parse and normalize files | ||
* from file paths or strings. | ||
* First value is a string, second value is a string or | ||
* an object. | ||
* | ||
* @param {String} `key` Glob patterns or file paths. | ||
* @param {String|Object} `value` String of content, `file` object with `content` property, or `locals` if the first arg is a file path. | ||
* @param {Object} `options` Options or `locals`. | ||
* @return {Object} Normalized file object. | ||
* @api public | ||
* - first arg can be a file-path | ||
* - first arg can be a non-file-path string | ||
* - first arg can be a glob pattern | ||
* - second arg can a string | ||
* - when the second arg is a string, the first arg cannot be a file path | ||
* - the second can be an object | ||
* - when the second arg is an object, it may _be_ locals | ||
* - when the second arg is an object, it may _have_ an `options` property | ||
* - the second can be an object | ||
* - in this pattern, when a third arg exists, it _must be_ the options object. | ||
* - when a third arg exists, the second arg may still have an options property | ||
* - when a third arg exists, `options` and `locals.options` are merged. | ||
* | ||
* **Examples:** | ||
* | ||
* ```js | ||
* template.normalize('a/b/c.md'); | ||
* template.normalize('a/b/c.md', 'this is content'); | ||
* template.normalize('a/b/c.md', {content: 'this is content'}); | ||
* template.normalize('a/b/c.md', {path: 'a/b/c.md'}); | ||
* template.normalize('a/b/c.md', {path: 'a/b/c.md', content: 'this is content'}); | ||
* template.normalize('a/b/c.md', {path: 'a/b/c.md'}, {a: 'b'}); | ||
* template.normalize('a/b/c.md', {path: 'a/b/c.md'}, {a: 'b'}, {c: 'd'}); | ||
* template.normalize('a/b/c.md', {path: 'a/b/c.md'}, {a: 'b', options: {c: 'd'}}); | ||
* template.normalize('a/b/c.md', {path: 'a/b/c.md', locals: {a: 'b'}, options: {c: 'd'}}); | ||
* ``` | ||
* | ||
* @param {Object} `value` Always an object. | ||
* @param {Object} `locals` Always an object. | ||
* @param {Object} `options` Always an object. | ||
* @return {Object} Returns a normalized object. | ||
*/ | ||
loader.string = function (key, value, options) { | ||
var args = [].slice.call(arguments).filter(Boolean); | ||
var file = {}, files = []; | ||
function normalizeString(key, value, locals, options) { | ||
debug('normalizing string: %s', key, value); | ||
if (typeof args[1] === 'string') { | ||
file[key] = {}; | ||
file[key].content = value; | ||
} else { | ||
var patterns = arrayify(key).map(function(pattern) { | ||
if (!isRelative) { | ||
return pattern; | ||
} | ||
return loader._cwd(pattern); | ||
}); | ||
var objects = utils.valuesOfType('object', arguments); | ||
var args = [].slice.call(arguments, 1); | ||
var props = utils.siftProps.apply(utils.siftProps, args); | ||
var opts = options || props.options; | ||
var locs = props.locals; | ||
var files; | ||
var root = {}; | ||
var opt = {}; | ||
var o = {}; | ||
o[key] = {}; | ||
files = glob.sync(patterns, {nonull: false}); | ||
if (files.length > 0) { | ||
files.forEach(function (filepath) { | ||
var key = loader.rename(filepath); | ||
file[key] = loader.parse(filepath); | ||
file[key].path = filepath; | ||
file[key].data = extend({}, file[key].data, value); | ||
}); | ||
// If only `key` is defined | ||
if (value == null) { | ||
// see if `key` is a value file path | ||
files = normalizeFiles(key); | ||
if (files != null) { | ||
return files; | ||
// if not, add a heuristic | ||
} else { | ||
file[key] = value || {}; | ||
o[key]._invalidpath = true; | ||
o[key].path = o[key].path || key; | ||
return o; | ||
} | ||
} | ||
// The object should be parsed and key renamed. | ||
return loader.object(file, options); | ||
}; | ||
if ((value && utils.isObject(value)) || objects == null) { | ||
debug('[value] s1o1: %s, %j', key, value); | ||
files = normalizeFiles(key, value, locals, options); | ||
if (files != null) { | ||
return files; | ||
} else { | ||
debug('[value] s1o2: %s, %j', key, value); | ||
root = utils.pickRoot(value); | ||
var loc = {}; | ||
opt = {}; | ||
loc = _.merge({}, loc, utils.pickLocals(value)); | ||
loc = _.merge({}, loc, locals); | ||
opt = _.merge({}, opt, loc.options); | ||
opt = _.merge({}, opt, value.options); | ||
opt = _.merge({}, opt, options); | ||
_.merge(root, utils.pickRoot(loc)); | ||
_.merge(root, utils.pickRoot(opt)); | ||
o[key] = root; | ||
o[key].locals = loc; | ||
o[key].options = opt; | ||
o[key].path = value.path || key; | ||
var content = value && value.content; | ||
if (o[key].content == null && content != null) { | ||
o[key].content = content; | ||
} | ||
} | ||
} | ||
if (value && utils.isString(value)) { | ||
debug('[value] string: %s, %s', key, value); | ||
root = utils.pickRoot(locals); | ||
o[key] = root; | ||
o[key].content = value; | ||
o[key].path = o[key].path = key; | ||
o[key]._s1s2 = true; | ||
if (objects == null) { | ||
return o; | ||
} | ||
} | ||
// TODO: when would this happen? | ||
if (locals && utils.isObject(locals)) { | ||
o[key]._s1s2o1 = true; | ||
} | ||
// TODO: when would this happen? | ||
if (options && utils.isObject(options)) { | ||
o[key]._s1s2o1o2 = true; | ||
} | ||
opt = utils.flattenOptions(opts); | ||
opt = extend({}, opt, o[key].options); | ||
o[key].options = opt; | ||
locs = omit(locs, 'options'); | ||
o[key].locals = utils.flattenLocals(locs); | ||
return o; | ||
} | ||
/** | ||
* Normalize an array of patterns. | ||
* Normalize objects that have `rootKeys` directly on | ||
* the root of the object. | ||
* | ||
* @param {Object} `patterns` Glob patterns or array of filepaths. | ||
* @param {Object} `options` Options or `locals` | ||
* @return {Array} Array of normalized file objects. | ||
* @api public | ||
* **Example** | ||
* | ||
* ```js | ||
* {path: 'a/b/c.md', content: 'this is content.'} | ||
* ``` | ||
* | ||
* @param {Object} `value` Always an object. | ||
* @param {Object} `locals` Always an object. | ||
* @param {Object} `options` Always an object. | ||
* @return {Object} Returns a normalized object. | ||
*/ | ||
loader.array = function (patterns, options) { | ||
var o = {}; | ||
arrayify(patterns).forEach(function (pattern) { | ||
extend(o, loader.load(pattern, options)); | ||
}); | ||
function normalizeShallowObject(value, locals, options) { | ||
debug('normalizing shallow object: %j', value); | ||
var o = utils.siftLocals(value); | ||
o.options = extend({}, options, o.options); | ||
o.locals = extend({}, locals, o.locals); | ||
return o; | ||
}; | ||
} | ||
/** | ||
* Normalize a template object. | ||
* Normalize nested templates that have the following pattern: | ||
* | ||
* @param {Object} `file` The object to normalize. | ||
* @param {Object} `options` Options or `locals` | ||
* @api public | ||
* ```js | ||
* => {'a/b/c.md': {path: 'a/b/c.md', content: 'this is content.'}} | ||
* ``` | ||
* or: | ||
* | ||
* ```js | ||
* { 'a/b/a.md': {path: 'a/b/a.md', content: 'this is content.'}, | ||
* 'a/b/b.md': {path: 'a/b/b.md', content: 'this is content.'}, | ||
* 'a/b/c.md': {path: 'a/b/c.md', content: 'this is content.'} } | ||
*``` | ||
*/ | ||
loader.object = function (file, options) { | ||
return this.normalize(file, options); | ||
}; | ||
function normalizeDeepObject(obj, locals, options) { | ||
debug('normalizing deep object: %j', obj); | ||
return reduce(obj, function (acc, value, key) { | ||
acc[key] = normalizeShallowObject(value, locals, options); | ||
return acc; | ||
}, {}); | ||
} | ||
/** | ||
* The current working directory to use. Default is `process.cwd()`. | ||
* When the first arg is an object, all arguments | ||
* should be objects. | ||
* | ||
* @param {String} `filepath` | ||
* @api public | ||
* ```js | ||
* loader({'a/b/c.md', ...}); | ||
* | ||
* // or | ||
* loader({path: 'a/b/c.md', ...}); | ||
* ``` | ||
* | ||
* @param {Object} `object` Template object | ||
* @param {Object} `locals` Possibly locals, with `options` property | ||
* @return {Object} `options` Possibly options | ||
*/ | ||
loader._cwd = function (filepath) { | ||
var cwd = path.resolve(this.options.cwd); | ||
return path.join(cwd, filepath); | ||
}; | ||
function normalizeObject(o) { | ||
debug('normalizing object: %j', o); | ||
var args = [].slice.call(arguments); | ||
var locals1 = utils.pickLocals(args[1]); | ||
var locals2 = utils.pickLocals(args[2]); | ||
var val; | ||
var opts = args.length === 3 ? locals2 : {}; | ||
if (hasAny(o, ['path', 'content'])) { | ||
val = normalizeShallowObject(o, locals1, opts); | ||
return createKeyFromPath(val.path, val); | ||
} | ||
if (hasAnyDeep(o, ['path', 'content'])) { | ||
val = normalizeDeepObject(o, locals1, opts); | ||
return createPathFromStringKey(val); | ||
} | ||
throw new Error('Invalid template object. Must' + | ||
'have a `path` or `content` property.'); | ||
} | ||
/** | ||
* Rename the `key` of each template loaded using whatever rename function | ||
* is defined on the options. `path.basename` is the default. | ||
* When the first arg is an array, assume it's glob | ||
* patterns or file paths. | ||
* | ||
* @param {String} `filepath` | ||
* @api public | ||
* ```js | ||
* loader(['a/b/c.md', 'a/b/*.md']); | ||
* ``` | ||
* | ||
* @param {Object} `patterns` Template object | ||
* @param {Object} `locals` Possibly locals, with `options` property | ||
* @return {Object} `options` Possibly options | ||
*/ | ||
loader.rename = function (filepath) { | ||
if (this.options.rename) { | ||
return this.options.rename(filepath); | ||
} | ||
return filepath; | ||
}; | ||
function normalizeArray(patterns, locals, options) { | ||
debug('normalizing array:', patterns); | ||
var opts = extend({}, locals && locals.options, options); | ||
return normalizeFiles(patterns, locals, opts); | ||
} | ||
/** | ||
* Parse the content of each template loaded using whatever parsing function | ||
* is defined on the options. `fs.readFileSync` is used by default. | ||
* When the first arg is an array, assume it's glob | ||
* patterns or file paths. | ||
* | ||
* @param {String} `filepath` The path of the file to read/parse. | ||
* @param {Object} `Options` Options or `locals`. | ||
* @api public | ||
* ```js | ||
* loader(['a/b/c.md', 'a/b/*.md']); | ||
* ``` | ||
* | ||
* @param {Object} `patterns` Template object | ||
* @param {Object} `locals` Possibly locals, with `options` property | ||
* @return {Object} `options` Possibly options | ||
*/ | ||
loader.parse = function (filepath, options) { | ||
var remove = _.keys(this.options).concat('normalized'); | ||
var opts = extend({}, this.options, options); | ||
var o = {}; | ||
function normalizeFn(fn, options) { | ||
var file = fn.call(null, options); | ||
debug('normalizing fn:', file); | ||
return file; | ||
} | ||
if (opts.noparse) { | ||
return filepath; | ||
} | ||
if (opts.parse) { | ||
return opts.parse(filepath, _.omit(opts, remove)); | ||
/** | ||
* Normalize base template formats. | ||
*/ | ||
function normalizeFormat() { | ||
var args = [].slice.call(arguments); | ||
debug('normalize format', args); | ||
switch (typeOf(args[0])) { | ||
case 'string': | ||
return normalizeString.apply(null, args); | ||
case 'object': | ||
return normalizeObject.apply(null, args); | ||
case 'array': | ||
return normalizeArray.apply(null, args); | ||
case 'function': | ||
return normalizeFn.apply(null, args); | ||
default: | ||
return {}; | ||
} | ||
} | ||
o.path = filepath; | ||
o.content = fs.readFileSync(filepath, 'utf8'); | ||
o.data = _.omit(opts, remove); | ||
return o; | ||
}; | ||
/** | ||
* Normalize a template using whatever normalize function is | ||
* defined on the options. | ||
* Final normalization step to remove empty values and rename | ||
* the object key. By now the template should be _mostly_ | ||
* loaderd. | ||
* | ||
* @param {Object} `file` The template object to normalize. | ||
* @param {Object} `Options` Options or `locals`. | ||
* @api public | ||
* @param {Object} `object` Template object | ||
* @return {Object} | ||
*/ | ||
loader.normalize = function (file, options) { | ||
var remove = _.keys(this.options).concat('normalized'); | ||
var opts = _.extend({}, this.options, options); | ||
var loader = function (options) { | ||
options = extend({}, options); | ||
debug('loader', options); | ||
if (opts.nonormalize) { | ||
return file; | ||
} | ||
return function(obj) { | ||
debug('pre-normalize', obj); | ||
if (opts.normalize) { | ||
return opts.normalize(file); | ||
} | ||
var o = {}, data = _.omit(opts, remove); | ||
obj = normalizeFormat.apply(null, arguments); | ||
_.forIn(file, function (value, key) { | ||
value.path = value.path || key; | ||
return reduce(obj, function (acc, value, key) { | ||
if (value && Object.keys(value).length === 0) { | ||
return acc; | ||
} | ||
if (!value.hasOwnProperty('normalized')) { | ||
key = loader.rename(key); | ||
delete value.normalized; | ||
} | ||
// save the content for comparison after parsing | ||
var opts = {}; | ||
var root = _.pick(value, loader.rootProps); | ||
root.data = extend({}, data, value.data, _.omit(value, loader.rootProps)); | ||
o[key] = root; | ||
}); | ||
extend(opts, options, value.options); | ||
value.ext = value.ext || path.extname(value.path); | ||
return o; | ||
var parsed = parseContent(value, opts); | ||
value = _.merge({}, value, parsed); | ||
if (value.content === value.orig) { | ||
value = omit(value, 'orig'); | ||
} | ||
if (opts.debug == null) { | ||
value = omit(value, utils.heuristics); | ||
} | ||
value = omitEmpty(value); | ||
acc[renameKey(key, opts)] = value; | ||
loader.normalize(opts, acc, value, key); | ||
return acc; | ||
}, {}); | ||
}; | ||
}; | ||
loader.normalize = function (options, acc, value, key) { | ||
debug('normalize: %s, %value', key); | ||
if (options && options.normalize) { | ||
return options.normalize(acc, value, key); | ||
} | ||
acc[key] = value; | ||
return acc; | ||
}; | ||
loader.valueOnly = function (options) { | ||
debug('valueOnly:', options); | ||
var fn = loader(options); | ||
return function(obj) { | ||
return reduce(fn(obj), function(acc, value) { | ||
value.ext = value.ext || path.extname(value.path); | ||
return value; | ||
}, {}); | ||
}; | ||
}; | ||
/** | ||
* Get the type of an object. | ||
* Expose utils | ||
*/ | ||
loader.generateKey = utils.generateKey; | ||
loader.generateId = utils.generateId; | ||
/** | ||
* Expose `loader` | ||
* | ||
* @param {*} value | ||
* @return {*} | ||
* @api private | ||
* @type {Object} | ||
*/ | ||
function typeOf(value) { | ||
return Object.prototype.toString.call(value).toLowerCase() | ||
.replace(/\[object ([\S]+)\]/, '$1'); | ||
} | ||
module.exports = loader; |
{ | ||
"name": "load-templates", | ||
"description": "Load templates from file paths, globs or objects, and cache them as normalized objects.", | ||
"version": "0.3.2", | ||
"description": "Load templates.", | ||
"version": "0.4.0", | ||
"homepage": "https://github.com/jonschlinkert/load-templates", | ||
@@ -23,66 +23,2 @@ "author": { | ||
], | ||
"keywords": [ | ||
"assemble", | ||
"atpl", | ||
"cache", | ||
"compile", | ||
"consolidate", | ||
"content", | ||
"data", | ||
"delimiters", | ||
"delims", | ||
"docs", | ||
"documentation", | ||
"dot", | ||
"dust", | ||
"dustjs-helpers", | ||
"dustjs-linkedin", | ||
"eco", | ||
"ect", | ||
"ejs", | ||
"engine", | ||
"engines", | ||
"express", | ||
"front", | ||
"generate", | ||
"generator", | ||
"gray-matter", | ||
"haml-coffee", | ||
"hamljs", | ||
"handlebars", | ||
"hogan.js", | ||
"jade", | ||
"jazz", | ||
"jqtpl", | ||
"liquor", | ||
"lo-dash", | ||
"lodash", | ||
"markdown", | ||
"matter", | ||
"mocha", | ||
"mote", | ||
"mustache", | ||
"noop", | ||
"nunjucks", | ||
"parse", | ||
"parser", | ||
"parsers", | ||
"pass-through", | ||
"process", | ||
"qejs", | ||
"ractive", | ||
"render", | ||
"should", | ||
"swig", | ||
"template", | ||
"templates", | ||
"templayed", | ||
"toffee", | ||
"underscore", | ||
"verb", | ||
"view", | ||
"walrus", | ||
"whiskers", | ||
"yaml" | ||
], | ||
"main": "index.js", | ||
@@ -96,13 +32,32 @@ "engines": { | ||
"devDependencies": { | ||
"chalk": "^0.5.1", | ||
"gray-matter": "^0.5.1", | ||
"mocha": "*", | ||
"should": "^4.0.4", | ||
"verb": ">= 0.2.6", | ||
"verb-tag-jscomments": "^0.2.2" | ||
"verb-tag-jscomments": ">= 0.2.0" | ||
}, | ||
"keywords": [ | ||
"load", | ||
"loader", | ||
"cache", | ||
"templates" | ||
], | ||
"dependencies": { | ||
"arrayify-compact": "^0.1.0", | ||
"globby": "^0.1.1", | ||
"is-relative": "^0.1.1", | ||
"lodash": "^2.4.1" | ||
"array-slice": "^0.2.0", | ||
"debug": "^2.0.0", | ||
"gray-matter": "^0.5.0", | ||
"has-any": "^0.1.0", | ||
"has-any-deep": "^0.2.0", | ||
"is-plain-object": "^0.1.0", | ||
"kind-of": "^0.1.0", | ||
"lodash": "^2.4.1", | ||
"map-files": "^0.1.2", | ||
"mixin-deep": "^0.1.0", | ||
"object-pick": "^0.1.0", | ||
"omit-empty": "^0.2.0", | ||
"omit-keys": "^0.1.0", | ||
"reduce-object": "^0.1.2", | ||
"uniqueid": "^0.1.0" | ||
} | ||
} |
117
README.md
@@ -1,30 +0,5 @@ | ||
# load-templates [![NPM version](https://badge.fury.io/js/load-templates.png)](http://badge.fury.io/js/load-templates) | ||
# load-templates [![NPM version](https://badge.fury.io/js/load-templates.svg)](http://badge.fury.io/js/load-templates) | ||
> Load templates from file paths, globs or objects, and cache them as normalized objects. | ||
> Load templates. | ||
This is a template loader, pure and simple, no rendering or caching. | ||
Currently any of the following input configurations will return a normalized template object with the same root properties: | ||
```js | ||
loader.load(['abc/*.hbs']); | ||
loader.load('abc/*.md'); | ||
loader.load({'abc/def.md': {content: 'ghi.', lmn: 'xyz'}); | ||
loader.load({'abc/def.md': {content: 'ghi.'}}, {lmn: 'xyz'}); | ||
loader.load({path: 'abc/def.md', content: 'ghi.'}, {lmn: 'xyz'}); | ||
loader.load({path: 'abc/def.md', content: 'ghi.', lmn: 'xyz'}); | ||
loader.load('abc.md', 'def <%= name %>.'); | ||
loader.load('abc.md', 'def <%= name %>.', {name: 'Jon Schlinkert'}); | ||
``` | ||
**Root properties** | ||
* `path`: file path or key to use for the template. | ||
* `data`: data from the parsed template, e.g. front-matter. | ||
* `locals`: locals pass on one of the loader methods. (keeping locals and data seperate allows you to merge however you need to.) | ||
* `content`: the parsed content of the template | ||
* `orig`: the original content of the template, if parsed | ||
Properties that are not on this list will be moved/copied to the `data` object and retained on `orig`. | ||
## Install | ||
@@ -43,7 +18,4 @@ #### Install with [npm](npmjs.org): | ||
## API | ||
### [loader](index.js#L31) | ||
## Usage | ||
* `options` **{Object}**: Options to initialize `loader` with | ||
```js | ||
@@ -53,84 +25,7 @@ var loader = require('load-templates'); | ||
### [.load](index.js#L87) | ||
### Valid formats | ||
Expand glob patterns, load, read, parse and normalize files from file paths, strings, objects, or arrays of these types. | ||
See [the docs](./docs.md) for valid formats. WIP. | ||
* `key` **{String|Object|Array}**: Array, object, string or file paths. | ||
* `value` **{String|Object}**: String of content, `file` object with `content` property, or `locals` if the first arg is a file path. | ||
* `options` **{Object}**: Options or `locals`. | ||
* `returns` **{Object}**: Normalized file object. | ||
**Examples:** | ||
Filepaths or arrays of glob patterns. | ||
```js | ||
var temlates = loader.load(['pages/*.hbs']); | ||
var posts = loader.load('posts/*.md'); | ||
``` | ||
As strings or objects: | ||
```js | ||
// loader.load(key, value, locals); | ||
var docs = loader.load({'foo/bar.md': {content: 'this is content.'}}, {foo: 'bar'}); | ||
// loader.load(key, value, locals); | ||
var post = loader.load('abc.md', 'My name is <%= name %>.', {name: 'Jon Schlinkert'}); | ||
``` | ||
### [.string](index.js#L106) | ||
* `key` **{String}**: Glob patterns or file paths. | ||
* `value` **{String|Object}**: String of content, `file` object with `content` property, or `locals` if the first arg is a file path. | ||
* `options` **{Object}**: Options or `locals`. | ||
* `returns` **{Object}**: Normalized file object. | ||
Expand glob patterns, load, read, parse and normalize files | ||
from file paths or strings. | ||
### [.array](index.js#L149) | ||
* `patterns` **{Object}**: Glob patterns or array of filepaths. | ||
* `options` **{Object}**: Options or `locals` | ||
* `returns` **{Array}**: Array of normalized file objects. | ||
Normalize an array of patterns. | ||
### [.object](index.js#L166) | ||
* `file` **{Object}**: The object to normalize. | ||
* `options` **{Object}**: Options or `locals` | ||
Normalize a template object. | ||
### [._cwd](index.js#L178) | ||
* `filepath` **{String}** | ||
The current working directory to use. Default is `process.cwd()`. | ||
### [.rename](index.js#L192) | ||
* `filepath` **{String}** | ||
Rename the `key` of each template loaded using whatever rename function | ||
is defined on the options. `path.basename` is the default. | ||
### [.parse](index.js#L209) | ||
* `filepath` **{String}**: The path of the file to read/parse. | ||
* `Options` **{Object}**: Options or `locals`. | ||
Parse the content of each template loaded using whatever parsing function | ||
is defined on the options. `fs.readFileSync` is used by default. | ||
### [.normalize](index.js#L238) | ||
* `file` **{Object}**: The template object to normalize. | ||
* `Options` **{Object}**: Options or `locals`. | ||
Normalize a template using whatever normalize function is | ||
defined on the options. | ||
## Author | ||
@@ -149,2 +44,2 @@ | ||
_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on September 04, 2014._ | ||
_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on September 28, 2014._ |
--- | ||
title: AAA | ||
--- | ||
This is fixture a.txt | ||
This is from a.txt. |
--- | ||
title: BBB | ||
--- | ||
This is fixture b.txt | ||
This is from b.txt. |
--- | ||
title: CCC | ||
--- | ||
This is fixture c.txt | ||
This is fixture c.md |
--- | ||
title: CCC | ||
--- | ||
This is fixture c.md | ||
This is from c.txt. |
984
test/test.js
@@ -10,127 +10,939 @@ /*! | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var chalk = require('chalk'); | ||
var matter = require('gray-matter'); | ||
var should = require('should'); | ||
var loader = require('..'); | ||
var fixture = function(filepath) { | ||
return path.join(__dirname, 'fixtures/' + filepath) | ||
.replace(/[\\\/]/g, '/'); | ||
}; | ||
var _loader = require('..'); | ||
var loader = _loader(); | ||
var utils = require('../lib/utils'); | ||
describe('loader', function () { | ||
it('should use cwd:', function () { | ||
loader({cwd: 'test/fixtures'}); | ||
loader.options.cwd.should.equal('test/fixtures'); | ||
describe('utils:', function () { | ||
describe('options:', function () { | ||
describe('.pickOptions():', function () { | ||
it('should pick an options object:', function () { | ||
var opts = utils.pickOptions({a: 'b', locals: {c: 'd'}, options: {foo: true}, content: 'This is content.'}); | ||
opts.should.eql({options: {foo: true}}); | ||
}); | ||
}); | ||
describe('.pickOptions():', function () { | ||
it('should return an empty object when nothing is found:', function () { | ||
utils.pickOptions({content: 'This is content.'}).should.eql({}); | ||
utils.pickOptions({}).should.eql({}); | ||
}); | ||
}); | ||
describe('.flattenOptions():', function () { | ||
it('should flatten an options object', function () { | ||
var opts = utils.flattenOptions({options: {foo: true}, bar: false}); | ||
opts.should.eql({foo: true, bar: false}); | ||
}); | ||
}); | ||
describe('.flattenOptions():', function () { | ||
it('should return an empty object when nothing is found:', function () { | ||
utils.flattenOptions({content: 'This is content.'}).should.eql({}); | ||
utils.flattenOptions({}).should.eql({}); | ||
}); | ||
}); | ||
describe('.omitOptions():', function () { | ||
it('should omit an options object', function () { | ||
var opts = utils.omitOptions({options: {foo: true}, bar: false}); | ||
opts.should.eql({bar: false}); | ||
}); | ||
}); | ||
}); | ||
describe('string', function () { | ||
it('should load templates from a string glob pattern', function () { | ||
var actual = loader.load('pages/*.txt'); | ||
var key = fixture('pages/a.txt'); | ||
describe('locals:', function () { | ||
describe('.pickLocals():', function () { | ||
it('should pick locals from the given object:', function () { | ||
var locals = utils.pickLocals({a: 'b', locals: {c: 'd'}, content: 'This is content.'}); | ||
locals.should.eql({a: 'b', locals: {c: 'd'}}); | ||
}); | ||
}); | ||
actual.should.be.an.object; | ||
actual.should.have.property(key); | ||
actual[key].should.have.property('path'); | ||
actual[key].should.have.property('data'); | ||
actual[key].should.have.property('content'); | ||
describe('.pickLocals():', function () { | ||
it('should return an empty object when nothing is found:', function () { | ||
utils.pickLocals({content: 'This is content.'}).should.eql({}); | ||
utils.pickLocals({}).should.eql({}); | ||
}); | ||
}); | ||
it('should normalize data passed as a second param', function () { | ||
var actual = loader.load('pages/*.txt', {name: 'Brian Woodward'}); | ||
var key = fixture('pages/a.txt'); | ||
describe('.flattenLocals():', function () { | ||
it('should flatten a locals object', function () { | ||
var locals = utils.flattenLocals({a: 'b', locals: {c: 'd'}, content: 'This is content.'}); | ||
locals.should.eql({a: 'b', c: 'd'}); | ||
}); | ||
}); | ||
actual.should.be.an.object; | ||
actual.should.have.property(key); | ||
actual[key].should.have.property('data'); | ||
actual[key].data.name.should.equal('Brian Woodward'); | ||
describe('.flattenLocals():', function () { | ||
it('should return an empty object when nothing is found:', function () { | ||
utils.flattenLocals({content: 'This is content.'}).should.eql({}); | ||
utils.flattenLocals({}).should.eql({}); | ||
}); | ||
}); | ||
it('should create a path property from the filepath.', function () { | ||
var actual = loader.load('pages/*.txt', {name: 'Brian Woodward'}); | ||
var key = fixture('pages/a.txt'); | ||
describe('.omitLocals():', function () { | ||
it('should omit locals', function () { | ||
var locals = utils.omitLocals({a: 'b', locals: {c: 'd'}, content: 'This is content.'}); | ||
locals.should.eql({a: 'b', content: 'This is content.'}); | ||
}); | ||
}); | ||
actual.should.be.an.object; | ||
actual.should.have.property(key); | ||
actual[key].should.have.property('path'); | ||
actual[key].path.should.equal(key); | ||
describe('.omitLocals():', function () { | ||
it('should return an empty object when nothing is found:', function () { | ||
utils.omitLocals({}).should.eql({}); | ||
}); | ||
}); | ||
}); | ||
it('should normalize content passed as a second param', function () { | ||
var actual = loader.load('abc.md', 'This is content.', {name: 'Jon Schlinkert'}); | ||
var key = 'abc.md'; | ||
describe('root:', function () { | ||
describe('.pickRoot():', function () { | ||
it('should pick root properties from the given object:', function () { | ||
var root = utils.pickRoot({a: 'b', locals: {c: 'd'}, content: 'This is content.'}); | ||
root.should.eql({content: 'This is content.', locals: {c: 'd'}}); | ||
}); | ||
}); | ||
actual.should.be.an.object; | ||
actual.should.have.property(key); | ||
actual[key].should.have.property('data'); | ||
actual[key].content.should.equal('This is content.'); | ||
actual[key].data.name.should.equal('Jon Schlinkert'); | ||
describe('.omitRoot():', function () { | ||
it('should omit root properties', function () { | ||
var root = utils.omitRoot({a: 'b', locals: {c: 'd'}, content: 'This is content.'}); | ||
root.should.eql({a: 'b'}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it('should normalize data passed as a second param', function () { | ||
var actual = loader.load(['pages/*.txt'], {name: 'Brian Woodward'}); | ||
var key = fixture('pages/a.txt'); | ||
actual.should.be.an.object; | ||
actual.should.have.property(key); | ||
actual[key].should.have.property('data'); | ||
actual[key].data.name.should.equal('Brian Woodward'); | ||
describe('loader.normalize()', function () { | ||
it('should use a custom normalization function to rename the key.', function () { | ||
loader = _loader({ | ||
normalize: function(acc, value, key) { | ||
key = path.basename(key); | ||
acc[key] = value; | ||
return acc; | ||
} | ||
}); | ||
var actual = loader('test/fixtures/a.txt', {a: 'b'}, {foo: true}); | ||
actual.should.have.property('a.txt'); | ||
actual['a.txt'].should.have.property('data', { title: 'AAA' }); | ||
// restore state | ||
loader = _loader(); | ||
}); | ||
describe('array', function () { | ||
it('should load templates from an array glob pattern', function () { | ||
var actual = loader.load(['pages/*.txt']); | ||
var key = fixture('pages/a.txt'); | ||
it('should use a custom normalization function to add a `name` property.', function () { | ||
loader = _loader({ | ||
normalize: function(acc, value, key) { | ||
key = path.basename(key); | ||
value.name = key; | ||
acc[key] = value; | ||
return acc; | ||
} | ||
}); | ||
actual.should.be.an.object; | ||
actual.should.have.property(key); | ||
actual[key].should.have.property('path'); | ||
actual[key].should.have.property('data'); | ||
actual[key].should.have.property('content'); | ||
var actual = loader('test/fixtures/a.txt', {a: 'b'}, {foo: true}); | ||
actual.should.have.property('a.txt'); | ||
actual['a.txt'].should.have.property('name', 'a.txt'); | ||
// restore state | ||
loader = _loader(); | ||
}); | ||
}); | ||
describe(chalk.magenta('[ function | object ]') + ' pattern:', function () { | ||
describe(chalk.bold('valid filepath:'), function () { | ||
it('should detect when the string is a filepath:', function () { | ||
var files = loader(function(options) { | ||
var file = matter.read('test/fixtures/a.md'); | ||
var o = {}; | ||
o[file.path] = file; | ||
return o; | ||
}); | ||
files['test/fixtures/a.md'].should.have.property('path', 'test/fixtures/a.md'); | ||
}); | ||
}); | ||
}); | ||
it('should normalize data passed as a second param', function () { | ||
var actual = loader.load(['pages/*.txt'], {name: 'Brian Woodward'}); | ||
var key = fixture('pages/a.txt'); | ||
actual.should.be.an.object; | ||
actual.should.have.property(key); | ||
actual[key].should.have.property('data'); | ||
actual[key].data.name.should.equal('Brian Woodward'); | ||
describe(chalk.magenta('[ string | object ]') + ' pattern:', function () { | ||
describe(chalk.bold('valid filepath:'), function () { | ||
it('should detect when the string is a filepath:', function () { | ||
var files = loader('test/fixtures/one/a.md'); | ||
files['test/fixtures/one/a.md'].should.have.property('path', 'test/fixtures/one/a.md'); | ||
}); | ||
it('should create a path property from the filepath.', function () { | ||
var actual = loader.load(['pages/*.txt'], {name: 'Brian Woodward'}); | ||
var key = fixture('pages/a.txt'); | ||
it('should read the file and return an object:', function () { | ||
var files = loader('test/fixtures/a.md'); | ||
files['test/fixtures/a.md'].should.be.an.object; | ||
}); | ||
actual.should.be.an.object; | ||
actual.should.have.property(key); | ||
actual[key].should.have.property('path'); | ||
actual[key].path.should.equal(key); | ||
it('should extend the object with `content` from the file:', function () { | ||
var files = loader('test/fixtures/one/a.md'); | ||
files['test/fixtures/one/a.md'].should.have.property('content', 'This is {{title}}'); | ||
}); | ||
it('should extend the object with the `path` for the file:', function () { | ||
var files = loader('test/fixtures/a.md'); | ||
files['test/fixtures/a.md'].should.have.property('path', 'test/fixtures/a.md'); | ||
}); | ||
it('should extend the object with `content`:', function () { | ||
var files = loader('test/fixtures/a.md'); | ||
files['test/fixtures/a.md'].should.have.property('content', 'This is fixture a.md'); | ||
}); | ||
it('should extend the object with `locals`:', function () { | ||
var files = loader('test/fixtures/a.md', {a: 'b'}); | ||
files['test/fixtures/a.md'].should.have.property('locals', {a: 'b'}); | ||
}); | ||
it('should extend the object with `options`:', function () { | ||
var files = loader('test/fixtures/a.md', {a: 'b'}, {something: true}); | ||
files['test/fixtures/a.md'].should.have.property('locals', {a: 'b'}); | ||
files['test/fixtures/a.md'].should.have.property('options', {something: true}); | ||
}); | ||
it('should parse front matter:', function () { | ||
var files = loader('test/fixtures/a.md'); | ||
files['test/fixtures/a.md'].should.have.property('data', { title: 'AAA' }); | ||
}); | ||
it('should create `orig` from parsed file string:', function () { | ||
var files = loader('test/fixtures/a.md'); | ||
files['test/fixtures/a.md'].should.have.property('orig', '---\ntitle: AAA\n---\nThis is fixture a.md'); | ||
}); | ||
it('should keep `locals` and `data` from front matter separate:', function () { | ||
var files = loader('test/fixtures/a.md', {a: 'b'}); | ||
files['test/fixtures/a.md'].should.have.property('locals', { a: 'b' }); | ||
files['test/fixtures/a.md'].should.have.property('data', { title: 'AAA' }); | ||
files['test/fixtures/a.md'].should.have.property('orig', '---\ntitle: AAA\n---\nThis is fixture a.md'); | ||
}); | ||
it('should get locals from the second argument:', function () { | ||
var files = loader('test/fixtures/one/a.md', {name: 'Brian Woodward'}); | ||
files['test/fixtures/one/a.md'].should.have.property('locals', {name: 'Brian Woodward'}); | ||
}); | ||
}); | ||
describe('object', function () { | ||
it('should load templates from an object', function () { | ||
var actual = loader.load({'foo/bar.md': {content: 'this is content.'}}); | ||
var key = 'foo/bar.md'; | ||
describe(chalk.bold('valid glob pattern:'), function () { | ||
it('should expand glob patterns:', function () { | ||
var files = loader('test/fixtures/*.txt'); | ||
files.should.be.an.object; | ||
files['test/fixtures/a.txt'].should.exist; | ||
}); | ||
actual.should.be.an.object; | ||
actual.should.have.property(key); | ||
actual[key].should.have.property('path'); | ||
actual[key].should.have.property('data'); | ||
actual[key].should.have.property('content'); | ||
it('should read files and return an object for each:', function () { | ||
var files = loader('test/fixtures/*.txt'); | ||
files.should.be.an.object; | ||
files['test/fixtures/a.txt'].should.exist; | ||
files['test/fixtures/b.txt'].should.exist; | ||
files['test/fixtures/c.txt'].should.exist; | ||
}); | ||
it('should normalize data passed as a second param', function () { | ||
var actual = loader.load({'foo/bar.md': {content: 'this is content.'}}, {foo: 'bar'}); | ||
var key = 'foo/bar.md'; | ||
it('should extend the objects with locals:', function () { | ||
var files = loader('test/fixtures/*.txt', {name: 'Brian Woodward'}); | ||
files['test/fixtures/a.txt'].should.have.property('locals', {name: 'Brian Woodward'}); | ||
files['test/fixtures/b.txt'].should.have.property('locals', {name: 'Brian Woodward'}); | ||
files['test/fixtures/c.txt'].should.have.property('locals', {name: 'Brian Woodward'}); | ||
}); | ||
actual.should.be.an.object; | ||
actual.should.have.property(key); | ||
actual[key].should.have.property('data'); | ||
actual[key].data.should.eql({foo: 'bar'}); | ||
it('should extend the objects with a `path` property.', function () { | ||
var files = loader('test/fixtures/*.txt'); | ||
files['test/fixtures/a.txt'].should.have.property('path', 'test/fixtures/a.txt'); | ||
files['test/fixtures/b.txt'].should.have.property('path', 'test/fixtures/b.txt'); | ||
files['test/fixtures/c.txt'].should.have.property('path', 'test/fixtures/c.txt'); | ||
}); | ||
it('should extend the objects with `content` from the file:', function () { | ||
var files = loader('test/fixtures/*.txt'); | ||
files['test/fixtures/a.txt'].should.have.property('content', 'This is from a.txt.'); | ||
files['test/fixtures/b.txt'].should.have.property('content', 'This is from b.txt.'); | ||
files['test/fixtures/c.txt'].should.have.property('content', 'This is from c.txt.'); | ||
}); | ||
it('should extend the objects with `options`:', function () { | ||
var files = loader('test/fixtures/*.txt', {a: 'b'}, {c: true}); | ||
files['test/fixtures/a.txt'].should.have.property('options', {c: true}); | ||
files['test/fixtures/b.txt'].should.have.property('options', {c: true}); | ||
files['test/fixtures/c.txt'].should.have.property('options', {c: true}); | ||
}); | ||
it('should detect options passed on the locals object:', function () { | ||
var files = loader('test/fixtures/*.txt', {a: 'b', options: {b: 'b'}}, {c: true}); | ||
files['test/fixtures/a.txt'].should.have.property('options', {b: 'b', c: true}); | ||
files['test/fixtures/b.txt'].should.have.property('options', {b: 'b', c: true}); | ||
files['test/fixtures/c.txt'].should.have.property('options', {b: 'b', c: true}); | ||
// ensure that locals is correct | ||
files['test/fixtures/a.txt'].should.have.property('locals', {a: 'b'}); | ||
files['test/fixtures/b.txt'].should.have.property('locals', {a: 'b'}); | ||
files['test/fixtures/c.txt'].should.have.property('locals', {a: 'b'}); | ||
}); | ||
it('should parse front matter:', function () { | ||
var files = loader('test/fixtures/*.txt'); | ||
files['test/fixtures/a.txt'].should.have.property('data', { title: 'AAA' }); | ||
files['test/fixtures/b.txt'].should.have.property('data', { title: 'BBB' }); | ||
files['test/fixtures/c.txt'].should.have.property('data', { title: 'CCC' }); | ||
}); | ||
it('should create `orig` from parsed file string:', function () { | ||
var files = loader('test/fixtures/*.txt'); | ||
files['test/fixtures/a.txt'].should.have.property('orig', '---\ntitle: AAA\n---\nThis is from a.txt.'); | ||
files['test/fixtures/b.txt'].should.have.property('orig', '---\ntitle: BBB\n---\nThis is from b.txt.'); | ||
files['test/fixtures/c.txt'].should.have.property('orig', '---\ntitle: CCC\n---\nThis is from c.txt.'); | ||
}); | ||
it('should keep `locals` and `data` from front matter separate:', function () { | ||
var files = loader('test/fixtures/*.txt', {a: 'b'}); | ||
files['test/fixtures/a.txt'].should.have.property('locals', { a: 'b' }); | ||
files['test/fixtures/a.txt'].should.have.property('data', { title: 'AAA' }); | ||
}); | ||
it('should move arbitrary props on the third arg to `options`:', function () { | ||
var files = loader('test/fixtures/*.md', {a: 'b'}, {engine: 'hbs'}); | ||
files['test/fixtures/a.md'].should.have.property('locals', {a: 'b'}); | ||
files['test/fixtures/a.md'].should.have.property('options', {engine: 'hbs'}); | ||
}); | ||
it('should NOT ATTEMPT to resolve glob patterns when second value is a string:', function () { | ||
var files = loader('test/fixtures/*.md', 'flflflfl', {name: 'Brian Woodward'}); | ||
files['test/fixtures/*.md'].should.have.property('path', 'test/fixtures/*.md'); | ||
files['test/fixtures/*.md'].should.have.property('content', 'flflflfl'); | ||
}); | ||
}); | ||
describe(chalk.bold('non-filepath, non-glob pattern:'), function () { | ||
it('should move arbitrary props on the second arg to `locals`:', function () { | ||
var files = loader('a', {content: 'this is content', layout: 'b'}); | ||
files['a'].should.have.property('locals', {layout: 'b'}); | ||
}); | ||
it('should load individual templates:', function () { | ||
var files = loader('foo1.md', 'This is content', {name: 'Jon Schlinkert'}); | ||
files['foo1.md'].should.have.property('content'); | ||
}); | ||
describe('when a `content` prop and actual content cannot be found:', function () { | ||
it('should not add a content property:', function () { | ||
var files = loader({'bar1.md': {path: 'a/b/c.md', name: 'Jon Schlinkert'}}); | ||
files['bar1.md'].should.not.have.property('content'); | ||
}); | ||
it('should add other prorties found on the object:', function () { | ||
var files = loader({'baz.md': {path: 'a/b/c.md', name: 'Jon Schlinkert'}}, {go: true}); | ||
files['baz.md'].should.have.property('path'); | ||
}); | ||
}); | ||
it.skip('should detect locals when passed as a second param', function () { | ||
var files = loader('whatever', {name: 'Brian Woodward'}); | ||
files['whatever'].should.have.property('locals', {name: 'Brian Woodward'}); | ||
}); | ||
it.skip('should return `{content: null}` when content is not defined or detected.', function () { | ||
var files = loader('whatever', {name: 'Brian Woodward'}); | ||
files['whatever'].should.have.property('content', null); | ||
}); | ||
it('should load when content is a property on an object.', function () { | ||
var files = loader('a.md', {content: 'c'}); | ||
files['a.md'].should.have.property('content', 'c'); | ||
}); | ||
it.skip('should load even if the key is an invalid filepath.', function () { | ||
var files = loader('a.md'); | ||
files.should.have.property('__id__1'); | ||
}); | ||
it.skip('should load even if the key is an invalid filepath.', function () { | ||
var files = loader('a.md', 'b'); | ||
files['a.md'].should.have.property('content', 'b'); | ||
}); | ||
it('should detect content passed as a second arg', function () { | ||
var files = loader('foo/bar/abc.md', 'This is content.'); | ||
files['foo/bar/abc.md'].should.have.property('path'); | ||
files['foo/bar/abc.md'].content.should.equal('This is content.'); | ||
}); | ||
it('should detect locals passed as a third arg', function () { | ||
var files = loader('foo/bar/abc.md', 'This is content.', { a: 'b' }); | ||
files['foo/bar/abc.md'].should.have.property('locals', { a: 'b' }); | ||
}); | ||
it('should detect options passed as a fourth arg', function () { | ||
var files = loader('foo/bar/abc.md', 'This is content.', { a: 'b' }, { c: 'd' }); | ||
files['foo/bar/abc.md'].should.have.property('locals', { a: 'b' }, { c: 'd' }); | ||
}); | ||
describe('when the second arg is an object:', function () { | ||
it('should use the first arg as the key.', function () { | ||
var files = loader('a', {content: 'A above\n{{body}}\nA below', layout: 'b'}); | ||
files['a'].should.have.property('content', 'A above\n{{body}}\nA below'); | ||
files['a'].should.have.property('locals', {layout: 'b'}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe(chalk.magenta('[ string | string ]') + ' pattern:', function () { | ||
it('should assume the second arg is `content`.', function () { | ||
var files = loader('abc.md', 'This is content.'); | ||
files['abc.md'].should.have.property('content', 'This is content.'); | ||
}); | ||
it('should assume the first arg is the template key.', function () { | ||
var files = loader('abc.md', 'This is content.'); | ||
files['abc.md'].should.have.property('path', 'abc.md'); | ||
}); | ||
it('should assume the key is not a file path.', function () { | ||
var files = loader('abc.md', 'This is content.'); | ||
files['abc.md'].should.have.property('path', 'abc.md'); | ||
}); | ||
it('should extend the object with `locals`', function () { | ||
var files = loader('abc.md', 'This is content.', {a: 'b'}, {locals: {c: 'd'}}); | ||
files['abc.md'].should.have.property('locals', {a: 'b'}); | ||
}); | ||
it('should extend the object with `options`', function () { | ||
var files = loader('abc.md', 'This is content.', {a: 'b'}, {c: 'd'}); | ||
files['abc.md'].should.have.property('locals', {a: 'b'}); | ||
files['abc.md'].should.have.property('options', {c: 'd'}); | ||
}); | ||
}); | ||
describe(chalk.magenta('[ object ]') + ' pattern:', function () { | ||
describe('when templates are formatted as objects', function () { | ||
it('should load multiple templates from objects:', function () { | ||
var files = loader({a: {layout: 'b', content: 'A above\n{{body}}\nA below' }}); | ||
files.should.have.property('a'); | ||
files.a.locals.should.have.property('layout'); | ||
}); | ||
it('should load multiple templates from objects:', function () { | ||
var files = loader({b: {layout: 'c', content: 'B above\n{{body}}\nB below' }}); | ||
files.should.have.property('b'); | ||
files.b.locals.should.have.property('layout'); | ||
}); | ||
it('should load multiple templates from objects:', function () { | ||
var files = loader({c: {layout: 'd', content: 'C above\n{{body}}\nC below' }}); | ||
files.should.have.property('c'); | ||
files.c.locals.should.have.property('layout'); | ||
}); | ||
}); | ||
it('should load loader from an object', function () { | ||
var files = loader({'foo/bar.md': {content: 'this is content.'}}); | ||
files['foo/bar.md'].should.have.property('path', 'foo/bar.md'); | ||
files['foo/bar.md'].should.not.have.property('locals'); | ||
files['foo/bar.md'].should.have.property('content', 'this is content.'); | ||
}); | ||
it('should normalize locals passed as a second param', function () { | ||
var files = loader({'foo/bar.md': {content: 'this is content.'}}, {foo: 'bar'}); | ||
files['foo/bar.md'].should.have.property('path', 'foo/bar.md'); | ||
files['foo/bar.md'].should.have.property('locals', {foo: 'bar'}); | ||
files['foo/bar.md'].locals.should.eql({foo: 'bar'}); | ||
}); | ||
it('should use the key as the `path`:', function () { | ||
var files = loader({a: {content: 'A above\n{{body}}\nA below' , layout: 'b'}}); | ||
files['a'].should.have.property('path', 'a'); | ||
files['a'].should.have.property('locals'); | ||
files['a'].locals.should.have.property('layout', 'b'); | ||
}); | ||
}); | ||
describe(chalk.magenta('[ array ]') + ' pattern:', function () { | ||
describe(chalk.bold('valid glob pattern:'), function () { | ||
it('should expand an array of glob patterns:', function () { | ||
var files = loader(['test/fixtures/*.txt']); | ||
files.should.be.an.object; | ||
files['test/fixtures/a.txt'].should.exist; | ||
}); | ||
it('should read files and return an object for each:', function () { | ||
var files = loader(['test/fixtures/*.txt']); | ||
files.should.be.an.object; | ||
files['test/fixtures/a.txt'].should.exist; | ||
files['test/fixtures/b.txt'].should.exist; | ||
files['test/fixtures/c.txt'].should.exist; | ||
}); | ||
it('should create a `path` property from each filepath.', function () { | ||
var files = loader(['test/fixtures/*.txt']); | ||
files['test/fixtures/a.txt'].should.have.property('path', 'test/fixtures/a.txt'); | ||
files['test/fixtures/b.txt'].should.have.property('path', 'test/fixtures/b.txt'); | ||
files['test/fixtures/c.txt'].should.have.property('path', 'test/fixtures/c.txt'); | ||
}); | ||
it('should extend the objects with locals:', function () { | ||
var files = loader(['test/fixtures/*.txt'], {name: 'Brian Woodward'}); | ||
files['test/fixtures/a.txt'].should.have.property('locals', {name: 'Brian Woodward'}); | ||
files['test/fixtures/b.txt'].should.have.property('locals', {name: 'Brian Woodward'}); | ||
files['test/fixtures/c.txt'].should.have.property('locals', {name: 'Brian Woodward'}); | ||
}); | ||
it('should extend the objects with locals and options:', function () { | ||
var files = loader(['test/fixtures/*.md', 'test/fixtures/*.txt'], {a: 'b'}, { | ||
engine: 'hbs' | ||
}); | ||
files['test/fixtures/a.md'].should.have.property('locals', {a: 'b'}); | ||
files['test/fixtures/a.txt'].should.have.property('locals', {a: 'b'}); | ||
files['test/fixtures/a.md'].should.have.property('options', {engine: 'hbs'}); | ||
files['test/fixtures/a.txt'].should.have.property('options', {engine: 'hbs'}); | ||
}); | ||
it('should extend the objects with a `path` property.', function () { | ||
var files = loader(['test/fixtures/*.txt']); | ||
files['test/fixtures/a.txt'].should.have.property('path', 'test/fixtures/a.txt'); | ||
files['test/fixtures/b.txt'].should.have.property('path', 'test/fixtures/b.txt'); | ||
files['test/fixtures/c.txt'].should.have.property('path', 'test/fixtures/c.txt'); | ||
}); | ||
it('should extend the objects with `content` from the file:', function () { | ||
var files = loader(['test/fixtures/*.txt']); | ||
files['test/fixtures/a.txt'].should.have.property('content', 'This is from a.txt.'); | ||
files['test/fixtures/b.txt'].should.have.property('content', 'This is from b.txt.'); | ||
files['test/fixtures/c.txt'].should.have.property('content', 'This is from c.txt.'); | ||
}); | ||
it('should extend the objects with `options`:', function () { | ||
var files = loader(['test/fixtures/*.txt'], {a: 'b'}, {c: true}); | ||
files['test/fixtures/a.txt'].should.have.property('options', {c: true}); | ||
files['test/fixtures/b.txt'].should.have.property('options', {c: true}); | ||
files['test/fixtures/c.txt'].should.have.property('options', {c: true}); | ||
}); | ||
it('should detect options passed on the locals object:', function () { | ||
var files = loader(['test/fixtures/*.txt'], {a: 'b', options: {b: 'b'}}, {c: true}); | ||
files['test/fixtures/a.txt'].should.have.property('options', {b: 'b', c: true}); | ||
files['test/fixtures/b.txt'].should.have.property('options', {b: 'b', c: true}); | ||
files['test/fixtures/c.txt'].should.have.property('options', {b: 'b', c: true}); | ||
// ensure that locals is correct | ||
files['test/fixtures/a.txt'].should.have.property('locals', {a: 'b'}); | ||
files['test/fixtures/b.txt'].should.have.property('locals', {a: 'b'}); | ||
files['test/fixtures/c.txt'].should.have.property('locals', {a: 'b'}); | ||
}); | ||
it('should parse front matter:', function () { | ||
var files = loader(['test/fixtures/*.txt']); | ||
files['test/fixtures/a.txt'].should.have.property('data', { title: 'AAA' }); | ||
files['test/fixtures/b.txt'].should.have.property('data', { title: 'BBB' }); | ||
files['test/fixtures/c.txt'].should.have.property('data', { title: 'CCC' }); | ||
}); | ||
it('should create `orig` from parsed file string:', function () { | ||
var files = loader(['test/fixtures/*.txt']); | ||
files['test/fixtures/a.txt'].should.have.property('orig', '---\ntitle: AAA\n---\nThis is from a.txt.'); | ||
files['test/fixtures/b.txt'].should.have.property('orig', '---\ntitle: BBB\n---\nThis is from b.txt.'); | ||
files['test/fixtures/c.txt'].should.have.property('orig', '---\ntitle: CCC\n---\nThis is from c.txt.'); | ||
}); | ||
it('should keep `locals` and `data` from front matter separate:', function () { | ||
var files = loader(['test/fixtures/*.txt'], {a: 'b'}); | ||
files['test/fixtures/a.txt'].should.have.property('locals', { a: 'b' }); | ||
files['test/fixtures/a.txt'].should.have.property('data', { title: 'AAA' }); | ||
}); | ||
}); | ||
}); | ||
describe('normalize templates', function () { | ||
describe('path and content properties', function () { | ||
var expected = { 'a/b/c.md': { path: 'a/b/c.md', ext: '.md', content: 'this is content.'}}; | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader({path: 'a/b/c.md', content: 'this is content.'}); | ||
files.should.eql(expected); | ||
}); | ||
it('should use the key to fill in a missing `path` property', function () { | ||
var files = loader({ 'a/b/c.md': { content: 'this is content.'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', {content: 'this is content.'}); | ||
files.should.eql(expected); | ||
}); | ||
describe('when the first two args are strings:', function () { | ||
it('should create an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', 'this is content.'); | ||
files.should.eql(expected); | ||
}); | ||
}); | ||
}); | ||
describe('sparse fields:', function () { | ||
it('should normalize options', function () { | ||
var files = loader('a', {content: 'This is content.', options: {ext: '.foo'}}); | ||
files.should.eql({a: {path: 'a', content: 'This is content.', ext: '.foo', options: {ext: '.foo'}}}); | ||
}); | ||
it('should normalize locals', function () { | ||
var files = loader('a', {content: 'This is content.'}, {ext: '.foo'}); | ||
files.should.eql({a: {path: 'a', content: 'This is content.', ext: '.foo'}}); | ||
}); | ||
}); | ||
describe('multiple templates:', function () { | ||
describe('objects:', function () { | ||
it('should use `path` and/or `content` properties as indicators:', function () { | ||
var expected = { | ||
'a/b/a.md': {path: 'a/b/a.md', ext: '.md', content: 'this is content.'}, | ||
'a/b/b.md': {path: 'a/b/b.md', ext: '.md', content: 'this is content.'}, | ||
'a/b/c.md': {path: 'a/b/c.md', ext: '.md', content: 'this is content.'} | ||
}; | ||
var files = loader({ | ||
'a/b/a.md': {content: 'this is content.'}, | ||
'a/b/b.md': {content: 'this is content.'}, | ||
'a/b/c.md': {content: 'this is content.'} | ||
}); | ||
files.should.eql(expected); | ||
}); | ||
it('should normalize locals:', function () { | ||
var expected = { | ||
'a/b/a.md': {path: 'a/b/a.md', ext: '.md', content: 'this is content.', locals: {a: {b: 'c'}}}, | ||
'a/b/b.md': {path: 'a/b/b.md', ext: '.md', content: 'this is content.', locals: {a: {c: 'd'}}}, | ||
'a/b/c.md': {path: 'a/b/c.md', ext: '.md', content: 'this is content.'} | ||
}; | ||
var files = loader({ | ||
'a/b/a.md': {content: 'this is content.', a: {b: 'c'}}, | ||
'a/b/b.md': {content: 'this is content.', locals: {a: {c: 'd'}}}, | ||
'a/b/c.md': {content: 'this is content.'} | ||
}); | ||
files.should.eql(expected); | ||
}); | ||
it('should normalize "method-locals":', function () { | ||
var expected = { | ||
'a/b/a.md': {path: 'a/b/a.md', ext: '.md', content: 'this is content.', locals: {a: {b: 'c'}, foo: 'bar'}}, | ||
'a/b/b.md': {path: 'a/b/b.md', ext: '.md', content: 'this is content.', locals: {a: {c: 'd'}, foo: 'bar'}}, | ||
'a/b/c.md': {path: 'a/b/c.md', ext: '.md', content: 'this is content.', locals: {foo: 'bar'}} | ||
}; | ||
var files = loader({ | ||
'a/b/a.md': {content: 'this is content.', a: {b: 'c'}}, | ||
'a/b/b.md': {content: 'this is content.', locals: {a: {c: 'd'}}}, | ||
'a/b/c.md': {content: 'this is content.'} | ||
}, {foo: 'bar'}); | ||
files.should.eql(expected); | ||
}); | ||
it('should normalize "method" locals:', function () { | ||
var expected = { | ||
'a/b/a.md': {path: 'a/b/a.md', ext: '.md', content: 'this is content.', locals: {a: {b: 'c'}, bar: 'bar'}}, | ||
'a/b/b.md': {path: 'a/b/b.md', ext: '.md', content: 'this is content.', locals: {a: {c: 'd'}, bar: 'bar'}}, | ||
'a/b/c.md': {path: 'a/b/c.md', ext: '.md', content: 'this is content.', locals: {bar: 'baz'}} | ||
}; | ||
var files = loader({ | ||
'a/b/a.md': {content: 'this is content.', a: {b: 'c'}, bar: 'bar'}, | ||
'a/b/b.md': {content: 'this is content.', locals: {a: {c: 'd'}, bar: 'bar'}}, | ||
'a/b/c.md': {content: 'this is content.'} | ||
}, {bar: 'baz'}); | ||
files.should.eql(expected); | ||
}); | ||
it('should normalize options:', function () { | ||
var expected = { | ||
'a/b/a.md': {path: 'a/b/a.md', ext: '.md', content: 'this is content.', locals: {a: {b: 'c'}, bar: 'baz'}, options: {foo: true}}, | ||
'a/b/b.md': {path: 'a/b/b.md', ext: '.md', content: 'this is content.', locals: {a: {c: 'd'}, bar: 'baz'}, options: {foo: true}}, | ||
'a/b/c.md': {path: 'a/b/c.md', ext: '.md', content: 'this is content.', locals: {bar: 'baz'}, options: {foo: true}} | ||
}; | ||
var files = loader({ | ||
'a/b/a.md': {content: 'this is content.', a: {b: 'c'}}, | ||
'a/b/b.md': {content: 'this is content.', locals: {a: {c: 'd'}}}, | ||
'a/b/c.md': {content: 'this is content.'} | ||
}, {bar: 'baz'}, {foo: true}); | ||
files.should.eql(expected); | ||
}); | ||
}); | ||
}); | ||
describe('locals', function () { | ||
var expected = { 'a/b/c.md': { path: 'a/b/c.md', ext: '.md', content: 'this is content.', locals: {a: 'b'}}}; | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader({path: 'a/b/c.md', content: 'this is content.', locals: {a: 'b'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader({path: 'a/b/c.md', content: 'this is content.', a: 'b'}); | ||
files.should.eql(expected); | ||
}); | ||
it('should use the key to fill in a missing `path` property', function () { | ||
var files = loader({ 'a/b/c.md': { content: 'this is content.', locals: {a: 'b'}}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should use the key to fill in a missing `path` property', function () { | ||
var files = loader({ 'a/b/c.md': { content: 'this is content.', a: 'b'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', {content: 'this is content.', locals: {a: 'b'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', {content: 'this is content.', a: 'b'}); | ||
files.should.eql(expected); | ||
}); | ||
describe('when the first two args are strings:', function () { | ||
it('should create an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', 'this is content.', {a: 'b'}); | ||
files.should.eql(expected); | ||
}); | ||
it('should create an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', 'this is content.', {locals: {a: 'b'}}); | ||
files.should.eql(expected); | ||
}); | ||
}); | ||
}); | ||
describe('options', function () { | ||
var expected = { 'a/b/c.md': { path: 'a/b/c.md', ext: '.md', content: 'this is content.', locals: {a: 'b'}, options: {y: 'z'}}}; | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader({path: 'a/b/c.md', content: 'this is content.', locals: {a: 'b'}, options: {y: 'z'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader({path: 'a/b/c.md', content: 'this is content.', a: 'b', options: {y: 'z'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should use the key to fill in a missing `path` property', function () { | ||
var files = loader({ 'a/b/c.md': { content: 'this is content.', locals: {a: 'b'}, options: {y: 'z'}}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should use the key to fill in a missing `path` property', function () { | ||
var files = loader({ 'a/b/c.md': { content: 'this is content.', a: 'b', options: {y: 'z'}}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', {content: 'this is content.', locals: {a: 'b'}, options: {y: 'z'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', {content: 'this is content.', a: 'b'}, {y: 'z'}); | ||
files.should.eql(expected); | ||
}); | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', {content: 'this is content.', a: 'b'}, {options: {y: 'z'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', {content: 'this is content.', a: 'b'}, {options: {y: 'z'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should detect the key from an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', {content: 'this is content.', a: 'b', options: {y: 'z'}}); | ||
files.should.eql(expected); | ||
}); | ||
describe('when the first two args are strings:', function () { | ||
it('should create an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', 'this is content.', {a: 'b'}, {options: {y: 'z'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should create an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', 'this is content.', {a: 'b', options: {y: 'z'}}); | ||
files.should.eql(expected); | ||
}); | ||
it('should create an object with `path` and `content` properties', function () { | ||
var files = loader('a/b/c.md', 'this is content.', {locals: {a: 'b'}, options: {y: 'z'}}); | ||
files.should.eql(expected); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('glob patterns', function () { | ||
describe('arrays', function () { | ||
var expected = { | ||
'test/fixtures/a.txt': { | ||
data: { title: 'AAA' }, | ||
content: 'This is from a.txt.', | ||
orig: '---\ntitle: AAA\n---\nThis is from a.txt.', | ||
path: 'test/fixtures/a.txt', | ||
ext: '.txt', | ||
locals: {a: 'b'}, | ||
options: {foo: true} | ||
}, | ||
'test/fixtures/b.txt': { | ||
data: { title: 'BBB' }, | ||
content: 'This is from b.txt.', | ||
orig: '---\ntitle: BBB\n---\nThis is from b.txt.', | ||
path: 'test/fixtures/b.txt', | ||
ext: '.txt', | ||
locals: {a: 'b'}, | ||
options: {foo: true} | ||
}, | ||
'test/fixtures/c.txt': { | ||
data: { title: 'CCC' }, | ||
content: 'This is from c.txt.', | ||
orig: '---\ntitle: CCC\n---\nThis is from c.txt.', | ||
path: 'test/fixtures/c.txt', | ||
ext: '.txt', | ||
locals: {a: 'b'}, | ||
options: {foo: true} | ||
} | ||
}; | ||
it('should read a glob of files and return an object of templates.', function () { | ||
loader(['test/fixtures/*.txt'], {a: 'b'}, {foo: true}).should.eql(expected); | ||
}); | ||
it('should read a glob of files and return an object of templates.', function () { | ||
loader(['test/fixtures/*.txt'], {a: 'b', options: {foo: true}}).should.eql(expected); | ||
}); | ||
}); | ||
describe('strings', function () { | ||
var expected = { | ||
'test/fixtures/a.txt': { | ||
data: { title: 'AAA' }, | ||
content: 'This is from a.txt.', | ||
orig: '---\ntitle: AAA\n---\nThis is from a.txt.', | ||
path: 'test/fixtures/a.txt', | ||
ext: '.txt', | ||
locals: {a: 'b'}, | ||
options: {foo: true} | ||
}, | ||
'test/fixtures/b.txt': { | ||
data: { title: 'BBB' }, | ||
content: 'This is from b.txt.', | ||
orig: '---\ntitle: BBB\n---\nThis is from b.txt.', | ||
path: 'test/fixtures/b.txt', | ||
ext: '.txt', | ||
locals: {a: 'b'}, | ||
options: {foo: true} | ||
}, | ||
'test/fixtures/c.txt': { | ||
data: { title: 'CCC' }, | ||
content: 'This is from c.txt.', | ||
orig: '---\ntitle: CCC\n---\nThis is from c.txt.', | ||
path: 'test/fixtures/c.txt', | ||
ext: '.txt', | ||
locals: {a: 'b'}, | ||
options: {foo: true} | ||
} | ||
}; | ||
it('should read a glob of files and return an object of templates.', function () { | ||
var actual = loader('test/fixtures/*.txt', {a: 'b'}, {foo: true}); | ||
actual.should.eql(expected); | ||
}); | ||
}); | ||
}); | ||
describe('random', function () { | ||
it('should normalize a template with a non-filepath key.', function () { | ||
var files = loader('foo', {content: 'this is content.'}); | ||
files.should.eql({'foo': {path: 'foo', content: 'this is content.'}}); | ||
}); | ||
it('should normalize a template with a non-filepath key.', function () { | ||
var files = loader('foo', {content: 'this is content.', a: 'b'}, {fez: 'foo'}); | ||
files.should.eql({'foo': {path: 'foo', content: 'this is content.', locals: {a: 'b'}, options: {fez: 'foo'}}}); | ||
}); | ||
it('should normalize a template with a non-filepath key.', function () { | ||
var files = loader({'foo': {content: 'this is content.', a: 'b'}}, {fez: 'foo'}); | ||
files.should.eql({'foo': {path: 'foo', content: 'this is content.', locals: {a: 'b', fez: 'foo'}}}); | ||
}); | ||
it('random stuff', function () { | ||
var files = loader({path: 'a/b/c.md', content: 'this is content.', a: 'b', options: {y: 'z'}}, {c: 'd'}, {e: 'f'}); | ||
files.should.eql({'a/b/c.md': {path: 'a/b/c.md', ext: '.md', content: 'this is content.', locals: {a: 'b', c: 'd'}, options: {y: 'z', e: 'f'}}}); | ||
}); | ||
it('random stuff', function () { | ||
var files = loader({path: 'a/b/c.md', content: 'this is foo'}, {foo: 'bar'}); | ||
files.should.eql({'a/b/c.md': {path: 'a/b/c.md', ext: '.md', content: 'this is foo', locals: {foo: 'bar'}}}); | ||
}); | ||
it('random stuff', function () { | ||
var files = loader('a/b/c.md', {content: 'this is baz', a: 'b', options: {foo: 'bar'}}, {bar: 'baz'}); | ||
files.should.eql({'a/b/c.md': {path: 'a/b/c.md', ext: '.md', content: 'this is baz', locals: {a: 'b'}, options: {bar: 'baz', foo: 'bar'}}}); | ||
}); | ||
it('random stuff', function () { | ||
var files = loader('a/b/c.md', {content: 'this is baz', a: 'b', options: {foo: 'bar'}}, {bar: 'baz'}); | ||
files.should.eql({'a/b/c.md': {path: 'a/b/c.md', ext: '.md', content: 'this is baz', locals: {a: 'b'}, options: {bar: 'baz', foo: 'bar'}}}); | ||
}); | ||
it('multiple templates:', function () { | ||
var files = loader({ | ||
'a/b/a.md': {content: 'this is content'}, | ||
'a/b/b.md': {content: 'this is content'}, | ||
'a/b/c.md': {content: 'this is content'} | ||
}, {a: 'b'}, {c: true}); | ||
files['a/b/a.md'].should.have.property('path', 'a/b/a.md'); | ||
files['a/b/b.md'].should.have.property('path', 'a/b/b.md'); | ||
files['a/b/c.md'].should.have.property('path', 'a/b/c.md'); | ||
files['a/b/a.md'].should.have.property('content', 'this is content'); | ||
files['a/b/b.md'].should.have.property('content', 'this is content'); | ||
files['a/b/c.md'].should.have.property('content', 'this is content'); | ||
files['a/b/a.md'].should.have.property('locals', { a: 'b' }); | ||
files['a/b/b.md'].should.have.property('locals', { a: 'b' }); | ||
files['a/b/c.md'].should.have.property('locals', { a: 'b' }); | ||
files['a/b/a.md'].should.have.property('options', { c: true } ); | ||
files['a/b/b.md'].should.have.property('options', { c: true } ); | ||
files['a/b/c.md'].should.have.property('options', { c: true } ); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
81856
45
1648
15
6
42
2
1
+ Addedarray-slice@^0.2.0
+ Addeddebug@^2.0.0
+ Addedgray-matter@^0.5.0
+ Addedhas-any@^0.1.0
+ Addedhas-any-deep@^0.2.0
+ Addedis-plain-object@^0.1.0
+ Addedkind-of@^0.1.0
+ Addedmap-files@^0.1.2
+ Addedmixin-deep@^0.1.0
+ Addedobject-pick@^0.1.0
+ Addedomit-empty@^0.2.0
+ Addedomit-keys@^0.1.0
+ Addedreduce-object@^0.1.2
+ Addeduniqueid@^0.1.0
+ Addedansi-styles@1.0.0(transitive)
+ Addedargparse@1.0.10(transitive)
+ Addedarray-difference@0.0.1(transitive)
+ Addedarray-slice@0.2.3(transitive)
+ Addedchalk@0.4.0(transitive)
+ Addedcoffee-script@1.12.7(transitive)
+ Addeddebug@2.6.9(transitive)
+ Addeddelims@0.4.2(transitive)
+ Addedesprima@4.0.1(transitive)
+ Addedfor-in@1.0.2(transitive)
+ Addedfor-own@0.1.5(transitive)
+ Addedgray-matter@0.5.3(transitive)
+ Addedhas-any@0.1.2(transitive)
+ Addedhas-any-deep@0.2.0(transitive)
+ Addedhas-color@0.1.7(transitive)
+ Addedhas-value@0.1.0(transitive)
+ Addedis-plain-object@0.1.0(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedisobject@0.2.02.1.0(transitive)
+ Addedjs-yaml@3.14.1(transitive)
+ Addedkind-of@0.1.2(transitive)
+ Addedmap-files@0.1.2(transitive)
+ Addedmixin-deep@0.1.0(transitive)
+ Addedms@2.0.0(transitive)
+ Addedobject-pick@0.1.2(transitive)
+ Addedomit-empty@0.2.0(transitive)
+ Addedomit-keys@0.1.0(transitive)
+ Addedreduce-object@0.1.3(transitive)
+ Addedsprintf-js@1.0.3(transitive)
+ Addedstrip-ansi@0.1.1(transitive)
+ Addedtoml@2.3.6(transitive)
+ Addeduniqueid@0.1.0(transitive)
+ Addedverbalize@0.1.2(transitive)
- Removedarrayify-compact@^0.1.0
- Removedglobby@^0.1.1
- Removedis-relative@^0.1.1
- Removedis-relative@0.1.3(transitive)