UNPKG

yeoman-generator

Version:

Rails-inspired generator system that provides scaffolding for your apps

173 lines (145 loc) 4.6 kB
'use strict'; var path = require('path'); var assert = require('assert'); var _ = require('lodash'); var yeoman = require('../..'); var util = require('util'); var EventEmitter = require('events').EventEmitter; var helpers = require('./helpers'); /** * This class provide a run context object to façade the complexity involved in setting * up a generator for testing * @constructor * @param {String|Function} Generator - Namespace or generator constructor. If the later * is provided, then namespace is assumed to be * 'gen:test' in all cases * @return {this} */ var RunContext = module.exports = function RunContext(Generator) { this._asyncHolds = 0; this.runned = false; this.args = []; this.options = {}; this._dependencies = []; this.Generator = Generator; setTimeout(this._run.bind(this), 0); }; util.inherits(RunContext, EventEmitter); /** * Hold the execution until the returned callback is triggered * @return {Function} Callback to notify the normal execution can resume */ RunContext.prototype.async = function () { this._asyncHolds++; return function () { this._asyncHolds--; this._run(); }.bind(this); }; /** * Method called when the context is ready to run the generator * @private */ RunContext.prototype._run = function () { if (this._asyncHolds !== 0 || this.runned) return; this.runned = true; var namespace; this.env = yeoman(); helpers.registerDependencies(this.env, this._dependencies); if (_.isString(this.Generator)) { namespace = this.env.namespace(this.Generator); this.env.register(this.Generator); } else { namespace = 'gen:test'; this.env.registerStub(this.Generator, namespace); } this.generator = this.env.create(namespace, { arguments: this.args, options: _.extend({ 'skip-install': true }, this.options) }); helpers.mockPrompt(this.generator, this._answers); this.generator.once('end', this.emit.bind(this, 'end')); this.emit('ready', this.generator); this.generator.run(); }; /** * Clean the provided directory, then change directory into it * @param {String} dirPath - Directory path (relative to CWD). Prefer passing an absolute * file path for predictable results * @return {this} */ RunContext.prototype.inDir = function (dirPath, cb) { var release = this.async(); var callBackThenRelease = _.compose(release, (cb || _.noop).bind(this, path.resolve(dirPath))); helpers.testDirectory(dirPath, callBackThenRelease); return this; }; /** * Provide arguments to the run context * @param {String|Array} args - command line arguments as Array or space separated string * @return {this} */ RunContext.prototype.withArguments = function (args) { this.args = _.isString(args) ? args.split(' ') : args; return this; }; /** * Provide options to the run context * @param {Object} options - command line options (e.g. `--opt-one=foo`) * @return {this} */ RunContext.prototype.withOptions = function (options) { this.options = options; return this; }; /** * Mock the prompt with dummy answers * @param {Object} answers - Answers to the prompt questions * @return {this} */ RunContext.prototype.withPrompts = function (answers) { this._answers = answers; return this; }; /** * @alias RunContext.prototype.withPrompts * @deprecated */ RunContext.prototype.withPrompt = RunContext.prototype.withPrompts; /** * Provide dependent generators * @param {Array} dependencies - paths to the generators dependencies * @return {this} * @example * var deps = ['../../common', * '../../controller', * '../../main', * [helpers.createDummyGenerator(), 'testacular:app'] * ]; * var angular = new RunContext('../../app'); * angular.withGenerator(deps); * angular.withPrompt({ * compass: true, * bootstrap: true * }); * angular.onEnd(function () { * // assert something * }); */ RunContext.prototype.withGenerators = function (dependencies) { assert(_.isArray(dependencies), 'dependencies should be an array'); this._dependencies = this._dependencies.concat(dependencies); return this; }; /** * Add a callback to be called after the generator has ran * @deprecated `onEnd` is deprecated, use .on('end', onEndHandler) instead. * @param {Function} callback * @return {this} */ RunContext.prototype.onEnd = function (cb) { console.log('`onEnd` is deprecated, use .on(\'end\', onEndHandler) instead.'); return this.on('end', cb); };