generator-verb
Version:
Kickstart documentation for any project! This is the official Yeoman generator for Verb, the zero-configuration markdown docs generator that is extremely easy to use and extend.
218 lines (177 loc) • 6.36 kB
JavaScript
/*!
* generator-verb <https://github.com/assemble/generator-verb>
*
* Copyright (c) 2014 Jon Schlinkert, contributors.
* Licensed under the MIT License
*/
'use strict';
var fs = require('fs');
var path = require('path');
var util = require('util');
var glob = require('glob');
var chalk = require('chalk');
var changeCase = require('change-case');
var Configstore = require('configstore');
var normalize = require('normalize-pkg');
var yeoman = require('yeoman-generator');
var wrap = require('word-wrap');
var namify = require('namify');
var log = require('verbalize');
var yosay = require('yosay');
log.runner = 'generator-verb';
var verbConfig = new Configstore('generator-verb');
var userPkg = {};
var VerbGenerator = module.exports = function VerbGenerator() {
var self = this;
yeoman.generators.Base.apply(this, arguments);
// Mix methods from change-case into yeoman's Lo-Dash
this._.mixin(changeCase);
this._.mixin({namify: namify});
this.appname = changeCase.paramCase(this.appname);
this.readJSON = function() {
var filepath = path.join.apply(path, arguments);
return JSON.parse(self.readFileAsString(filepath));
};
this.username = this.user.git.username || process.env.user || process.env.username || null;
if (fs.existsSync('package.json')) {
userPkg = this.readJSON('package.json');
}
if (this.options['p'] || this.options['pkg']) {
userPkg = normalize.all(userPkg);
}
this.on('end', function () {
this.installDependencies({
skipInstall: this.options['skip-install'] || this.options['s'],
skipMessage: this.options['skip-welcome-message'] || this.options['w']
});
});
};
util.inherits(VerbGenerator, yeoman.generators.Base);
VerbGenerator.prototype.askFor = function askFor() {
var cb = this.async();
var prompts = [];
// have Yeoman greet the user, unless skipped
if (!this.options['skip-welcome-message']) {
this.log(yosay(
chalk.gray('Welcome to the stellar ')
+ chalk.bold('Verb')
+ chalk.gray(' generator!')
));
introductionMessage();
}
var author = verbConfig.get('author') || {};
prompts.push({
name: 'projectname',
message: 'Project name?',
default: userPkg.name ? userPkg.name : this.appname
});
prompts.push({
name: 'projectdesc',
message: 'Description?',
default: userPkg.description ? userPkg.description : 'The most interesting project in the world > Verb'
});
prompts.push({
name: 'authorname',
message: 'Author\'s name?',
default: author.name || ((userPkg.author && userPkg.author.name) ? userPkg.author.name : this.username)
});
prompts.push({
name: 'authorurl',
message: 'Author\'s URL?',
default: author.url || ((userPkg.author && userPkg.author.url) ? userPkg.author.url : ('https://github.com/' + this.username))
});
prompts.push({
name: 'username',
message: 'GitHub username/org?',
default: verbConfig.get('username') || this.username
});
this.prompt(prompts, function (props) {
verbConfig.set('username', props.username);
verbConfig.set('author', {
name: props.authorname,
url: props.authorurl
});
this.authorname = verbConfig.get('author').name;
this.authorurl = verbConfig.get('author').url;
this.username = verbConfig.get('username');
this.projectname = props.projectname;
this.projectdesc = props.projectdesc;
cb();
}.bind(this));
};
function safeCopy(thisArg, from, to) {
if (!fs.existsSync(to)) {
thisArg.copy(from, to);
}
}
function safeTemplate(thisArg, from, to) {
if (!fs.existsSync(to)) {
thisArg.template(from, to);
}
}
VerbGenerator.prototype.dotfiles = function dotfiles() {
safeCopy(this, 'gitignore', '.gitignore');
safeCopy(this, 'gitattributes', '.gitattributes');
safeCopy(this, 'editorconfig', '.editorconfig');
safeCopy(this, 'jshintrc', '.jshintrc');
};
VerbGenerator.prototype.root = function root() {
safeTemplate(this, 'index.js', 'index.js');
safeTemplate(this, 'LICENSE');
};
VerbGenerator.prototype.tests = function tests() {
this.directory('test', 'test', true);
};
VerbGenerator.prototype.travis = function travis() {
this.copy('travis.yml', '.travis.yml');
};
function mapper(patterns, cwd) {
var files = glob.sync(patterns, {cwd: cwd ||__dirname});
return files.reduce(function (acc, fp) {
var name = path.basename(fp, path.extname(fp));
acc[name] = fp.replace(/^[\\\/]*templates[\\\/]*/, '');
return acc;
}, {});
}
VerbGenerator.prototype._matcher = function(src, dest, dir, pattern) {
var files = mapper('templates/' + dir + '/' + (pattern || '*.md'));
for (var key in files) {
if (this.options.hasOwnProperty(key)) {
src = files[key];
break;
}
}
this.template(src, dest);
};
VerbGenerator.prototype.verb = function verb() {
this._matcher('verb.md', '.verb.md', 'verbfiles');
};
VerbGenerator.prototype.pkg = function pkg() {
var pkgTemplate = this.readFileAsString(__dirname + '/templates/_package.json');
var verbDefaultPkg = this.engine(pkgTemplate, this);
// If a package.json already exists, let's try to just update the
// values we asked about, and leave other data alone.
if (fs.existsSync('package.json')) {
var _pkg = this.readJSON('package.json');
_pkg.devDependencies = _pkg.devDependencies || {};
// Add any missing properties to the existing package.json
this._.defaults(_pkg, JSON.parse(verbDefaultPkg));
// Update some values we asked the user to provide.
this._.extend(_pkg.name, this.projectname);
this._.extend(_pkg.description, this.projectdesc);
this._.extend(_pkg.author.name, this.authorname);
this._.extend(_pkg.author.url, this.authorurl);
// Add `verb` to devDependencies. That's why we're here, right?
this._.extend(_pkg.devDependencies, JSON.parse(verbDefaultPkg).devDependencies);
fs.unlink('package.json');
fs.writeFileSync('package.json', JSON.stringify(_pkg, null, 2));
} else {
this.template('_package.json', 'package.json');
}
};
function introductionMessage() {
console.log(log.bold(' Head\'s up!'));
console.log();
console.log(chalk.gray(wrap('verb-generator saves time by offering to re-use answers from the previous run. If something is incorrect, no worries! Just provide a new value!')));
console.log();
}