verb
Version:
Verb makes it easy to build project documentation using simple markdown templates, with zero configuration required.
248 lines (195 loc) • 5.95 kB
JavaScript
/**
* Verb <https://github.com/assemble/verb>
* Generate markdown documentation for GitHub projects.
*
* Copyright (c) 2014 Jon Schlinkert, Brian Woodward, contributors.
* Licensed under the MIT license.
*/
;
var path = require('path');
var file = require('fs-utils');
var configFile = require('config-file');
var cwd = require('cwd');
var _ = require('lodash');
/**
* verb
*/
var verb = module.exports = {};
verb.cwd = cwd;
verb.base = cwd;
verb.file = _.defaults(require('./lib/file'), file);
// Logging and utils
verb.colors = require('./lib/colors');
verb.utils = require('./lib/utils/index');
verb.log = require('./lib/log');
verb.verbose = verb.log.verbose;
verb.mode = {};
verb.mode.verbose = false;
// Extensions
verb.plugins = require('./lib/plugins');
verb.filters = require('./lib/filters');
verb.tags = require('./lib/tags');
// Templates
verb.scaffolds = require('./lib/scaffolds');
verb.template = require('./lib/template');
// Data
verb.data = require('./lib/data');
verb.matter = require('./lib/matter');
verb.exclusions = require('./lib/exclusions');
verb.ext = '.md';
// Adds the `runner` property to the context, for
// thirdy-party tools using Verb to be specified
verb.runner = {
name: 'Verb',
url: 'https://github.com/assemble/verb'
};
/**
* runtime config
*/
verb.verbrc = {};
if (file.exists('.verbrc')) {
verb.verbrc = configFile.load('.verbrc');
} else if (file.exists('.verbrc.yml')) {
verb.verbrc = configFile.load('.verbrc.yml');
}
/**
* verb.init
*/
verb.init = function (options) {
if (verb.initalized) {
return;
}
verb.initalized = true;
var opts = _.extend({verbose: false}, options);
verb.mode.verbose = opts.verbose;
// Initialize mixins
_.fn = require('./lib/mixins.js');
_.mixin(_.fn);
};
/**
* verb.process
*/
verb.process = function(src, options) {
var opts = _.extend({toc: {maxDepth: 2}}, options);
verb.init(opts);
// Add runtime config
var runtimeConfig;
if(opts.verbrc) {
runtimeConfig = configFile.load(cwd(opts.verbrc));
} else {
runtimeConfig = verb.verbrc;
}
_.extend(opts, runtimeConfig);
verb.options = opts;
verb.config = require('./lib/config').init(opts.config);
verb.context = _.extend({}, verb.config);
delete verb.context.config;
src = src || '';
// Extend `verb`
verb.layout = require('./lib/layout')(verb);
// Build up the context
_.extend(verb.context, opts);
_.extend(verb.context, opts.metadata || {});
_.extend(verb.context, require('./lib/data').init(opts));
// Template settings
var settings = _.defaults({}, opts.settings);
// Initialize Lo-Dash tags and filters
_.extend(verb.context, verb.tags.init(verb));
_.extend(verb.context, verb.filters.init(verb));
// Initialize `options.data`
_.extend(verb.context, verb.data.init(opts));
// Extract and parse front matter
verb.page = verb.matter.init(src, opts);
_.extend(verb.context, verb.page.context);
// Exclusion patterns, to omit certain options from context
verb.context = verb.exclusions(verb.context, opts);
_.extend(verb.context, {runner: verb.runner});
// Initialize plugins
_.extend(verb.context, verb.plugins.init(verb));
// Process templates and render content
var renderDone = false;
var rendered = verb.template(verb.page.content, verb.context, settings);
verb.tags.resolve(verb, rendered, function (err, results) {
rendered = results;
renderDone = true;
});
while (!renderDone) {
process.nextTick();
}
var result = verb.utils.postProcess(rendered, opts);
// Generate a TOC from <!-- toc --> after all content is included.
result = require('marked-toc').insert(result, opts.toc);
return {
verb: verb,
context: verb.context,
content: result,
original: src
};
};
// Read a file, then process with Verb
verb.read = function(src, options) {
options = options || {};
verb.init(options);
verb.options = verb.options || {};
_.extend(verb.options, options)
var content = file.readFileSync(src);
return verb.process(content, options).content;
};
// Read a file, process it with Verb, then write it.
verb.copy = function(src, dest, options) {
options = options || {};
verb.init(options);
verb.options = _.extend(verb.options || {}, options);
verb.options.dest = dest || verb.cwd();
file.writeFileSync(dest, verb.read(src, options));
verb.log.success('Saved to:', dest);
};
// Expand filepaths
verb.expandMapping = function(src, dest, options) {
var opts = _.extend({concat: false}, options);
verb.init(opts);
dest = dest || verb.cwd();
verb.options = _.extend(verb.options || {}, options);
verb.options.dest = verb.cwd(dest) || verb.cwd();
var defaults = {
cwd: opts.cwd || verb.cwd('.'),
ext: verb.ext || opts.ext,
destBase: dest
};
defaults.srcBase = defaults.cwd;
var concat = opts.concat || file.hasExt(dest) || false;
var defer = [];
var count = 0;
file.expandMapping(src, defaults).map(function(fp) {
fp.src.filter(function(filepath) {
if (!file.exists(filepath)) {
verb.log.error('>> Source file "' + filepath + '" not found.');
return false;
} else {
return true;
}
}).map(function(filepath) {
verb.options.src = filepath;
if(!concat) {
count++;
file.writeFileSync(fp.dest, verb.read(filepath, opts));
verb.log.success('Saved to', fp.dest);
} else {
defer.push(filepath);
}
});
});
if(concat) {
count = 1;
var blob = _.flatten(defer).map(function(filepath) {
return verb.read(filepath, opts);
}).join('\n');
file.writeFileSync(dest, blob);
verb.log.success('Saved to', dest);
}
if(count >= 1) {
verb.log.success('Done\n');
} else {
verb.log.error('Failed.\n');
}
};