Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,12 @@ async function init() {
return;
}

runYo(env).catch(error => onError(error));
try {
await runYo(env);
} catch (error) {
onError(error);
}

return;
}

Expand All @@ -152,7 +157,11 @@ async function init() {
console.log(chalk.red('Installed generators don\'t need the "generator-" prefix.'));
console.log(`In the future, run ${generatorCommand} instead!\n`);

await env.run(generatorName, firstCmd.opts).catch(error => onError(error));
try {
await env.run(generatorName, firstCmd.opts);
} catch (error) {
onError(error);
}

return;
}
Expand All @@ -161,8 +170,12 @@ async function init() {
// one that will be triggered by the below args. Maybe the nopt parsing
// should be done internally, from the args.
for (const generator of cli) {
// eslint-disable-next-line no-await-in-loop
await env.run(generator.args, generator.opts).catch(error => onError(error));
try {
// eslint-disable-next-line no-await-in-loop
await env.run(generator.args, generator.opts);
} catch (error) {
onError(error);
}
}
}

Expand Down
7 changes: 4 additions & 3 deletions lib/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ export default class Router {
* Navigate to a route
* @param {String} name Route name
* @param {*} arg A single argument to pass to the route handler
* @return {Promise} Promise this.
* @return {Promise<this>}
*/
navigate(name, argument) {
async navigate(name, argument) {
if (typeof this.routes[name] === 'function') {
return this.routes[name].call(null, this, argument).then(() => this);
await this.routes[name].call(null, this, argument);
return this;
}

throw new Error(`No routes called: ${name}`);
Expand Down
14 changes: 7 additions & 7 deletions lib/routes/clear-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,21 @@ export const clearConfig = async app => {
});
}

return app.adapter.prompt([{
const answer = await app.adapter.prompt([{
name: 'whatNext',
type: 'list',
message: 'Which store would you like to clear?',
choices: [
generatorList,
defaultChoices,
].flat(),
}]).then(answer => {
if (answer.whatNext === 'home') {
return app.navigate('home');
}
}]);

if (answer.whatNext === 'home') {
return app.navigate('home');
}

_clearGeneratorConfig(app, answer.whatNext);
});
_clearGeneratorConfig(app, answer.whatNext);
};

/**
Expand Down
42 changes: 22 additions & 20 deletions lib/routes/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,30 @@ import open from 'open';
* @param {import('../router.js').default} app
* @returns
*/
export const help = async app => app.adapter.prompt([{
name: 'whereTo',
type: 'list',
message: 'Here are a few helpful resources.\n\nI will open the link you select in your browser for you',
choices: [{
name: 'Take me to the documentation',
value: 'http://yeoman.io/learning/',
}, {
name: 'View Frequently Asked Questions',
value: 'http://yeoman.io/learning/faq.html',
}, {
name: 'File an issue on GitHub',
value: 'http://yeoman.io/contributing/opening-issues.html',
}, {
name: 'Take me back home, Yo!',
value: 'home',
}],
}]).then(async answer => {
export const help = async app => {
const answer = await app.adapter.prompt([{
name: 'whereTo',
type: 'list',
message: 'Here are a few helpful resources.\n\nI will open the link you select in your browser for you',
choices: [{
name: 'Take me to the documentation',
value: 'http://yeoman.io/learning/',
}, {
name: 'View Frequently Asked Questions',
value: 'http://yeoman.io/learning/faq.html',
}, {
name: 'File an issue on GitHub',
value: 'http://yeoman.io/contributing/opening-issues.html',
}, {
name: 'Take me back home, Yo!',
value: 'home',
}],
}]);

if (answer.whereTo === 'home') {
console.log('I get it, you like learning on your own. I respect that.');
return app.navigate('home');
}

open(answer.whereTo);
});
return open(answer.whereTo);
};
45 changes: 22 additions & 23 deletions lib/routes/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,30 +53,29 @@ export const home = async app => {
});
}

