UNPKG

roots-records

Version:

dynamic content functionality for roots

239 lines (201 loc) 7.26 kB
// Generated by CoffeeScript 1.10.0 (function() { var RootsUtil, W, _, fs, node, path, rest; fs = require('fs'); rest = require('rest'); path = require('path'); W = require('when'); node = require('when/node'); _ = require('lodash'); RootsUtil = require('roots-util'); module.exports = function(opts) { var Records; return Records = (function() { /** * Creates a locals object if one isn't set. * @constructor */ var add_to_locals, apply_hook, compile_single_views, fetch, resolve_data, resolve_file, resolve_url; function Records(roots) { var base, base1; this.roots = roots; this.util = new RootsUtil(this.roots); (base = this.roots.config).locals || (base.locals = {}); (base1 = this.roots.config.locals).records || (base1.records = {}); } /** * Setup extension method loops through objects and * returns a promise to get all data and store. */ Records.prototype.setup = function() { var conf, fetch_records, key; fetch_records = (function() { var results; results = []; for (key in opts) { conf = opts[key]; results.push(fetch.call(this, key, conf)); } return results; }).call(this); return W.all(fetch_records).then(function(res) { return W.map(res, apply_hook); }).tap((function(_this) { return function(res) { return W.map(res, add_to_locals.bind(_this)); }; })(this)).tap((function(_this) { return function(res) { return W.map(res, compile_single_views.bind(_this)); }; })(this)); }; /** * Fetches the JSON data from a url, file, or data and returns it neatly as * an object containing the key, options, and resolved data. * * @param {String} key - name of the record being fetched * @param {Object} opts - options provided under the key * @returns {Promise|Object} - a promise for an object with a `key`, * `options`, and `data` values */ fetch = function(key, opts) { var data_promise; data_promise = (function() { switch (false) { case !_.has(opts, 'url'): return resolve_url(opts); case !_.has(opts, 'file'): return resolve_file.call(this, opts); case !_.has(opts, 'data'): return resolve_data(opts); default: throw new Error("You must provide a 'url', 'file', or 'data' key"); } }).call(this); return data_promise.then(function(data) { return { key: key, options: opts, data: data }; }); }; /** * Makes a request to the provided url, returning the response body as JSON. * * @param {Object} opts - the key's parameters */ resolve_url = function(opts) { var client, conf, error_code, mime; mime = require('rest/interceptor/mime'); error_code = require('rest/interceptor/errorCode'); client = rest.wrap(mime).wrap(error_code); if (typeof opts.url === 'string') { conf = { path: opts.url }; } else { conf = opts.url; } return client(conf).then(function(res) { if (!res.entity) { throw new Error("URL has not returned any content"); } if (typeof res.entity !== 'object') { throw new Error("URL did not return JSON"); } return res.entity; }); }; /** * Reads the file based on a path relative to the project root, returns the * results as JSON. * * @param {Object} obj - the key's parameters */ resolve_file = function(opts) { return node.call(fs.readFile.bind(fs), path.join(this.roots.root, opts.file), 'utf8').then(function(contents) { return JSON.parse(contents); }); }; /** * Ensures data provided is an object, then resolves it through. * * @param {Object} opts - the key's parameters */ resolve_data = function(opts) { var type; type = typeof opts.data; if (type !== 'object') { throw new Error("Data provided is a " + type + " but must be an object"); } return W.resolve(opts.data); }; /** * If a hook was provided in the config, runs the response through the hook. * * @param {String} obj - record object with a `key`, `options`, and `data` */ apply_hook = function(obj) { if (!obj.options.hook) { return obj; } obj.data = obj.options.hook(obj.data); return obj; }; /** * Given a resolved records object, adds it to the view's locals. * * @param {Object} obj - records object, containing a `key` and `data` */ add_to_locals = function(obj) { return this.roots.config.locals.records[obj.key] = obj.data; }; /** * Given a records object, if that object has `template` and `out` keys, and * its data is an array, iterates through its data, creating a single view * for each item in the array using the template provided in the `template` * value, and writing to the path provided in the `out` value. * * @param {Object} obj - record object with a `key`, `options`, and `data` */ compile_single_views = function(obj) { var obj_opts; obj_opts = obj.options; if (!obj_opts.template && !obj_opts.out) { return; } if (obj_opts.template && !obj_opts.out) { throw new Error("You must also provide an 'out' option"); } if (obj_opts.out && !obj_opts.template) { throw new Error("You must also provide a 'template' option"); } if (!Array.isArray(obj.data)) { throw new Error("'" + obj.key + "' data must be an array"); } return W.map(obj.data, (function(_this) { return function(item) { var compiler, compiler_opts, output_path, ref, tpl, tpl_path; tpl = _.isFunction(obj_opts.template) ? obj_opts.template(item) : obj_opts.template; tpl_path = path.join(_this.roots.root, tpl); output_path = (obj_opts.out(item)) + ".html"; compiler = _.find(_this.roots.config.compilers, function(c) { return _.contains(c.extensions, path.extname(tpl_path).substring(1)); }); compiler_opts = _.extend(_this.roots.config.locals, (ref = _this.roots.config[compiler.name]) != null ? ref : {}, { _path: output_path }, { item: item }); return compiler.renderFile(tpl_path, compiler_opts).then(function(res) { return _this.util.write(output_path, res.result); }); }; })(this)); }; return Records; })(); }; }).call(this);