dynamic-content
Version:
dynamic content functionality for roots
241 lines (206 loc) • 6.73 kB
JavaScript
// Generated by CoffeeScript 1.9.1
(function() {
var W, _, filter, fs, helpers, os, path, reformat, write_json, yaml;
path = require('path');
fs = require('fs');
os = require('os');
_ = require('lodash');
yaml = require('js-yaml');
W = require('when');
helpers = require('./helpers');
module.exports = function(opts) {
var DynamicContent;
if (opts == null) {
opts = {};
}
return DynamicContent = (function() {
var after_category, after_hook, all_fn, before_hook, write_hook;
function DynamicContent() {
this.category = 'dynamic';
this.all_content = [];
}
DynamicContent.prototype.fs = function() {
return {
extract: true,
ordered: true,
detect: function(f) {
return helpers.detect_file(f.path);
}
};
};
DynamicContent.prototype.compile_hooks = function() {
return {
before_pass: before_hook.bind(this),
after_file: after_hook.bind(this),
write: write_hook.bind(this)
};
};
DynamicContent.prototype.category_hooks = function() {
return {
after: after_category.bind(this)
};
};
/**
* For dynamic files before the last compile pass:
* - remove the front matter, parse into an object
* - add the object to the locals, nesting as deep as the folder it's in
* - add an "all" utility function to each level
*
* @private
*
* @param {Object} ctx - roots context
*/
before_hook = function(ctx) {
var base, data, f, file_locals, folders, front_matter, i, j, len, locals, results, roots;
if (ctx.index === ctx.file.adapters.length) {
f = ctx.file;
roots = f.roots;
data = helpers.read(ctx.content);
front_matter = _.omit(data, 'content');
ctx.content = data.content;
folders = path.dirname(f.file.relative).split(path.sep);
locals = (base = f.compile_options).site != null ? base.site : base.site = {};
file_locals = f.file_options;
front_matter._categories = folders;
front_matter._url = roots.config.out(f.file, ctx.adapter.output).replace(roots.config.output_path(), '');
results = [];
for (i = j = 0, len = folders.length; j < len; i = ++j) {
f = folders[i];
if (locals[f] == null) {
locals[f] = [];
}
locals = locals[f];
if (i === folders.length - 1) {
locals.push(front_matter);
this.all_content.push(front_matter);
locals.all = all_fn;
results.push(file_locals.post = locals[locals.length - 1]);
} else {
results.push(void 0);
}
}
return results;
}
};
/**
* After a file in the category has been compiled, grabs the content and
* adds it to the locals object unless _content key is false
*
* @private
*
* @param {Object} ctx - roots context
* @return {Boolean}
*/
after_hook = function(ctx) {
var locals;
locals = ctx.file_options.post;
if (locals._content !== false) {
return locals.content = ctx.content;
}
};
/**
* After the category has finished, if the user has chosen to have all
* dynamic content written as json, make that happen. This can only happen
* if a `write` option has been provided with an `output` key. Also can
* optionally contain `flattened` and `keys` keys, which reformat or filter
* the data in a certain way.
*
* @param {Object} ctx - roots context
*/
after_category = function(ctx) {
var content, k, opt, results, v;
opt = opts.write;
if (opt) {
content = reformat(this.all_content);
if (typeof opt === 'string') {
return write_json(ctx, opt, content);
}
results = [];
for (k in opt) {
v = opt[k];
results.push(write_json(ctx, k, filter(content, v)));
}
return results;
}
};
/**
* If a dynamic file has `_render` set to false in the locals, don't write
* the file. Otherwise write as usual.
*
* @param {Object} ctx - roots context
* @return {Boolean} whether or not to write the file as usual
*/
write_hook = function(ctx) {
return ctx.file_options.post._render !== false;
};
/**
* Returns an array of all the dynamic content object in the folder
* it was called on, as well as every folder nested under it, flattened
* into a single array.
*
* @private
*
* @return {Array} Array of dynamic content objects
*/
all_fn = function() {
var recurse, values;
values = [];
recurse = function(obj) {
var j, len, o, ref, results;
ref = Object.keys(obj);
results = [];
for (j = 0, len = ref.length; j < len; j++) {
o = ref[j];
if (!isNaN(parseInt(o))) {
values.push(obj[o]);
continue;
}
results.push(recurse(obj[o]));
}
return results;
};
recurse(this);
return values;
};
return DynamicContent;
})();
};
module.exports.Helpers = helpers;
reformat = function(data) {
var base, item, j, l, len, len1, level, output, pointer, ref;
output = {};
for (j = 0, len = data.length; j < len; j++) {
item = data[j];
pointer = output;
ref = item._categories;
for (l = 0, len1 = ref.length; l < len1; l++) {
level = ref[l];
if (pointer[level] == null) {
pointer[level] = {};
}
if ((base = pointer[level])['items'] == null) {
base['items'] = [];
}
pointer = pointer[level];
}
delete item._categories;
pointer.items.push(item);
}
return output;
};
filter = function(data, keys) {
var j, key, len, pointer;
keys = keys.split('/');
pointer = data;
for (j = 0, len = keys.length; j < len; j++) {
key = keys[j];
pointer = pointer[key];
}
return pointer;
};
write_json = function(ctx, relative_path, content) {
var destination;
destination = path.join(ctx.roots.config.output_path(), relative_path);
return fs.writeFileSync(destination, JSON.stringify(content));
};
}).call(this);