Permalink
Fetching contributors…
Cannot retrieve contributors at this time
290 lines (249 sloc) 7.21 KB
'use strict';
const fs = require('fs');
const path = require('path');
const debug = require('debug')('verb-generate-readme');
const through = require('through2');
const placements = require('./lib/placements');
const sections = require('./lib/sections');
const helpers = require('./lib/helpers');
const options = require('./lib/options');
const setup = require('./lib/setup');
const utils = require('./lib/utils');
const gfm = require('./lib/gfm');
/**
* Verb readme generator
*/
function generator(app, base) {
if (!utils.isValid(app, 'verb-readme-generator')) return;
app.cwd = process.cwd();
/**
* Listeners
*/
app.on('view', view => {
view.extname = view.extname || '.md';
});
/**
* Init options
*/
options(app);
app.option(app.pkg.get('verb') || {});
/**
* Plugins
*/
app.use(require('verb-defaults'));
app.use(require('verb-collections'));
app.use(require('verb-repo-helpers'));
app.use(require('verb-repo-data'));
app.use(require('verb-toc'));
/**
* Engine
*/
app.engine('hbs', require('engine-handlebars'));
app.engine('md', app.getEngine('.*'));
/**
* Helpers
*/
helpers(app);
setup.options(app);
setup.data(app);
/**
* Alias for the [readme]() task, generates a README.md to the user's working directory.
*
* ```sh
* $ verb readme
* ```
* @name default
* @api public
*/
app.task('default', ['verbmd-prompt', 'readme']);
/**
* Generate `README.md` and fix missing [reflinks](#reflinks).
*
* ```sh
* $ verb readme
* ```
* @name readme
* @api public
*/
app.task('readme', [
'readme-middleware',
'readme-templates',
'readme-data',
'readme-render',
'readme-reflinks'
]);
/**
* Generate a README.md from a `.verb.md` template. Runs the [setup](), and [verbmd]() tasks.
* This is a [verb][docs]{tasks.md#silent} task.
*
* ```sh
* $ verb readme:readme-render
* ```
* @name readme-render
*/
app.task('readme-render', {silent: true}, function() {
debug(`starting task: ${this.name}`, __filename);
const srcBase = app.options.srcBase || app.cwd;
const file = app.options.readme || '.verb.md';
app.data('pkg', require(path.join(process.cwd(), 'package.json')));
app.data('author.linkedin', app.data('author.linkedin') || 'jonschlinkert');
app.data('author.twitter', app.data('author.twitter') || 'jonschlinkert');
return app.src(file, {cwd: srcBase})
.pipe(through.obj((file, enc, next) => {
let print = app.options.pp;
if (print) {
let str = `{%= print(${print}) %}\n` + file.contents.toString();
file.contents = Buffer.from(str);
}
next(null, file);
}))
.pipe(app.renderFile('*'))
.pipe(gfm.replace())
.pipe(utils.handle.once(app, 'prePipeline'))
.pipe(utils.reflinks(app.options))
.pipe(app.pipeline(app.options.pipeline))
.pipe(gfm.restore())
.pipe(app.dest(file => {
app.base.emit('dest', file);
file.basename = 'README.md';
return app.cwd;
}));
});
/**
* Initialize middleware used for rendering the [readme](#readme).
*
* ```sh
* $ verb readme:readme-middleware
* ```
* @name readme-middleware
*/
app.task('readme-middleware', { silent: true }, cb => {
app.handler('prePipeline');
app.preRender(/(verb|readme)\.md$/i, (file, next) => {
utils.del(path.resolve(app.cwd, 'readme.md'), next);
});
app.preWrite(/\.md$/, (file, next) => {
app.union('cache.reflinks', file._reflinks);
placements(app, file, err => {
if (err) {
next(err);
return;
}
sections(app, file, next);
});
});
cb();
});
/**
* Loads data to used for rendering templates. Called by the [readme]() task.
*
* ```sh
* $ verb readme:readme-data
* ```
* @name readme-data
*/
app.task('readme-data', { silent: true }, cb => {
app.data({bower: fs.existsSync(path.join(app.cwd, 'bower.json'))});
cb();
});
/**
* Load layouts, includes and badges commonly used for generating a README.md.
*
* ```sh
* $ verb readme:readme-templates
* ```
* @name readme-templates
*/
app.task('readme-templates', { silent: true }, cb => {
let templates = path.resolve.bind(path, __dirname, 'templates');
let config = app.base.get('cache.config') || {};
// load default docs
app.docs('*.md', {cwd: templates('docs')});
// load `layout` templates
app.layouts('*.md', { cwd: templates('layouts') });
app.includes('**/*.md', { cwd: templates('includes') });
app.includes(require('./templates/includes'));
app.badges(require('./templates/badges'));
// load `docs` templates from user `./docs` or specified dir
let docs = path.resolve(app.cwd, 'docs');
if (fs.existsSync(docs) && app.pkg.get('verb.options.docs') !== false) {
app.docs('**/*.md', { cwd: docs });
}
// call `.config.process` again to override built-in templates
// with any templates defined in `package.json`
if (typeof config.views !== 'undefined') {
app.config.process({views: config.views}, cb);
} else {
cb();
}
});
/**
* Run after other tasks to get any missing reflinks found in rendered markdown
* documents, and add them to the `verb.reflinks` array in package.json. Verb
* uses this array to generate reflinks so that missing reflinks will still resolve.
*
* ```sh
* $ verb readme:readme-reflinks
* ```
* @name readme-reflinks
*/
app.task('readme-reflinks', {silent: true}, cb => {
let existing = app.pkg.get('verb.reflinks') || [];
let reflinks = app.get('cache.reflinks') || [];
let diff = utils.diff(reflinks, existing);
if (diff.length > 1) {
app.pkg.union('verb.reflinks', diff);
app.pkg.save();
app.pkg.logInfo('updated package.json with:', {reflinks: diff});
}
cb();
});
/**
* Generate a new `.verb.md` template to the current working directory. This task is
* also aliased as `verbmd-new` to provide a semantic task name when this generator is
* used as a plugin.
*
* ```sh
* $ verb readme:new
* # or
* $ verb readme:verbmd-new
* ```
* @name new
*/
app.task('new', ['verbmd-new']);
app.task('verbmd-new', function() {
debug(`starting task: ${this.name}`, __filename);
let cwd = app.options.srcBase || path.join(__dirname, 'templates/verbmd');
return app.src('basic.md', { cwd })
.pipe(app.conflicts(app.cwd))
.pipe(app.dest(app.cwd));
});
/**
* Prompts the user to add a new `.verb.md` template to the current working directory.
* Useful in sub-generators.
*
* ```sh
* $ verb readme:verbmd-prompt
* # alias aliased as
* $ verb readme:ask
* ```
* @name verbmd-prompt
*/
app.task('verbmd-prompt', {silent: true}, function(cb) {
if (fs.existsSync('.verb.md')) return cb();
app.confirm('verbmd', 'Can\'t find a .verb.md, want to add one?');
app.ask('verbmd', { save: false }, function(err, answers) {
if (err) return cb(err);
if (answers.verbmd) {
app.build('new', cb);
} else {
cb();
}
});
});
return generator;
}
/**
* Expose `generator`
*/
module.exports = generator;