Skip to content

Commit

Permalink
Merge branch 'master' into resolve
Browse files Browse the repository at this point in the history
  • Loading branch information
mshima committed Jan 24, 2020
2 parents 1490b12 + f28df18 commit 4d94cd4
Show file tree
Hide file tree
Showing 13 changed files with 1,865 additions and 2,807 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/stale.yml
Expand Up @@ -11,7 +11,7 @@ jobs:
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 15 days with no activity. Remove stale label or comment or this will be closed in 5 days'
days-before-stale: 15
days-before-close: 5
days-before-stale: 45
days-before-close: 15
stale-issue-label: 'stale'
exempt-issue-label: 'in progress'
exempt-issue-label: 'not stale'
94 changes: 66 additions & 28 deletions lib/environment.js
Expand Up @@ -101,16 +101,7 @@ class Environment extends EventEmitter {
}

if (!env.runLoop) {
env.runLoop = new GroupedQueue([
'initializing',
'prompting',
'configuring',
'default',
'writing',
'conflicts',
'install',
'end'
]);
env.runLoop = new GroupedQueue(Environment.queues);
}

if (!env.sharedFs) {
Expand Down Expand Up @@ -147,28 +138,52 @@ class Environment extends EventEmitter {
*
* @param {String|Array} namespaces
* @param {Object} [options]
* @param {Boolean|Object} [options.localOnly=false] - Set true to skip lookups of
* @param {Boolean} [options.localOnly=false] - Set true to skip lookups of
* globally-installed generators.
* @param {Boolean|Object} [options.packagePath=false] - Set true to return the package
* @param {Boolean} [options.packagePath=false] - Set true to return the package
* path instead of generators file.
* @param {boolean} [options.singleResult=true] - Set false to return all occurrences.
* @param {Boolean} [options.singleResult=true] - Set false to return multiple values.
* @return {String} generator
*/
static lookupGenerator(namespaces, options = {}) {
// Multiple was renamed to !singleResult
options = {singleResult: !options.multiple, ...options, skipRegister: true, namespaces, packageNamespace: options.packagePath};
debug('Performing lookupGenerator with %o', options);

const modules = resolver.lookup(options);
if (modules.length === 0) {
return undefined;
static lookupGenerator(namespace, options = {singleResult: true}) {
if (typeof options === 'boolean') {
options = {singleResult: true, localOnly: options};
} else {
// Keep compatibility with options.multiple
options = {singleResult: !options.multiple, ...options};
}

options.filePatterns = options.filePatterns || '*/index.js';

const name = Environment.namespaceToName(namespace);
options.packagePatterns = options.packagePatterns || getGeneratorHint(name);
const envProt = Environment.prototype;

const npmPaths = options.npmPaths || envProt.getNpmPaths(options.localOnly).reverse();
const generatorsModules = envProt.findGeneratorsIn(npmPaths, options);

const paths = [];
for (const modulePath of generatorsModules) {
for (const lookup of Environment.lookups) {
const pattern = path.join(modulePath, lookup);
for (const filename of globby.sync(options.filePatterns, {cwd: pattern, absolute: true, deep: 1})) {
const fileNS = envProt.namespace(filename, Environment.lookups);
if (namespace === fileNS || (options.packagePath && namespace === Environment.namespaceToName(fileNS))) {
// Version 2.6.0 returned pattern instead of modulePath for options.packagePath
const path = options.packagePath ? modulePath : options.generatorPath ? pattern : filename;
if (options.singleResult) {
return path;
}
paths.push(path);
}
}
}
}

const getPath = module => options.packagePath ? module.packagePath : options.generatorPath ? module.generatorPath : module.generator;
if (options.singleResult) {
return getPath(modules[0]);
if (!options.singleResult) {
return paths;
}
return modules.map(getPath);
return undefined;
}

constructor(args, opts, adapter) {
Expand Down Expand Up @@ -284,11 +299,13 @@ class Environment extends EventEmitter {
}

this.store.add(namespace, modulePath, undefined, packagePath);
const packageNS = Environment.namespaceToName(namespace);
this.store.addPackageNS(packageNS);
if (packagePath) {
this.store.addPackage(Environment.namespaceToName(namespace), packagePath);
this.store.addPackage(packageNS, packagePath);
}

debug('Registered %s (%s) on package (%s)', namespace, modulePath, packagePath);
debug('Registered %s (%s) on package %s (%s)', namespace, modulePath, packageNS, packagePath);
return this;
}

Expand All @@ -313,8 +330,10 @@ class Environment extends EventEmitter {
}

this.store.add(namespace, Generator, resolved, packagePath);
const packageNS = Environment.namespaceToName(namespace);
this.store.addPackageNS(packageNS);
if (packagePath) {
this.store.addPackage(Environment.namespaceToName(namespace), packagePath);
this.store.addPackage(packageNS, packagePath);
}

debug('Registered %s (%s) on package (%s)', namespace, resolved, packagePath);
Expand Down Expand Up @@ -346,6 +365,25 @@ class Environment extends EventEmitter {
return _.uniq(Object.keys(this.getGeneratorsMeta()).map(Environment.namespaceToName));
}

/**
* Verify if a package namespace already have been registered.
*
* @param {String} [packageNS] - namespace of the package.
* @return {boolean} - true if any generator of the package has been registered
*/
isPackageRegistered(packageNS) {
return this.getRegisteredPackages().includes(packageNS);
}

/**
* Get all registered packages namespaces.
*
* @return {Array} - array of namespaces.
*/
getRegisteredPackages() {
return this.store.getPackagesNS();
}

/**
* Get last added path for a namespace
*
Expand Down
83 changes: 27 additions & 56 deletions lib/resolver.js
Expand Up @@ -42,13 +42,11 @@ Object.assign(resolver, {
* globally-installed generators.
* @param {boolean} [options.filterPaths = false] - Ignore paths that aren't a known repository
* (don't touch at NODE_PATH paths).
* @param {string|Array} [options.npmPaths] - Paths to look generators at.
* @param {Array} [options.packagePaths] - Paths to look for generators.
* @param {string|Array} [options.npmPaths] - Repository paths to look for generators packages.
* @param {string|Array} [options.filePatterns='*\/index.js'] - File pattern to look for.
* @param {string|Array} [options.packagePatterns='generator-*'] - Package pattern to look for.
* @param {string|Array} [options.namespaces] - Namespaces to look for.
* @param {string|Array} [options.pattern='generator-*'] - Alternative way to narrow down packages to look for. Ex 'generator-foo-*'.
* @param {string|Array} [options.filePattern='*\/index.js'] - Alternative way to narrow down generators to look for. Ex ['foo.js', 'bar.js'].
* @param {string|Array} [options.lookups=['.', 'generators', 'lib/generators']] - Alternative way to narrow down generators to look for..
* @param {boolean} [options.singlePackage=false] - If true don't consider npmPaths repository paths,
* It won't look for generators at npmPaths childs.
* @param {boolean} [options.skipRegister=false] - Don't try to register the generator into environment.
* @param {boolean} [options.singleResult=false] - Set true to return the first match ocurrence.
* @param {boolean} [options.packageNamespace=false] - Set true to do a package namespace lookup.
Expand All @@ -71,37 +69,18 @@ resolver.lookup = function (options = {localOnly: false}, cb) {
options.pattern = options.pattern || options.parsed.map(ns => ns.generatorHint);
}

options.filePattern = options.filePattern || '*/index.js';
debug('Performing lookup with %o', options);

const lookups = options.lookups || this.lookups || resolver.lookups;

let npmPaths = options.npmPaths || this.getNpmPaths(options).reverse();
npmPaths = Array.isArray(npmPaths) ? npmPaths : [npmPaths];
const generatorsModules = this.findGeneratorsIn(npmPaths, options);

let registeredAny = false;
const modules = [];
const self = this;
for (const modulePath of generatorsModules) {
for (const lookup of lookups) {
const pattern = path.join(modulePath, lookup);
for (const filename of globby.sync(options.filePattern, {cwd: pattern, absolute: true, deep: 1})) {
if (options.parsed) {
const namespace = fileToNamespace(filename, lookups);
const found = options.parsed.find(ns => ns.namespace === namespace || self.alias(ns.namespace) === namespace || (options.packageNamespace && requireNamespace(namespace).packageNamespace === ns.packageNamespace));
if (!found) {
continue;
}
}
modules.push({packagePath: modulePath, generatorPath: pattern, generator: filename});
if (!options.skipRegister) {
registeredAny = this._tryRegistering(filename, modulePath) || registeredAny;
}
if (options.singleResult) {
return modules;
}
}
options.filePatterns = options.filePatterns || this.lookups.map(prefix => path.join(prefix, '*/index.js'));

if (!Array.isArray(options.packagePaths)) {
options.npmPaths = options.npmPaths || this.getNpmPaths(options).reverse();
options.packagePaths = this.findGeneratorsIn(options.npmPaths, options);
}

debug('Running lookup with options %o', options);

for (const modulePath of options.packagePaths) {
for (const filename of globby.sync(options.filePatterns, {cwd: modulePath, absolute: true, deep: 1})) {
this._tryRegistering(filename, modulePath);
}
}

Expand All @@ -123,52 +102,44 @@ resolver.lookup = function (options = {localOnly: false}, cb) {
*
* @param {Array} List of search paths
* @param {Object} [options]
* @param {boolean} [options.singlePackage=false] - Don't look for generators at npmPaths childs.
* @param {boolean} [options.pattern='generator-*'] - Pattern for globby.
* @param {boolean} [options.packagePatterns='generator-*'] - Pattern pattern.
* @return {Array} List of the generator modules path
*/
resolver.findGeneratorsIn = function (searchPaths, options) {
let pattern;
if (typeof options === 'object') {
pattern = options.pattern;
} else {
pattern = options;
options = {};
resolver.findGeneratorsIn = function (searchPaths, options = {}) {
if (typeof options === 'string') {
options = {packagePatterns: options};
}

pattern = pattern || 'generator-*';
options.packagePatterns = options.packagePatterns || 'generator-*';

// Remove undefined values and convert paths to absolute
searchPaths = searchPaths.filter(npmPath => npmPath).map(npmPath => path.resolve(npmPath));

// Add if it is a generator.
// Add directly if it is a generator package dir.
let modules = searchPaths.filter(npmPath => /generator-.*/.test(path.basename(npmPath)));
if (options.singlePackage) {
return modules;
}

for (const root of searchPaths) {
// Some folders might not be readable to the current user. For those, we add a try
// catch to handle the error gracefully as globby doesn't have an option to skip
// restricted folders.
try {
modules = modules.concat(globby.sync(
pattern,
options.packagePatterns,
{cwd: root, onlyFiles: false, absolute: true, deep: 0}
));

// To limit recursive lookups into non-namespace folders within globby,
// fetch all namespaces in root, then search each namespace separately
// for generator modules
const namespaces = globby.sync(
const scopes = globby.sync(
['@*'],
{cwd: root, onlyFiles: false, absolute: true, deep: 0}
);

for (const namespace of namespaces) {
for (const scope of scopes) {
modules = modules.concat(globby.sync(
pattern,
{cwd: namespace, onlyFiles: false, absolute: true, deep: 0}
options.packagePatterns,
{cwd: scope, onlyFiles: false, absolute: true, deep: 0}
));
}
} catch (err) {
Expand Down
25 changes: 22 additions & 3 deletions lib/store.js
Expand Up @@ -15,6 +15,8 @@ class Store {
this._meta = {};
// Store packages paths by ns
this._packagesPaths = {};
// Store packages ns
this._packagesNS = [];
}

/**
Expand Down Expand Up @@ -93,9 +95,8 @@ class Store {

/**
* Store a package under the namespace key
* @param {String} namespace - The key under which the generator can be retrieved
* @param {String} path - The package path
* @param {String} [generatorNS] - Namespace of a generator to register.
* @param {String} packageNS - The key under which the generator can be retrieved
* @param {String} packagePath - The package path
*/
addPackage(packageNS, packagePath) {
if (this._packagesPaths[packageNS]) {
Expand Down Expand Up @@ -123,6 +124,24 @@ class Store {
getPackagesPaths() {
return this._packagesPaths;
}

/**
* Store a package ns
* @param {String} packageNS - The key under which the generator can be retrieved
*/
addPackageNS(packageNS) {
if (!this._packagesNS.includes(packageNS)) {
this._packagesNS.push(packageNS);
}
}

/**
* Get the stored packages namespaces.
* @return {Array} Stored packages namespaces.
*/
getPackagesNS() {
return this._packagesNS;
}
}

module.exports = Store;

0 comments on commit 4d94cd4

Please sign in to comment.