Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

yeoman-environment

Package Overview
Dependencies
Maintainers
7
Versions
128
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

yeoman-environment - npm Package Compare versions

Comparing version 1.6.6 to 2.0.0

127

lib/adapter.js
'use strict';
const _ = require('lodash');
const inquirer = require('inquirer');
const diff = require('diff');
const chalk = require('chalk');
const logger = require('./util/log');
var _ = require('lodash');
var inquirer = require('inquirer');
var diff = require('diff');
var chalk = require('chalk');
var logger = require('./util/log');
/**

@@ -17,60 +16,70 @@ * `TerminalAdapter` is the default implementation of `Adapter`, an abstraction

*/
var TerminalAdapter = module.exports = function TerminalAdapter() {
this.promptModule = inquirer.createPromptModule();
};
class TerminalAdapter {
constructor() {
this.promptModule = inquirer.createPromptModule();
}
TerminalAdapter.prototype._colorDiffAdded = chalk.black.bgGreen;
TerminalAdapter.prototype._colorDiffRemoved = chalk.bgRed;
TerminalAdapter.prototype._colorLines = function colorLines(name, str) {
return str.split('\n').map(function (line) {
return this['_colorDiff' + name](line);
}, this).join('\n');
};
get _colorDiffAdded() {
return chalk.black.bgGreen;
}
/**
* Prompt a user for one or more questions and pass
* the answer(s) to the provided callback.
*
* It shares its interface with `Base.prompt`
*
* (Defined inside the constructor to keep interfaces separated between
* instances)
*
* @param {Array} questions
* @param {Function} callback
*/
TerminalAdapter.prototype.prompt = function () {};
get _colorDiffRemoved() {
return chalk.bgRed;
}
/**
* Shows a color-based diff of two strings
*
* @param {string} actual
* @param {string} expected
*/
TerminalAdapter.prototype.diff = function _diff(actual, expected) {
var msg = diff.diffLines(actual, expected).map(function (str) {
if (str.added) {
return this._colorLines('Added', str.value);
}
_colorLines(name, str) {
return str.split('\n').map(line => this[`_colorDiff${name}`](line)).join('\n');
}
if (str.removed) {
return this._colorLines('Removed', str.value);
}
/**
* Prompt a user for one or more questions and pass
* the answer(s) to the provided callback.
*
* It shares its interface with `Base.prompt`
*
* (Defined inside the constructor to keep interfaces separated between
* instances)
*
* @param {Array} questions
* @param {Function} callback
*/
prompt(questions, cb) {
const promise = this.promptModule(questions);
promise.then(cb || _.noop);
return promise;
}
return str.value;
}, this).join('');
/**
* Shows a color-based diff of two strings
*
* @param {string} actual
* @param {string} expected
*/
diff(actual, expected) {
let msg = diff.diffLines(actual, expected).map(str => {
if (str.added) {
return this._colorLines('Added', str.value);
}
// legend
msg = '\n' +
this._colorDiffRemoved('removed') +
' ' +
this._colorDiffAdded('added') +
'\n\n' +
msg +
'\n';
if (str.removed) {
return this._colorLines('Removed', str.value);
}
console.log(msg);
return msg;
};
return str.value;
}).join('');
// Legend
msg = '\n' +
this._colorDiffRemoved('removed') +
' ' +
this._colorDiffAdded('added') +
'\n\n' +
msg +
'\n';
console.log(msg);
return msg;
}
}
/**

@@ -82,6 +91,2 @@ * Logging utility

TerminalAdapter.prototype.prompt = function (questions, cb) {
var promise = this.promptModule(questions);
promise.then(cb || _.noop);
return promise;
};
module.exports = TerminalAdapter;
'use strict';
var util = require('util');
var fs = require('fs');
var path = require('path');
var events = require('events');
var chalk = require('chalk');
var _ = require('lodash');
var GroupedQueue = require('grouped-queue');
var escapeStrRe = require('escape-string-regexp');
var untildify = require('untildify');
var memFs = require('mem-fs');
var debug = require('debug')('yeoman:environment');
var Store = require('./store');
var resolver = require('./resolver');
var TerminalAdapter = require('./adapter');
const fs = require('fs');
const path = require('path');
const EventEmitter = require('events');
const chalk = require('chalk');
const _ = require('lodash');
const GroupedQueue = require('grouped-queue');
const escapeStrRe = require('escape-string-regexp');
const untildify = require('untildify');
const memFs = require('mem-fs');
const debug = require('debug')('yeoman:environment');
const isScoped = require('is-scoped');
const Store = require('./store');
const resolver = require('./resolver');
const TerminalAdapter = require('./adapter');

@@ -39,488 +39,482 @@ /**

*/
class Environment extends EventEmitter {
static get queues() {
return [
'initializing',
'prompting',
'configuring',
'default',
'writing',
'conflicts',
'install',
'end'
];
}
var Environment = module.exports = function Environment(args, opts, adapter) {
events.EventEmitter.call(this);
/**
* Make sure the Environment present expected methods if an old version is
* passed to a Generator.
* @param {Environment} env
* @return {Environment} The updated env
*/
static enforceUpdate(env) {
if (!env.adapter) {
env.adapter = new TerminalAdapter();
}
args = args || [];
this.arguments = Array.isArray(args) ? args : args.split(' ');
this.options = opts || {};
this.adapter = adapter || new TerminalAdapter();
this.cwd = this.options.cwd || process.cwd();
this.store = new Store();
if (!env.runLoop) {
env.runLoop = new GroupedQueue([
'initializing',
'prompting',
'configuring',
'default',
'writing',
'conflicts',
'install',
'end'
]);
}
this.runLoop = new GroupedQueue(Environment.queues);
this.sharedFs = memFs.create();
if (!env.sharedFs) {
env.sharedFs = memFs.create();
}
// Each composed generator might set listeners on these shared resources. Let's make sure
// Node won't complain about event listeners leaks.
this.runLoop.setMaxListeners(0);
this.sharedFs.setMaxListeners(0);
return env;
}
this.lookups = ['.', 'generators', 'lib/generators'];
this.aliases = [];
/**
* Factory method to create an environment instance. Take same parameters as the
* Environment constructor.
*
* @see This method take the same arguments as {@link Environment} constructor
*
* @return {Environment} a new Environment instance
*/
static createEnv(args, opts, adapter) {
return new Environment(args, opts, adapter);
}
this.alias(/^([^:]+)$/, '$1:app');
};
/**
* Convert a generators namespace to its name
*
* @param {String} namespace
* @return {String}
*/
static namespaceToName(namespace) {
return namespace.split(':')[0];
}
util.inherits(Environment, events.EventEmitter);
_.extend(Environment.prototype, resolver);
constructor(args, opts, adapter) {
super();
Environment.queues = [
'initializing',
'prompting',
'configuring',
'default',
'writing',
'conflicts',
'install',
'end'
];
args = args || [];
this.arguments = Array.isArray(args) ? args : args.split(' ');
this.options = opts || {};
this.adapter = adapter || new TerminalAdapter();
this.cwd = this.options.cwd || process.cwd();
this.store = new Store();
/**
* Error handler taking `err` instance of Error.
*
* The `error` event is emitted with the error object, if no `error` listener
* is registered, then we throw the error.
*
* @param {Object} err
* @return {Error} err
*/
this.runLoop = new GroupedQueue(Environment.queues);
this.sharedFs = memFs.create();
Environment.prototype.error = function error(err) {
err = err instanceof Error ? err : new Error(err);
// Each composed generator might set listeners on these shared resources. Let's make sure
// Node won't complain about event listeners leaks.
this.runLoop.setMaxListeners(0);
this.sharedFs.setMaxListeners(0);
if (!this.emit('error', err)) {
throw err;
this.lookups = ['.', 'generators', 'lib/generators'];
this.aliases = [];
this.alias(/^([^:]+)$/, '$1:app');
}
return err;
};
/**
* Error handler taking `err` instance of Error.
*
* The `error` event is emitted with the error object, if no `error` listener
* is registered, then we throw the error.
*
* @param {Object} err
* @return {Error} err
*/
error(err) {
err = err instanceof Error ? err : new Error(err);
/**
* Outputs the general help and usage. Optionally, if generators have been
* registered, the list of available generators is also displayed.
*
* @param {String} name
*/
if (!this.emit('error', err)) {
throw err;
}
Environment.prototype.help = function help(name) {
name = name || 'init';
return err;
}
var out = [
'Usage: :binary: GENERATOR [args] [options]',
'',
'General options:',
' --help # Print generator\'s options and usage',
' -f, --force # Overwrite files that already exist',
'',
'Please choose a generator below.',
''
];
/**
* Outputs the general help and usage. Optionally, if generators have been
* registered, the list of available generators is also displayed.
*
* @param {String} name
*/
help(name) {
name = name || 'init';
var ns = this.namespaces();
const out = [
'Usage: :binary: GENERATOR [args] [options]',
'',
'General options:',
' --help # Print generator\'s options and usage',
' -f, --force # Overwrite files that already exist',
'',
'Please choose a generator below.',
''
];
var groups = {};
ns.forEach(function (namespace) {
var base = namespace.split(':')[0];
const ns = this.namespaces();
if (!groups[base]) {
groups[base] = [];
const groups = {};
for (const namespace of ns) {
const base = namespace.split(':')[0];
if (!groups[base]) {
groups[base] = [];
}
groups[base].push(namespace);
}
groups[base].push(namespace);
});
for (const key of Object.keys(groups).sort()) {
const group = groups[key];
Object.keys(groups).sort().forEach(function (key) {
var group = groups[key];
if (group.length >= 1) {
out.push('', key.charAt(0).toUpperCase() + key.slice(1));
}
if (group.length >= 1) {
out.push('', key.charAt(0).toUpperCase() + key.slice(1));
for (const ns of groups[key]) {
out.push(` ${ns}`);
}
}
groups[key].forEach(function (ns) {
out.push(' ' + ns);
});
});
return out.join('\n').replace(/:binary:/g, name);
}
return out.join('\n').replace(/:binary:/g, name);
};
/**
* Registers a specific `generator` to this environment. This generator is stored under
* provided namespace, or a default namespace format if none if available.
*
* @param {String} name - Filepath to the a generator or a npm package name
* @param {String} namespace - Namespace under which register the generator (optional)
* @return {String} namespace - Namespace assigned to the registered generator
*/
register(name, namespace) {
if (typeof name !== 'string') {
return this.error(new Error('You must provide a generator name to register.'));
}
/**
* Registers a specific `generator` to this environment. This generator is stored under
* provided namespace, or a default namespace format if none if available.
*
* @param {String} name - Filepath to the a generator or a npm package name
* @param {String} namespace - Namespace under which register the generator (optional)
* @return {String} namespace - Namespace assigned to the registered generator
*/
const modulePath = this.resolveModulePath(name);
namespace = namespace || this.namespace(modulePath);
Environment.prototype.register = function register(name, namespace) {
if (!_.isString(name)) {
return this.error(new Error('You must provide a generator name to register.'));
}
if (!namespace) {
return this.error(new Error('Unable to determine namespace.'));
}
var modulePath = this.resolveModulePath(name);
namespace = namespace || this.namespace(modulePath);
this.store.add(namespace, modulePath);
if (!namespace) {
return this.error(new Error('Unable to determine namespace.'));
debug('Registered %s (%s)', namespace, modulePath);
return this;
}
this.store.add(namespace, modulePath);
/**
* Register a stubbed generator to this environment. This method allow to register raw
* functions under the provided namespace. `registerStub` will enforce the function passed
* to extend the Base generator automatically.
*
* @param {Function} Generator - A Generator constructor or a simple function
* @param {String} namespace - Namespace under which register the generator
* @return {this}
*/
registerStub(Generator, namespace) {
if (typeof Generator !== 'function') {
return this.error(new Error('You must provide a stub function to register.'));
}
debug('Registered %s (%s)', namespace, modulePath);
return this;
};
if (typeof namespace !== 'string') {
return this.error(new Error('You must provide a namespace to register.'));
}
/**
* Register a stubbed generator to this environment. This method allow to register raw
* functions under the provided namespace. `registerStub` will enforce the function passed
* to extend the Base generator automatically.
*
* @param {Function} Generator - A Generator constructor or a simple function
* @param {String} namespace - Namespace under which register the generator
* @return {this}
*/
this.store.add(namespace, Generator);
Environment.prototype.registerStub = function registerStub(Generator, namespace) {
if (!_.isFunction(Generator)) {
return this.error(new Error('You must provide a stub function to register.'));
return this;
}
if (!_.isString(namespace)) {
return this.error(new Error('You must provide a namespace to register.'));
/**
* Returns the list of registered namespace.
* @return {Array}
*/
namespaces() {
return this.store.namespaces();
}
this.store.add(namespace, Generator);
/**
* Returns stored generators meta
* @return {Object}
*/
getGeneratorsMeta() {
return this.store.getGeneratorsMeta();
}
return this;
};
/**
* Get registered generators names
*
* @return {Array}
*/
getGeneratorNames() {
return _.uniq(Object.keys(this.getGeneratorsMeta()).map(Environment.namespaceToName));
}
/**
* Returns the list of registered namespace.
* @return {Array}
*/
/**
* Get a single generator from the registered list of generators. The lookup is
* based on generator's namespace, "walking up" the namespaces until a matching
* is found. Eg. if an `angular:common` namespace is registered, and we try to
* get `angular:common:all` then we get `angular:common` as a fallback (unless
* an `angular:common:all` generator is registered).
*
* @param {String} namespaceOrPath
* @return {Generator|null} - the generator registered under the namespace
*/
get(namespaceOrPath) {
// Stop the recursive search if nothing is left
if (!namespaceOrPath) {
return;
}
Environment.prototype.namespaces = function namespaces() {
return this.store.namespaces();
};
let namespace = namespaceOrPath;
/**
* Returns stored generators meta
* @return {Object}
*/
// Legacy yeoman-generator `#hookFor()` function is passing the generator path as part
// of the namespace. If we find a path delimiter in the namespace, then ignore the
// last part of the namespace.
const parts = namespaceOrPath.split(':');
const maybePath = _.last(parts);
if (parts.length > 1 && /[/\\]/.test(maybePath)) {
parts.pop();
Environment.prototype.getGeneratorsMeta = function getGeneratorsMeta() {
return this.store.getGeneratorsMeta();
};
// We also want to remove the drive letter on windows
if (maybePath.indexOf('\\') >= 0 && _.last(parts).length === 1) {
parts.pop();
}
/**
* Get registered generators names
*
* @return {Array}
*/
namespace = parts.join(':');
}
Environment.prototype.getGeneratorNames = function getGeneratorNames() {
return _.uniq(Object.keys(this.getGeneratorsMeta()).map(Environment.namespaceToName));
};
/**
* Get a single generator from the registered list of generators. The lookup is
* based on generator's namespace, "walking up" the namespaces until a matching
* is found. Eg. if an `angular:common` namespace is registered, and we try to
* get `angular:common:all` then we get `angular:common` as a fallback (unless
* an `angular:common:all` generator is registered).
*
* @param {String} namespaceOrPath
* @return {Generator|null} - the generator registered under the namespace
*/
Environment.prototype.get = function get(namespaceOrPath) {
// Stop the recursive search if nothing is left
if (!namespaceOrPath) {
return;
return this.store.get(namespace) ||
this.store.get(this.alias(namespace)) ||
// Namespace is empty if namespaceOrPath contains a win32 absolute path of the form 'C:\path\to\generator'.
// for this reason we pass namespaceOrPath to the getByPath function.
this.getByPath(namespaceOrPath);
}
var namespace = namespaceOrPath;
/**
* Get a generator by path instead of namespace.
* @param {String} path
* @return {Generator|null} - the generator found at the location
*/
getByPath(path) {
if (fs.existsSync(path)) {
const namespace = this.namespace(path);
this.register(path, namespace);
// Legacy yeoman-generator `#hookFor()` function is passing the generator path as part
// of the namespace. If we find a path delimiter in the namespace, then ignore the
// last part of the namespace.
var parts = namespaceOrPath.split(':');
var maybePath = _.last(parts);
if (parts.length > 1 && /[\/\\]/.test(maybePath)) {
parts.pop();
// We also want to remove the drive letter on windows
if (maybePath.indexOf('\\') >= 0 && _.last(parts).length === 1) {
parts.pop();
return this.get(namespace);
}
namespace = parts.join(':');
}
return this.store.get(namespace) ||
this.store.get(this.alias(namespace)) ||
// namespace is empty if namespaceOrPath contains a win32 absolute path of the form 'C:\path\to\generator'.
// for this reason we pass namespaceOrPath to the getByPath function.
this.getByPath(namespaceOrPath);
};
/**
* Create is the Generator factory. It takes a namespace to lookup and optional
* hash of options, that lets you define `arguments` and `options` to
* instantiate the generator with.
*
* An error is raised on invalid namespace.
*
* @param {String} namespace
* @param {Object} options
*/
create(namespace, options) {
options = options || {};
/**
* Get a generator by path instead of namespace.
* @param {String} path
* @return {Generator|null} - the generator found at the location
*/
Environment.prototype.getByPath = function (path) {
if (fs.existsSync(path)) {
var namespace = this.namespace(path);
this.register(path, namespace);
const Generator = this.get(namespace);
return this.get(namespace);
}
};
if (typeof Generator !== 'function') {
let generatorHint = '';
if (isScoped(namespace)) {
const splitName = namespace.split('/');
generatorHint = `${splitName[0]}/generator-${splitName[1]}`;
} else {
generatorHint = `generator-${namespace}`;
}
/**
* Create is the Generator factory. It takes a namespace to lookup and optional
* hash of options, that lets you define `arguments` and `options` to
* instantiate the generator with.
*
* An error is raised on invalid namespace.
*
* @param {String} namespace
* @param {Object} options
*/
return this.error(
new Error(
chalk.red('You don\'t seem to have a generator with the name “' + namespace + '” installed.') + '\n' +
'But help is on the way:\n\n' +
'You can see available generators via ' +
chalk.yellow('npm search yeoman-generator') + ' or via ' + chalk.yellow('http://yeoman.io/generators/') + '. \n' +
'Install them with ' + chalk.yellow(`npm install ${generatorHint}`) + '.\n\n' +
'To see all your installed generators run ' + chalk.yellow('yo') + ' without any arguments. ' +
'Adding the ' + chalk.yellow('--help') + ' option will also show subgenerators. \n\n' +
'If ' + chalk.yellow('yo') + ' cannot find the generator, run ' + chalk.yellow('yo doctor') + ' to troubleshoot your system.'
)
);
}
Environment.prototype.create = function create(namespace, options) {
options = options || {};
var Generator = this.get(namespace);
if (!_.isFunction(Generator)) {
return this.error(
new Error(
chalk.red('You don\’t seem to have a generator with the name “' + namespace + '” installed.') + '\n' +
'But help is on the way:\n\n' +
'You can see available generators via ' +
chalk.yellow('npm search yeoman-generator') + ' or via ' + chalk.yellow('http://yeoman.io/generators/') + '. \n' +
'Install them with ' + chalk.yellow('npm install generator-' + namespace) + '.\n\n' +
'To see all your installed generators run ' + chalk.yellow('yo') + ' without any arguments. ' +
'Adding the ' + chalk.yellow('--help') + ' option will also show subgenerators. \n\n' +
'If ' + chalk.yellow('yo') + ' cannot find the generator, run ' + chalk.yellow('yo doctor') + ' to troubleshoot your system.'
)
);
return this.instantiate(Generator, options);
}
return this.instantiate(Generator, options);
};
/**
* Instantiate a Generator with metadatas
*
* @param {String} namespace
* @param {Object} options
* @param {Array|String} options.arguments Arguments to pass the instance
* @param {Object} options.options Options to pass the instance
*/
instantiate(Generator, options) {
options = options || {};
/**
* Instantiate a Generator with metadatas
*
* @param {String} namespace
* @param {Object} options
* @param {Array|String} options.arguments Arguments to pass the instance
* @param {Object} options.options Options to pass the instance
*/
let args = options.arguments || options.args || _.clone(this.arguments);
args = Array.isArray(args) ? args : args.split(' ');
Environment.prototype.instantiate = function instantiate(Generator, options) {
options = options || {};
const opts = options.options || _.clone(this.options);
var args = options.arguments || options.args || _.clone(this.arguments);
args = Array.isArray(args) ? args : args.split(' ');
var opts = options.options || _.clone(this.options);
opts.env = this;
opts.resolved = Generator.resolved || 'unknown';
opts.namespace = Generator.namespace;
return new Generator(args, opts);
};
/**
* Tries to locate and run a specific generator. The lookup is done depending
* on the provided arguments, options and the list of registered generators.
*
* When the environment was unable to resolve a generator, an error is raised.
*
* @param {String|Array} args
* @param {Object} options
* @param {Function} done
*/
Environment.prototype.run = function run(args, options, done) {
args = args || this.arguments;
if (typeof options === 'function') {
done = options;
options = this.options;
opts.env = this;
opts.resolved = Generator.resolved || 'unknown';
opts.namespace = Generator.namespace;
return new Generator(args, opts);
}
if (typeof args === 'function') {
done = args;
options = this.options;
args = this.arguments;
}
/**
* Tries to locate and run a specific generator. The lookup is done depending
* on the provided arguments, options and the list of registered generators.
*
* When the environment was unable to resolve a generator, an error is raised.
*
* @param {String|Array} args
* @param {Object} options
* @param {Function} done
*/
run(args, options, done) {
args = args || this.arguments;
args = Array.isArray(args) ? args : args.split(' ');
options = options || this.options;
if (typeof options === 'function') {
done = options;
options = this.options;
}
var name = args.shift();
if (!name) {
return this.error(new Error('Must provide at least one argument, the generator namespace to invoke.'));
}
if (typeof args === 'function') {
done = args;
options = this.options;
args = this.arguments;
}
var generator = this.create(name, {
args: args,
options: options
});
args = Array.isArray(args) ? args : args.split(' ');
options = options || this.options;
if (generator instanceof Error) {
return generator;
}
const name = args.shift();
if (!name) {
return this.error(new Error('Must provide at least one argument, the generator namespace to invoke.'));
}
if (options.help) {
return console.log(generator.help());
}
const generator = this.create(name, {
args,
options
});
return generator.run(done);
};
if (generator instanceof Error) {
return generator;
}
/**
* Given a String `filepath`, tries to figure out the relative namespace.
*
* ### Examples:
*
* this.namespace('backbone/all/index.js');
* // => backbone:all
*
* this.namespace('generator-backbone/model');
* // => backbone:model
*
* this.namespace('backbone.js');
* // => backbone
*
* this.namespace('generator-mocha/backbone/model/index.js');
* // => mocha:backbone:model
*
* @param {String} filepath
*/
if (options.help) {
return console.log(generator.help());
}
Environment.prototype.namespace = function namespace(filepath) {
if (!filepath) {
throw new Error('Missing namespace');
return generator.run(done);
}
// cleanup extension and normalize path for differents OS
var ns = path.normalize(filepath.replace(new RegExp(escapeStrRe(path.extname(filepath)) + '$'), ''));
/**
* Given a String `filepath`, tries to figure out the relative namespace.
*
* ### Examples:
*
* this.namespace('backbone/all/index.js');
* // => backbone:all
*
* this.namespace('generator-backbone/model');
* // => backbone:model
*
* this.namespace('backbone.js');
* // => backbone
*
* this.namespace('generator-mocha/backbone/model/index.js');
* // => mocha:backbone:model
*
* @param {String} filepath
*/
namespace(filepath) {
if (!filepath) {
throw new Error('Missing namespace');
}
// Sort lookups by length so biggest are removed first
var lookups = _(this.lookups.concat(['..'])).map(path.normalize).sortBy('length').value().reverse();
// Cleanup extension and normalize path for differents OS
let ns = path.normalize(filepath.replace(new RegExp(escapeStrRe(path.extname(filepath)) + '$'), ''));
// if `ns` contains a lookup dir in its path, remove it.
ns = lookups.reduce(function (ns, lookup) {
// only match full directory (begin with leading slash or start of input, end with trailing slash)
lookup = new RegExp('(?:\\\\|/|^)' + escapeStrRe(lookup) + '(?=\\\\|/)', 'g');
return ns.replace(lookup, '');
}, ns);
// Sort lookups by length so biggest are removed first
const lookups = _(this.lookups.concat(['..'])).map(path.normalize).sortBy('length').value().reverse();
var folders = ns.split(path.sep);
var scope = _.findLast(folders, function (folder) {
return folder.indexOf('@') === 0;
});
// If `ns` contains a lookup dir in its path, remove it.
ns = lookups.reduce((ns, lookup) => {
// Only match full directory (begin with leading slash or start of input, end with trailing slash)
lookup = new RegExp(`(?:\\\\|/|^)${escapeStrRe(lookup)}(?=\\\\|/)`, 'g');
return ns.replace(lookup, '');
}, ns);
// cleanup `ns` from unwanted parts and then normalize slashes to `:`
ns = ns
.replace(/(.*generator-)/, '') // remove before `generator-`
.replace(/[\/\\](index|main)$/, '') // remove `/index` or `/main`
.replace(/^[\/\\]+/, '') // remove leading `/`
.replace(/[\/\\]+/g, ':'); // replace slashes by `:`
const folders = ns.split(path.sep);
const scope = _.findLast(folders, folder => folder.indexOf('@') === 0);
if (scope) {
ns = scope + '/' + ns;
}
// Cleanup `ns` from unwanted parts and then normalize slashes to `:`
ns = ns
.replace(/(.*generator-)/, '') // Remove before `generator-`
.replace(/[/\\](index|main)$/, '') // Remove `/index` or `/main`
.replace(/^[/\\]+/, '') // Remove leading `/`
.replace(/[/\\]+/g, ':'); // Replace slashes by `:`
debug('Resolve namespaces for %s: %s', filepath, ns);
if (scope) {
ns = `${scope}/${ns}`;
}
return ns;
};
debug('Resolve namespaces for %s: %s', filepath, ns);
/**
* Resolve a module path
* @param {String} moduleId - Filepath or module name
* @return {String} - The resolved path leading to the module
*/
Environment.prototype.resolveModulePath = function resolveModulePath(moduleId) {
if (moduleId[0] === '.') {
moduleId = path.resolve(moduleId);
return ns;
}
if (path.extname(moduleId) === '') {
moduleId += path.sep;
}
return require.resolve(untildify(moduleId));
};
/**
* Resolve a module path
* @param {String} moduleId - Filepath or module name
* @return {String} - The resolved path leading to the module
*/
resolveModulePath(moduleId) {
if (moduleId[0] === '.') {
moduleId = path.resolve(moduleId);
}
/**
* Make sure the Environment present expected methods if an old version is
* passed to a Generator.
* @param {Environment} env
* @return {Environment} The updated env
*/
if (path.extname(moduleId) === '') {
moduleId += path.sep;
}
Environment.enforceUpdate = function (env) {
if (!env.adapter) {
env.adapter = new TerminalAdapter();
return require.resolve(untildify(moduleId));
}
}
if (!env.runLoop) {
env.runLoop = new GroupedQueue([
'initializing',
'prompting',
'configuring',
'default',
'writing',
'conflicts',
'install',
'end'
]);
}
Object.assign(Environment.prototype, resolver);
if (!env.sharedFs) {
env.sharedFs = memFs.create();
}
return env;
};
/**
* Factory method to create an environment instance. Take same parameters as the
* Environment constructor.
*
* @see This method take the same arguments as {@link Environment} constructor
*
* @return {Environment} a new Environment instance
*/
Environment.createEnv = function (args, opts, adapter) {
return new Environment(args, opts, adapter);
};
/**
* Convert a generators namespace to its name
*
* @param {String} namespace
* @return {String}
*/
Environment.namespaceToName = function (namespace) {
return namespace.split(':')[0];
};
/**
* Expose the utilities on the module
* @see {@link env/util}
*/
Environment.util = require('./util/util');
Environment.util = require('./util/util');
module.exports = Environment;
'use strict';
var path = require('path');
var fs = require('fs');
var _ = require('lodash');
var globby = require('globby');
var debug = require('debug')('yeoman:environment');
const path = require('path');
const fs = require('fs');
const _ = require('lodash');
const globby = require('globby');
const debug = require('debug')('yeoman:environment');
var win32 = process.platform === 'win32';
const win32 = process.platform === 'win32';

@@ -14,3 +14,3 @@ /**

*/
var resolver = module.exports;
const resolver = module.exports;

@@ -33,20 +33,19 @@ /**

*/
resolver.lookup = function (cb) {
var generatorsModules = this.findGeneratorsIn(this.getNpmPaths());
var patterns = [];
const generatorsModules = this.findGeneratorsIn(this.getNpmPaths());
const patterns = [];
this.lookups.forEach(function (lookup) {
generatorsModules.forEach(function (modulePath) {
for (const lookup of this.lookups) {
for (const modulePath of generatorsModules) {
patterns.push(path.join(modulePath, lookup));
});
});
}
}
patterns.forEach(function (pattern) {
globby.sync('*/index.js', { cwd: pattern }).forEach(function (filename) {
for (const pattern of patterns) {
for (const filename of globby.sync('*/index.js', {cwd: pattern})) {
this._tryRegistering(path.join(pattern, filename));
}, this);
}, this);
}
}
if (_.isFunction(cb)) {
if (typeof cb === 'function') {
return cb(null);

@@ -64,7 +63,6 @@ }

*/
resolver.findGeneratorsIn = function (searchPaths) {
var modules = [];
let modules = [];
searchPaths.forEach(function (root) {
for (const root of searchPaths) {
if (!root) {

@@ -77,6 +75,6 @@ return;

'@*/generator-*'
], { cwd: root }).map(function (match) {
return path.join(root, match);
}).concat(modules);
});
], {cwd: root})
.map(match => path.join(root, match))
.concat(modules);
}

@@ -91,6 +89,5 @@ return modules;

*/
resolver._tryRegistering = function (generatorReference) {
var namespace;
var realPath = fs.realpathSync(generatorReference);
let namespace;
const realPath = fs.realpathSync(generatorReference);

@@ -105,4 +102,4 @@ try {

this.register(realPath, namespace);
} catch (e) {
console.error('Unable to register %s (Error: %s)', generatorReference, e.message);
} catch (err) {
console.error('Unable to register %s (Error: %s)', generatorReference, err.message);
}

@@ -116,3 +113,3 @@ };

resolver.getNpmPaths = function () {
var paths = [];
let paths = [];

@@ -136,3 +133,3 @@ // Add NVM prefix directory

// adds support for generator resolving when yeoman-generator has been linked
// Adds support for generator resolving when yeoman-generator has been linked
if (process.argv[1]) {

@@ -151,7 +148,7 @@ paths.push(path.join(path.dirname(process.argv[1]), '../..'));

// Walk up the CWD and add `node_modules/` folder lookup on each level
process.cwd().split(path.sep).forEach(function (part, i, parts) {
var lookup = path.join.apply(path, parts.slice(0, i + 1).concat(['node_modules']));
process.cwd().split(path.sep).forEach((part, i, parts) => {
let lookup = path.join.apply(path, parts.slice(0, i + 1).concat(['node_modules']));
if (!win32) {
lookup = '/' + lookup;
lookup = `/${lookup}`;
}

@@ -194,8 +191,7 @@

*/
resolver.alias = function alias(match, value) {
resolver.alias = function (match, value) {
if (match && value) {
this.aliases.push({
match: match instanceof RegExp ? match : new RegExp('^' + match + '$'),
value: value
match: match instanceof RegExp ? match : new RegExp(`^${match}$`),
value
});

@@ -205,5 +201,5 @@ return this;

var aliases = this.aliases.slice(0).reverse();
const aliases = this.aliases.slice(0).reverse();
return aliases.reduce(function (res, alias) {
return aliases.reduce((res, alias) => {
if (!alias.match.test(res)) {

@@ -210,0 +206,0 @@ return res;

'use strict';
var _ = require('lodash');

@@ -11,80 +10,79 @@ /**

*/
class Store {
constructor() {
this._generators = {};
this._meta = {};
}
var Store = module.exports = function Store() {
this._generators = {};
this._meta = {};
};
/**
* Store a module under the namespace key
* @param {String} namespace - The key under which the generator can be retrieved
* @param {String|Function} generator - A generator module or a module path
*/
add(namespace, generator) {
if (typeof generator === 'string') {
this._storeAsPath(namespace, generator);
return;
}
/**
* Store a module under the namespace key
* @param {String} namespace - The key under which the generator can be retrieved
* @param {String|Function} generator - A generator module or a module path
*/
Store.prototype.add = function add(namespace, generator) {
if (_.isString(generator)) {
this._storeAsPath(namespace, generator);
return;
this._storeAsModule(namespace, generator);
}
this._storeAsModule(namespace, generator);
};
_storeAsPath(namespace, path) {
this._meta[namespace] = {
resolved: path,
namespace
};
Store.prototype._storeAsPath = function _storeAsPath(namespace, path) {
this._meta[namespace] = {
resolved: path,
namespace: namespace
};
Object.defineProperty(this._generators, namespace, {
get() {
const Generator = require(path);
return Generator;
},
enumerable: true,
configurable: true
});
}
Object.defineProperty(this._generators, namespace, {
get: function () {
var Generator = require(path);
return Generator;
},
enumerable: true,
configurable: true
});
};
_storeAsModule(namespace, Generator) {
this._meta[namespace] = {
resolved: 'unknown',
namespace
};
Store.prototype._storeAsModule = function _storeAsModule(namespace, Generator) {
this._meta[namespace] = {
resolved: 'unknown',
namespace: namespace
};
this._generators[namespace] = Generator;
}
this._generators[namespace] = Generator;
};
/**
* Get the module registered under the given namespace
* @param {String} namespace
* @return {Module}
*/
get(namespace) {
const Generator = this._generators[namespace];
/**
* Get the module registered under the given namespace
* @param {String} namespace
* @return {Module}
*/
if (!Generator) {
return;
}
Store.prototype.get = function get(namespace) {
var Generator = this._generators[namespace];
return Object.assign(Generator, this._meta[namespace]);
}
if (!Generator) {
return;
/**
* Returns the list of registered namespace.
* @return {Array} Namespaces array
*/
namespaces() {
return Object.keys(this._generators);
}
return _.extend(Generator, this._meta[namespace]);
};
/**
* Get the stored generators meta data
* @return {Object} Generators metadata
*/
getGeneratorsMeta() {
return this._meta;
}
}
/**
* Returns the list of registered namespace.
* @return {Array} Namespaces array
*/
Store.prototype.namespaces = function namespaces() {
return Object.keys(this._generators);
};
/**
* Get the stored generators meta data
* @return {Object} Generators metadata
*/
Store.prototype.getGeneratorsMeta = function getGeneratorsMeta() {
return this._meta;
};
module.exports = Store;
/** @module env/log */
'use strict';
const util = require('util');
const EventEmitter = require('events');
const _ = require('lodash');
const table = require('text-table');
const chalk = require('chalk');
const logSymbols = require('log-symbols');
var util = require('util');
var events = require('events');
var _ = require('lodash');
var table = require('text-table');
var chalk = require('chalk');
var logSymbols = require('log-symbols');
// Padding step
const step = ' ';
let padding = ' ';
// padding step
var step = ' ';
var padding = ' ';
// color -> status mappings
var colors = {
// Color -> status mappings
const colors = {
skip: 'yellow',

@@ -27,12 +26,12 @@ force: 'yellow',

function pad(status) {
var max = 'identical'.length;
var delta = max - status.length;
return delta ? new Array(delta + 1).join(' ') + status : status;
const max = 'identical'.length;
const delta = max - status.length;
return delta ? ' '.repeat(delta) + status : status;
}
// borrowed from https://github.com/mikeal/logref/blob/master/main.js#L6-15
// Borrowed from https://github.com/mikeal/logref/blob/master/main.js#L6-15
function formatter(msg, ctx) {
while (msg.indexOf('%') !== -1) {
var start = msg.indexOf('%');
var end = msg.indexOf(' ', start);
const start = msg.indexOf('%');
let end = msg.indexOf(' ', start);

@@ -49,3 +48,3 @@ if (end === -1) {

module.exports = function logger() {
module.exports = () => {
// `this.log` is a [logref](https://github.com/mikeal/logref)

@@ -80,3 +79,3 @@ // compatible logger, with an enhanced API.

_.extend(log, events.EventEmitter.prototype);
_.extend(log, EventEmitter.prototype);

@@ -111,11 +110,13 @@ // A simple write method, with formatted message.

log.on('up', function () {
padding = padding + step;
log.on('up', () => {
padding += step;
});
log.on('down', function () {
log.on('down', () => {
padding = padding.replace(step, '');
});
Object.keys(colors).forEach(function (status) {
/* eslint-disable no-loop-func */
// TODO: Fix this ESLint warning
for (const status of Object.keys(colors)) {
// Each predefined status has its logging method utility, handling

@@ -146,3 +147,3 @@ // status color and padding before the usual `.write()`

log[status] = function () {
var color = colors[status];
const color = colors[status];
this.write(chalk[color](pad(status))).write(padding);

@@ -152,3 +153,4 @@ this.write(util.format.apply(util, arguments) + '\n');

};
});
}
/* eslint-enable no-loop-func */

@@ -163,11 +165,11 @@ // A basic wrapper around `cli-table` package, resetting any single

// Returns the table reprensetation
log.table = function (opts) {
var tableData = [];
log.table = opts => {
const tableData = [];
opts = Array.isArray(opts) ? { rows: opts } : opts;
opts = Array.isArray(opts) ? {rows: opts} : opts;
opts.rows = opts.rows || [];
opts.rows.forEach(function (row) {
for (const row of opts.rows) {
tableData.push(row);
});
}

@@ -174,0 +176,0 @@ return table(tableData);

/** @module env/util */
'use strict';
const GroupedQueue = require('grouped-queue');
var GroupedQueue = require('grouped-queue');
/**

@@ -16,7 +15,6 @@ * Create a "sloppy" copy of an initial Environment object. The focus of this method is on

*/
exports.duplicateEnv = function (initialEnv) {
var queues = require('../environment').queues;
// Hack: create a clone of the environment with a new instance of runLoop
var env = Object.create(initialEnv);
exports.duplicateEnv = initialEnv => {
const queues = require('../environment').queues;
// Hack: Create a clone of the environment with a new instance of `runLoop`
const env = Object.create(initialEnv);
env.runLoop = new GroupedQueue(queues);

@@ -23,0 +21,0 @@ return env;

{
"name": "yeoman-environment",
"version": "1.6.6",
"version": "2.0.0",
"description": "Handles the lifecyle and bootstrapping of generators in a specific environment",

@@ -27,3 +27,3 @@ "homepage": "http://yeoman.io",

"scripts": {
"test": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js",
"test": "xo && gulp",
"doc": "jsdoc -c ./jsdoc.json ./readme.md",

@@ -36,7 +36,8 @@ "benchmark": "matcha benchmark/**",

"debug": "^2.0.0",
"diff": "^2.1.2",
"diff": "^3.2.0",
"escape-string-regexp": "^1.0.2",
"globby": "^4.0.0",
"globby": "^6.1.0",
"grouped-queue": "^0.3.0",
"inquirer": "^1.0.2",
"inquirer": "^3.0.1",
"is-scoped": "^1.0.0",
"lodash": "^4.11.1",

@@ -46,3 +47,3 @@ "log-symbols": "^1.0.1",

"text-table": "^0.2.0",
"untildify": "^2.0.0"
"untildify": "^3.0.2"
},

@@ -53,7 +54,4 @@ "devDependencies": {

"gulp-coveralls": "^0.1.0",
"gulp-eslint": "^2.0.0",
"gulp-exclude-gitignore": "^1.0.0",
"gulp-istanbul": "^0.10.3",
"gulp-jscs": "^3.0.0",
"gulp-mocha": "^2.0.0",
"gulp-istanbul": "^1.1.1",
"gulp-mocha": "^3.0.1",
"gulp-nsp": "^2.1.0",

@@ -64,8 +62,20 @@ "gulp-plumber": "^1.0.0",

"matcha": "^0.7.0",
"mocha": "^2.3.4",
"mocha": "^3.2.0",
"shelljs": "^0.7.0",
"sinon": "^1.9.1",
"yeoman-assert": "^2.1.1",
"yeoman-generator": "^0.22.1"
"sinon": "^2.1.0",
"sinon-test": "^1.0.1",
"xo": "^0.18.1",
"yeoman-assert": "^3.0.0",
"yeoman-generator": "^1.1.0"
},
"xo": {
"space": true,
"envs": [
"node",
"mocha"
],
"rules": {
"import/no-dynamic-require": "off"
}
}
}

@@ -9,2 +9,3 @@ # Yeoman Environment

## Install

@@ -19,12 +20,12 @@

Full documentation available at http://yeoman.io/authoring/integrating-yeoman.html
Full documentation available [here](http://yeoman.io/authoring/integrating-yeoman.html).
```js
var yeoman = require('yeoman-environment');
var env = yeoman.createEnv();
const yeoman = require('yeoman-environment');
const env = yeoman.createEnv();
// The #lookup() method will search the user computer for installed generators.
// The search if done from the current working directory.
env.lookup(function () {
env.run('angular', {'skip-install': true}, function (err) {
// The #lookup() method will search the user computer for installed generators
// The search if done from the current working directory
env.lookup(() => {
env.run('angular', {'skip-install': true}, err => {
console.log('done');

@@ -40,2 +41,2 @@ });

BSD © Yeoman
BSD-2-Clause © Yeoman
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc