From 00912ce9b52a51037eb7252a90f5f149923b6e53 Mon Sep 17 00:00:00 2001 From: Simon Boudrias Date: Sun, 5 Mar 2017 13:13:38 +0800 Subject: [PATCH] Remove class-extend (isn't necessary with ES6), clean jsdoc --- lib/index.js | 74 +++++++---------- lib/util/prompt-suggestion.js | 4 +- lib/util/storage.js | 11 +-- package.json | 1 - test/base.js | 102 ++++++++++-------------- test/fixtures/options-generator/main.js | 15 ++-- test/install.js | 4 +- 7 files changed, 88 insertions(+), 123 deletions(-) diff --git a/lib/index.js b/lib/index.js index 012c4583..fc3357fd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -22,7 +22,7 @@ const promptSuggestion = require('./util/prompt-suggestion'); const EMPTY = '@@_YEOMAN_EMPTY_MARKER_@@'; /** - * The `Base` class provides the common API shared by all generators. + * The `Generator` class provides the common API shared by all generators. * It define options, arguments, file, prompt, log, API, etc. * * It mixes into its prototype all the methods found in the `actions/` mixins. @@ -30,10 +30,10 @@ const EMPTY = '@@_YEOMAN_EMPTY_MARKER_@@'; * Every generator should extend this base class. * * @constructor + * @mixes actions/help * @mixes actions/install * @mixes actions/spawn-command * @mixes actions/user - * @mixes actions/help * @mixes nodejs/EventEmitter * * @param {String|Array} args @@ -57,7 +57,7 @@ const EMPTY = '@@_YEOMAN_EMPTY_MARKER_@@'; * }; */ -const Base = function (args, options) { +const Generator = function (args, options) { EventEmitter.call(this); if (!Array.isArray(args)) { @@ -141,13 +141,13 @@ const Base = function (args, options) { this.sourceRoot(path.join(path.dirname(this.resolved), 'templates')); }; -util.inherits(Base, EventEmitter); +util.inherits(Generator, EventEmitter); // Mixin the actions modules -_.extend(Base.prototype, require('./actions/install')); -_.extend(Base.prototype, require('./actions/help')); -_.extend(Base.prototype, require('./actions/spawn-command')); -Base.prototype.user = require('./actions/user'); +_.extend(Generator.prototype, require('./actions/install')); +_.extend(Generator.prototype, require('./actions/help')); +_.extend(Generator.prototype, require('./actions/spawn-command')); +Generator.prototype.user = require('./actions/user'); /* * Prompt user to answer questions. The signature of this method is the same as {@link https://github.com/SBoudrias/Inquirer.js Inquirer.js} @@ -160,7 +160,7 @@ Base.prototype.user = require('./actions/user'); * @return {Promise} */ -Base.prototype.prompt = function (questions) { +Generator.prototype.prompt = function (questions) { questions = promptSuggestion.prefillQuestions(this._globalConfig, questions); questions = promptSuggestion.prefillQuestions(this.config, questions); @@ -191,7 +191,7 @@ Base.prototype.prompt = function (questions) { * @param {Object} config */ -Base.prototype.option = function (name, config) { +Generator.prototype.option = function (name, config) { config = config || {}; // Alias default to defaults for backward compatibility. @@ -249,7 +249,7 @@ Base.prototype.option = function (name, config) { * @param {Object} config */ -Base.prototype.argument = function (name, config) { +Generator.prototype.argument = function (name, config) { config = config || {}; // Alias default to defaults for backward compatibility. @@ -270,7 +270,7 @@ Base.prototype.argument = function (name, config) { return this; }; -Base.prototype.parseOptions = function () { +Generator.prototype.parseOptions = function () { const minimistDef = { string: [], boolean: [], @@ -346,7 +346,7 @@ Base.prototype.parseOptions = function () { this.checkRequiredArgs(); }; -Base.prototype.checkRequiredArgs = function () { +Generator.prototype.checkRequiredArgs = function () { // If the help option was provided, we don't want to check for required // arguments, since we're only going to print the help message anyway. if (this.options.help) { @@ -381,7 +381,7 @@ Base.prototype.checkRequiredArgs = function () { * @param {Function} [cb] */ -Base.prototype.run = function (cb) { +Generator.prototype.run = function (cb) { cb = cb || function () {}; const self = this; @@ -496,7 +496,7 @@ Base.prototype.run = function (cb) { * this.composeWith(require.resolve('generator-bootstrap/app/main.js'), { sass: true }); */ -Base.prototype.composeWith = function (modulePath, options) { +Generator.prototype.composeWith = function (modulePath, options) { let generator; options = options || {}; @@ -537,21 +537,21 @@ Base.prototype.composeWith = function (modulePath, options) { }; /** - * Determine the root generator name (the one who's extending Base). + * Determine the root generator name (the one who's extending Generator). * @return {String} The name of the root generator */ -Base.prototype.rootGeneratorName = function () { +Generator.prototype.rootGeneratorName = function () { const pkg = readPkgUp.sync({cwd: this.resolved}).pkg; return pkg ? pkg.name : '*'; }; /** - * Determine the root generator version (the one who's extending Base). + * Determine the root generator version (the one who's extending Generator). * @return {String} The version of the root generator */ -Base.prototype.rootGeneratorVersion = function () { +Generator.prototype.rootGeneratorVersion = function () { const pkg = readPkgUp.sync({cwd: this.resolved}).pkg; return pkg ? pkg.version : '0.0.0'; }; @@ -562,7 +562,7 @@ Base.prototype.rootGeneratorVersion = function () { * @private */ -Base.prototype._getStorage = function () { +Generator.prototype._getStorage = function () { const storePath = path.join(this.destinationRoot(), '.yo-rc.json'); return new Storage(this.rootGeneratorName(), this.fs, storePath); }; @@ -573,7 +573,7 @@ Base.prototype._getStorage = function () { * @private */ -Base.prototype._getGlobalStorage = function () { +Generator.prototype._getGlobalStorage = function () { const storePath = path.join(os.homedir(), '.yo-rc-global.json'); const storeName = util.format('%s:%s', this.rootGeneratorName(), this.rootGeneratorVersion()); return new Storage(storeName, this.fs, storePath); @@ -587,7 +587,7 @@ Base.prototype._getGlobalStorage = function () { * @return {String} destination root path */ -Base.prototype.destinationRoot = function (rootPath) { +Generator.prototype.destinationRoot = function (rootPath) { if (_.isString(rootPath)) { this._destinationRoot = path.resolve(rootPath); @@ -612,7 +612,7 @@ Base.prototype.destinationRoot = function (rootPath) { * @return {String} source root path */ -Base.prototype.sourceRoot = function (rootPath) { +Generator.prototype.sourceRoot = function (rootPath) { if (_.isString(rootPath)) { this._sourceRoot = path.resolve(rootPath); } @@ -626,7 +626,7 @@ Base.prototype.sourceRoot = function (rootPath) { * @return {String} joined path */ -Base.prototype.templatePath = function () { +Generator.prototype.templatePath = function () { let filepath = path.join.apply(path, arguments); if (!path.isAbsolute(filepath)) { @@ -642,7 +642,7 @@ Base.prototype.templatePath = function () { * @return {String} joined path */ -Base.prototype.destinationPath = function () { +Generator.prototype.destinationPath = function () { let filepath = path.join.apply(path, arguments); if (!path.isAbsolute(filepath)) { @@ -660,7 +660,7 @@ Base.prototype.destinationPath = function () { * Finally defaults to the name of the current directory. * @return {String} The name of the application */ -Base.prototype.determineAppname = function () { +Generator.prototype.determineAppname = function () { let appname = this.fs.readJSON(this.destinationPath('bower.json'), {}).name; if (!appname) { @@ -683,7 +683,7 @@ Base.prototype.determineAppname = function () { * or a single one. * @return {this} */ -Base.prototype.registerTransformStream = function (streams) { +Generator.prototype.registerTransformStream = function (streams) { assert(streams, 'expected to receive a transform stream as parameter'); if (!_.isArray(streams)) { streams = [streams]; @@ -695,8 +695,9 @@ Base.prototype.registerTransformStream = function (streams) { /** * Write memory fs file to disk and logging results * @param {Function} done - callback once files are written + * @private */ -Base.prototype._writeFiles = function (done) { +Generator.prototype._writeFiles = function (done) { const self = this; const conflictChecker = through.obj(function (file, enc, cb) { @@ -738,19 +739,4 @@ Base.prototype._writeFiles = function (done) { }); }; -/** - * Extend the Generator class to create a new one inherithing the base one. This - * method is useful if your environment do not suport the ES6 classes. - * @param {Object} protoProps Prototype properties (available on the instances) - * @param {Object} staticProps Static properties (available on the contructor) - * @return {Object} New sub class - * @example - * var Generator = require('yeoman-generator'); - * module.exports = Generator.extend({ - * writing: function () {} - * // ... - * }); - */ -Base.extend = require('class-extend').extend; - -module.exports = Base; +module.exports = Generator; diff --git a/lib/util/prompt-suggestion.js b/lib/util/prompt-suggestion.js index 96c10ae2..ca2c5039 100644 --- a/lib/util/prompt-suggestion.js +++ b/lib/util/prompt-suggestion.js @@ -3,8 +3,8 @@ const assert = require('assert'); const _ = require('lodash'); /** - * @mixin - * @alias util/prompt-suggestion + * @module promptSuggestion + * @description Utilities to allow remembering answers to Inquirer.js prompts */ const promptSuggestion = module.exports; diff --git a/lib/util/storage.js b/lib/util/storage.js index ced545a5..4beab9d0 100644 --- a/lib/util/storage.js +++ b/lib/util/storage.js @@ -5,7 +5,7 @@ const _ = require('lodash'); /** * Storage instances handle a json file where Generator authors can store data. * - * `Base` instantiate the storage as `config` by default. + * The `Generator` class instantiate the storage named `config` by default. * * @constructor * @param {String} name The name of the new storage (this is a namespace) @@ -13,11 +13,11 @@ const _ = require('lodash'); * @param {String} configPath The filepath used as a storage. * * @example - * var MyGenerator = yeoman.base.extend({ - * config: function() { + * class extend Generator { + * writing: function() { * this.config.set('coffeescript', false); * } - * }); + * } */ class Storage { constructor(name, fs, configPath) { @@ -32,8 +32,8 @@ class Storage { /** * Return the current store as JSON object - * @private * @return {Object} the store content + * @private */ get _store() { return this.fs.readJSON(this.path, {})[this.name] || {}; @@ -42,6 +42,7 @@ class Storage { /** * Persist a configuration to disk * @param {Object} val - current configuration values + * @private */ _persist(val) { const fullStore = this.fs.readJSON(this.path, {}); diff --git a/package.json b/package.json index 9c2c080f..19a40979 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "dependencies": { "async": "^2.0.0", "chalk": "^1.0.0", - "class-extend": "^0.1.0", "cli-table": "^0.3.1", "cross-spawn": "^5.0.1", "dargs": "^5.1.0", diff --git a/test/base.js b/test/base.js index b7c08fda..f3cabd99 100644 --- a/test/base.js +++ b/test/base.js @@ -4,6 +4,7 @@ const os = require('os'); const LF = require('os').EOL; const path = require('path'); const util = require('util'); +const _ = require('lodash'); const sinon = require('sinon'); const mkdirp = require('mkdirp'); const mockery = require('mockery'); @@ -31,9 +32,8 @@ describe('Base', () => { beforeEach(function () { this.env = yeoman.createEnv([], {'skip-install': true}, new TestAdapter()); mkdirp.sync(resolveddir); - this.Dummy = Base.extend({ - exec: sinon.spy() - }); + this.Dummy = class extends Base {}; + this.Dummy.prototype.exec = sinon.spy(); this.dummy = new this.Dummy(['bar', 'baz', 'bom'], { foo: false, @@ -64,7 +64,7 @@ describe('Base', () => { }); it('use the environment options', function () { - this.env.registerStub(Base.extend(), 'ember:model'); + this.env.registerStub(class extends Base {}, 'ember:model'); const generator = this.env.create('ember:model', { options: { @@ -173,33 +173,10 @@ describe('Base', () => { }); }); - describe('.extend()', () => { - it('create a new object inheriting the Generator', function () { - const gen = new (Base.extend())([], {resolved: 'path/', env: this.env}); - assert.ok(gen instanceof Base); - }); - - it('pass the extend method along', () => { - const Sub = Base.extend(); - assert.equal(Sub.extend, Base.extend); - }); - - it('assign prototype methods', () => { - const proto = {foo() {}}; - const Sub = Base.extend(proto); - assert.equal(Sub.prototype.foo, proto.foo); - }); - - it('assign static methods', () => { - const staticProps = {foo() {}}; - const Sub = Base.extend({}, staticProps); - assert.equal(Sub.foo, staticProps.foo); - }); - }); - describe('#run()', () => { beforeEach(function () { - this.TestGenerator = Base.extend({ + this.TestGenerator = class extends Base {}; + _.extend(this.TestGenerator.prototype, { exec: sinon.spy(), exec2: sinon.spy(), exec3: sinon.spy(), @@ -369,7 +346,7 @@ describe('Base', () => { }); it('throws if no method is available', function () { - const gen = new (Base.extend())([], { + const gen = new (class extends Base {})([], { resolved: 'generator-ember/all/index.js', namespace: 'dummy', env: this.env @@ -551,13 +528,13 @@ describe('Base', () => { }); it('allows specifying default argument values', function () { - const Generator = Base.extend({ - constructor: function () { - Base.apply(this, arguments); + const Generator = class extends Base { + constructor(args, opts) { + super(args, opts); this.argument('bar', {default: 'baz'}); } - }); + }; const gen = new Generator({ env: this.env, @@ -568,13 +545,13 @@ describe('Base', () => { }); it('allows specifying default argument values', function () { - const Generator = Base.extend({ - constructor: function () { - Base.apply(this, arguments); + const Generator = class extends Base { + constructor(args, opts) { + super(args, opts); this.argument('bar', {default: 'baz'}); } - }); + }; const gen = new Generator({ env: this.env, @@ -585,13 +562,13 @@ describe('Base', () => { }); it('properly uses arguments values passed from constructor', function () { - const Generator = Base.extend({ - constructor: function () { - Base.apply(this, arguments); + const Generator = class extends Base { + constructor(args, opts) { + super(args, opts); this.argument('bar', {default: 'baz'}); } - }); + }; const gen = new Generator({ env: this.env, @@ -661,16 +638,16 @@ describe('Base', () => { }); it('allow aliasing options', function () { - const Generator = Base.extend({ - constructor: function () { - Base.apply(this, arguments); + const Generator = class extends Base { + constructor(args, opts) { + super(args, opts); this.option('long-name', { alias: 'short-name', type: String }); } - }); + }; const gen = new Generator({ env: this.env, @@ -682,13 +659,13 @@ describe('Base', () => { }); it('allows Boolean options to be undefined', function () { - const Generator = Base.extend({ - constructor: function () { - Base.apply(this, arguments); + const Generator = class extends Base { + constructor(args, opts) { + super(args, opts); this.option('undef', {type: Boolean}); } - }); + }; const gen = new Generator({ env: this.env, @@ -767,7 +744,8 @@ describe('Base', () => { }); this.spy = sinon.spy(); - this.GenCompose = Base.extend({exec: this.spy}); + this.GenCompose = class extends Base {}; + this.GenCompose.prototype.exec = this.spy; this.env.registerStub(this.GenCompose, 'composed:gen'); }); @@ -815,7 +793,8 @@ describe('Base', () => { beforeEach(function () { this.spy = sinon.spy(); this.stubPath = path.join(__dirname, 'fixtures/generator-mocha'); - this.LocalDummy = Base.extend({exec: this.spy}); + this.LocalDummy = class extends Base {}; + this.LocalDummy.prototype.exec = this.spy; mockery.registerMock(this.stubPath, this.LocalDummy); }); @@ -964,9 +943,8 @@ describe('Base', () => { describe('#registerTransformStream()', () => { beforeEach(function () { this.filepath = path.join(os.tmpdir(), '/yeoman-transform-stream/filea.txt'); - this.TestGenerator = Base.extend({ - exec: sinon.spy() - }); + this.TestGenerator = class extends Base {}; + this.TestGenerator.prototype.exec = sinon.spy(); this.testGen = new this.TestGenerator([], { resolved: 'generator-ember/all/index.js', namespace: 'dummy', @@ -1110,17 +1088,19 @@ describe('Base', () => { it('triggers end event after all generators methods are ran (#709)', done => { const endSpy = sinon.spy(); - const GeneratorEnd = Base.extend({ - constructor: function () { - Base.apply(this, arguments); + const GeneratorEnd = class extends Base { + constructor(args, opts) { + super(args, opts); this.on('end', () => { sinon.assert.calledOnce(endSpy); done(); }); - }, + } - end: endSpy - }); + end() { + endSpy(); + } + }; const generatorEnd = new GeneratorEnd([], { env: yeoman.createEnv([], {}, new TestAdapter()), diff --git a/test/fixtures/options-generator/main.js b/test/fixtures/options-generator/main.js index 31a342fb..14affc9a 100644 --- a/test/fixtures/options-generator/main.js +++ b/test/fixtures/options-generator/main.js @@ -9,21 +9,20 @@ var Base = require('../../../'); -module.exports = Base.extend({ - constructor: function () { - Base.apply(this, arguments); +module.exports = class extends Base { + constructor(args, opts) { + super(args, opts); - // this.log('as passed in: ', this.options.testOption); this.option('testOption', { type: Boolean, desc: 'Testing falsey values for option', defaults: true }); - }, + } - testOption: function () { - // this.log('as rendered: ', this.options.testOption); + testOption() { + return 'foo'; } -}); +}; module.exports.namespace = 'options:generator'; diff --git a/test/install.js b/test/install.js index 98f3037f..2a1cf9dd 100644 --- a/test/install.js +++ b/test/install.js @@ -17,9 +17,9 @@ const asyncStub = { describe('Base (actions/install mixin)', () => { beforeEach(function () { this.env = yeoman.createEnv([], {}, new TestAdapter()); - const Dummy = Base.extend({ + const Dummy = class extends Base { exec() {} - }); + }; this.env.registerStub(Dummy, 'dummy'); this.dummy = this.env.create('dummy');