return fullname().then(name => {
const allo = (name && _.isString(name)) ? `'Allo ${name.split(' ')[0]}! ` : '\'Allo! ';
const name = await fullname();
const allo = (name && _.isString(name)) ? `'Allo ${name.split(' ')[0]}! ` : '\'Allo! ';

return app.adapter.prompt([{
name: 'whatNext',
type: 'list',
message: `${allo}What would you like to do?`,
choices: [
app.adapter.separator?.('Run a generator'),
generatorList,
app.adapter.separator?.(),
defaultChoices,
app.adapter.separator?.(),
].flat(),
}]).then(answer => {
if (answer.whatNext.method === 'run') {
return app.navigate('run', answer.whatNext.generator);
}
const answer = await app.adapter.prompt([{
name: 'whatNext',
type: 'list',
message: `${allo}What would you like to do?`,
choices: [
app.adapter.separator?.('Run a generator'),
generatorList,
app.adapter.separator?.(),
defaultChoices,
app.adapter.separator?.(),
].flat(),
}]);

if (answer.whatNext === 'exit') {
return;
}
if (answer.whatNext.method === 'run') {
return app.navigate('run', answer.whatNext.generator);
}

return app.navigate(answer.whatNext);
});
});
if (answer.whatNext === 'exit') {
return;
}

return app.navigate(answer.whatNext);
};
26 changes: 15 additions & 11 deletions lib/routes/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,14 @@ const OFFICIAL_GENERATORS = new Set([
* @param {import('../router.js').default} app
* @returns
*/
export const install = app => app.adapter.prompt([{
name: 'searchTerm',
message: 'Search npm for generators:',
}]).then(answers => searchNpm(app, answers.searchTerm));
export const install = async app => {
const answers = await app.adapter.prompt([{
name: 'searchTerm',
message: 'Search npm for generators:',
}]);

return searchNpm(app, answers.searchTerm);
};

const generatorMatchTerm = (generator, term) => `${generator.name} ${generator.description}`.includes(term);
const getAllGenerators = _.memoize(() => npmKeyword('yeoman-generator'));
Expand Down Expand Up @@ -79,7 +83,7 @@ async function searchNpm(app, term) {
* @param {import('../router.js').default} app
* @returns
*/
function promptInstallOptions(app, choices) {
async function promptInstallOptions(app, choices) {
let introMessage = 'Sorry, no results matches your search term';

if (choices.length > 0) {
Expand All @@ -99,13 +103,13 @@ function promptInstallOptions(app, choices) {
}],
}];

return app.adapter.prompt(resultsPrompt).then(answer => {
if (answer.toInstall === 'home' || answer.toInstall === 'install') {
return app.navigate(answer.toInstall);
}
const answer = await app.adapter.prompt(resultsPrompt);

installGenerator(app, answer.toInstall);
});
if (answer.toInstall === 'home' || answer.toInstall === 'install') {
return app.navigate(answer.toInstall);
}

installGenerator(app, answer.toInstall);
}

function installGenerator(app, packageName) {
Expand Down
29 changes: 15 additions & 14 deletions lib/routes/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,20 @@ function updateGenerators(app, pkgs) {

/**
* @param {import('../router.js').default} app
* @returns
*/
export const update = app => app.adapter.prompt([{
name: 'generators',
message: 'Generators to update',
type: 'checkbox',
validate(input) {
return input.length > 0 ? true : 'Please select at least one generator to update.';
},
choices: Object.keys(app.generators || {}).map(key => ({
name: app.generators[key].name,
checked: true,
})),
}]).then(answer => {
export const update = async app => {
const answer = await app.adapter.prompt([{
name: 'generators',
message: 'Generators to update',
type: 'checkbox',
validate(input) {
return input.length > 0 ? true : 'Please select at least one generator to update.';
},
choices: Object.keys(app.generators || {}).map(key => ({
name: app.generators[key].name,
checked: true,
})),
}]);

updateGenerators(app, answer.generators);
});
};
5 changes: 4 additions & 1 deletion test/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ describe('Router', () => {
});

it('throws on invalid route name', function () {
assert.throws(this.router.navigate.bind(this.route, 'invalid route name'));
assert.rejects(
this.router.navigate.bind(this.router, 'invalid route name'),
'No routes called: invalid route name',
);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example failure of this test on
https://github.com/yeoman/yo/actions/runs/19107048177/job/54593675005?pr=918:

  1) Router
       #navigate()
         throws on invalid route name:
     AssertionError [ERR_ASSERTION]: Missing expected exception.
      at Context.<anonymous> (file:///Users/runner/work/yo/yo/test/router.js:59:14)

Two existing problems with the test:

  • It's this.router, not this.route
  • The function returns a Promise, so the test should be testing what it rejects, not throws

Previously it was synchronously throwing an error because this was undefined (yay, JavaScript quirks!). Switching from synchronous Promise creation to async changes the code to all be asynchronous. Now it asynchronously rejects (throws) the No routes called: ${name}.

});
});

Expand Down
Loading