Skip to content

Commit

Permalink
Implement package-json mixin.
Browse files Browse the repository at this point in the history
  • Loading branch information
mshima committed Feb 15, 2021
1 parent 52c90a2 commit 097cd20
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 1 deletion.
53 changes: 53 additions & 0 deletions lib/actions/package-json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use strict';

/**
* @mixin
* @alias actions/packege-json
*/
module.exports = (cls) =>
class extends cls {
/**
* @private
* Resolve the dependencies to be added to the package.json.
*
* @param {Object|string|string[]} dependencies
* @return {Promise} a 'packageName: packageVersion' object
*/
async _resolvePackageJsonDependencies(dependencies) {
if (typeof dependencies === 'string') {
dependencies = [dependencies];
} else if (typeof dependencies !== 'object') {
throw new TypeError(
'resolvePackageJsonDependencies requires an object'
);
} else if (!Array.isArray(dependencies)) {
return dependencies;
}

const entries = await Promise.all(
dependencies.map((dependency) => this.env.resolvePackage(dependency))
);
return Object.fromEntries(entries);
}

/**
* @private
* Add dependencies to be added to the package.json.
*
* @param {Object|string|string[]} dependencies
* @return {Promise} a 'packageName: packageVersion' object
*/
async addDependencies(dependencies) {
dependencies = await this._resolvePackageJsonDependencies(dependencies);
this.packageJson.merge({dependencies});
return dependencies;
}

async addDevDependencies(devDependencies) {
devDependencies = await this._resolvePackageJsonDependencies(
devDependencies
);
this.packageJson.merge({devDependencies});
return devDependencies;
}
};
24 changes: 23 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ const EMPTY = '@@_YEOMAN_EMPTY_MARKER_@@';
const debug = createDebug('yeoman:generator');
const ENV_VER_WITH_VER_API = '2.9.0';

const mixins = [require('./actions/package-json')];

// eslint-disable-next-line unicorn/no-reduce
const Base = mixins.reduce((a, b) => b(a), EventEmitter);

// Ensure a prototype method is a candidate run by default
const methodIsValid = function (name) {
return !['_', '#'].includes(name.charAt(0)) && name !== 'constructor';
Expand Down Expand Up @@ -82,7 +87,7 @@ const runGenerator = (generator) => {
* @typedef {Function} WrappedMethod
*/

class Generator extends EventEmitter {
class Generator extends Base {
// If for some reason environment adds more queues, we should use or own for stability.
static get queues() {
return [
Expand Down Expand Up @@ -965,6 +970,9 @@ class Generator extends EventEmitter {
);
}

/**
* Generator config Storage.
*/
get config() {
if (!this._config) {
this._config = this._getStorage();
Expand All @@ -973,6 +981,17 @@ class Generator extends EventEmitter {
return this._config;
}

/**
* Package.json Storage.
*/
get packageJson() {
if (!this._packageJson) {
this._packageJson = this.createStorage('package.json');
}

return this._packageJson;
}

/**
* Ignore cancellable tasks.
*/
Expand Down Expand Up @@ -1228,6 +1247,8 @@ class Generator extends EventEmitter {

// Reset the storage
this._config = undefined;
// Reset packageJson
this._packageJson = undefined;
}

return this._destinationRoot || this.env.cwd;
Expand Down Expand Up @@ -1329,6 +1350,7 @@ class Generator extends EventEmitter {
_.extend(Generator.prototype, require('./actions/help'));
_.extend(Generator.prototype, require('./actions/spawn-command'));
_.extend(Generator.prototype, require('./actions/fs'));
_.extend(Generator.prototype, require('./actions/package-json'));
Generator.prototype.user = require('./actions/user');

module.exports = Generator;
110 changes: 110 additions & 0 deletions test/package-json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
'use strict';
const assert = require('assert');
const os = require('os');
const path = require('path');
const makeDir = require('make-dir');
const rimraf = require('rimraf');
const Environment = require('yeoman-environment');

const Base = require('..');

const tmpdir = path.join(os.tmpdir(), 'yeoman-package-json');

describe('Base#package-json', function () {
this.timeout(10000);
let generator;
let env;

beforeEach(function () {
this.prevCwd = process.cwd();
this.tmp = tmpdir;
makeDir.sync(path.join(tmpdir, 'subdir'));
process.chdir(tmpdir);

env = Environment.createEnv();
const Generator = class extends Base {};
Generator.prototype.exec = function () {};
generator = new Generator({
env
});
});

afterEach(function (done) {
process.chdir(this.prevCwd);
rimraf(tmpdir, done);
});

describe('_resolvePackageJsonDependencies()', () => {
it('should accept semver version', async () => {
assert.deepStrictEqual(
await generator._resolvePackageJsonDependencies('yeoman-generator@^2'),
{'yeoman-generator': '^2'}
);
});

it('should accept github repository', async () => {
assert.deepStrictEqual(
await generator._resolvePackageJsonDependencies(
'yeoman/generator#v4.13.0'
),
{'yeoman-generator': 'github:yeoman/generator#v4.13.0'}
);
});

it('should accept github repository version', async () => {
assert.deepStrictEqual(
await generator._resolvePackageJsonDependencies(
'yeoman-generator@yeoman/generator#v4.13.0'
),
{'yeoman-generator': 'github:yeoman/generator#v4.13.0'}
);
});

it('should accept object and return it', async () => {
const a = {};
assert.strictEqual(await generator._resolvePackageJsonDependencies(a), a);
});

it('should accept arrays', async () => {
assert.deepStrictEqual(
await generator._resolvePackageJsonDependencies([
'yeoman-generator@^2',
'yeoman-environment@^2'
]),
{'yeoman-generator': '^2', 'yeoman-environment': '^2'}
);
});
});

describe('addDependencies()', () => {
it('should generate dependencies inside package.json', async () => {
await generator.addDependencies('yeoman-generator@^2');
assert.deepStrictEqual(generator.packageJson.getAll(), {
dependencies: {'yeoman-generator': '^2'}
});
});

it('should accept object and merge inside package.json', async () => {
await generator.addDependencies({'yeoman-generator': '^2'});
assert.deepStrictEqual(generator.packageJson.getAll(), {
dependencies: {'yeoman-generator': '^2'}
});
});
});

describe('addDependencies()', () => {
it('should generate dependencies inside package.json', async () => {
await generator.addDevDependencies('yeoman-generator@^2');
assert.deepStrictEqual(generator.packageJson.getAll(), {
devDependencies: {'yeoman-generator': '^2'}
});
});

it('should accept object and merge devDependencies inside package.json', async () => {
await generator.addDevDependencies({'yeoman-generator': '^2'});
assert.deepStrictEqual(generator.packageJson.getAll(), {
devDependencies: {'yeoman-generator': '^2'}
});
});
});
});

0 comments on commit 097cd20

Please sign in to comment.