Skip to content

Commit

Permalink
feat: show multiple suggestions on unknown options (#2349)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed Jan 13, 2021
1 parent 3eabbbc commit 7314d6c
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 27 deletions.
21 changes: 0 additions & 21 deletions packages/webpack-cli/lib/utils/cli-flags.js
Expand Up @@ -23,30 +23,26 @@ const builtInFlags = [
// For configs
{
name: 'config',
usage: '--config <path-to-config> | --config <path-to-config> --config <path-to-config>',
alias: 'c',
type: String,
multiple: true,
description: 'Provide path to a webpack configuration file e.g. ./webpack.config.js.',
},
{
name: 'config-name',
usage: '--config-name <name-of-config> | --config-name <name-of-config> --config-name <name-of-config>',
type: String,
multiple: true,
description: 'Name of the configuration to use.',
},
{
name: 'merge',
usage: '--config <first-config> --config <second-config> --merge',
alias: 'm',
type: Boolean,
description: "Merge two or more configurations using 'webpack-merge'.",
},
// Complex configs
{
name: 'env',
usage: '--env <variable> | --env <variable> --env <variable=value>',
type: (value, previous = {}) => {
// This ensures we're only splitting by the first `=`
const [allKeys, val] = value.split(/=(.+)/, 2);
Expand Down Expand Up @@ -79,7 +75,6 @@ const builtInFlags = [
// Adding more plugins
{
name: 'hot',
usage: '--hot',
alias: 'h',
type: Boolean,
negative: true,
Expand All @@ -88,28 +83,24 @@ const builtInFlags = [
},
{
name: 'analyze',
usage: '--analyze',
type: Boolean,
multiple: false,
description: 'It invokes webpack-bundle-analyzer plugin to get bundle information.',
},
{
name: 'progress',
usage: '--progress | --progress profile',
type: [Boolean, String],
description: 'Print compilation progress during build.',
},
{
name: 'prefetch',
usage: '--prefetch <request>',
type: String,
description: 'Prefetch this request.',
},

// Output options
{
name: 'json',
usage: '--json | --json <path-to-stats-file>',
type: [String, Boolean],
alias: 'j',
description: 'Prints result as JSON or store it in a file.',
Expand All @@ -118,29 +109,25 @@ const builtInFlags = [
// For webpack@4
{
name: 'entry',
usage: '--entry <path-to-entry-file> | --entry <path> --entry <path>',
type: String,
multiple: true,
description: 'The entry point(s) of your application e.g. ./src/main.js.',
},
{
name: 'output-path',
usage: '--output-path <path-to-output-directory>',
alias: 'o',
type: String,
description: 'Output location of the file generated by webpack e.g. ./dist/.',
},
{
name: 'target',
usage: '--target <value> | --target <value> --target <value>',
alias: 't',
type: String,
multiple: cli !== undefined,
description: 'Sets the build target e.g. node.',
},
{
name: 'devtool',
usage: '--devtool <value>',
type: String,
negative: true,
alias: 'd',
Expand All @@ -149,27 +136,23 @@ const builtInFlags = [
},
{
name: 'mode',
usage: '--mode <development | production | none>',
type: String,
description: 'Defines the mode to pass to webpack.',
},
{
name: 'name',
usage: '--name',
type: String,
description: 'Name of the configuration. Used when loading multiple configurations.',
},
{
name: 'stats',
usage: '--stats | --stats <value>',
type: [String, Boolean],
negative: true,
description: 'It instructs webpack on how to treat the stats e.g. verbose.',
negatedDescription: 'Disable stats output.',
},
{
name: 'watch',
usage: '--watch',
type: Boolean,
negative: true,
alias: 'w',
Expand All @@ -178,7 +161,6 @@ const builtInFlags = [
},
{
name: 'watch-options-stdin',
usage: '--watch-options-stdin',
type: Boolean,
negative: true,
description: 'Stop watching when stdin stream has ended.',
Expand All @@ -192,14 +174,11 @@ const coreFlags = cli
? Object.entries(cli.getArguments()).map(([flag, meta]) => {
if (meta.simpleType === 'string') {
meta.type = String;
meta.usage = `--${flag} <value>`;
} else if (meta.simpleType === 'number') {
meta.type = Number;
meta.usage = `--${flag} <value>`;
} else {
meta.type = Boolean;
meta.negative = !flag.endsWith('-reset');
meta.usage = `--${flag}`;
}

const inBuiltIn = builtInFlags.find((builtInFlag) => builtInFlag.name === flag);
Expand Down
12 changes: 6 additions & 6 deletions packages/webpack-cli/lib/webpack-cli.js
Expand Up @@ -316,7 +316,7 @@ class WebpackCLI {
const loadCommandByName = async (commandName, allowToInstall = false) => {
if (commandName === bundleCommandOptions.name || commandName === bundleCommandOptions.alias) {
// Make `bundle|b [options]` command
this.makeCommand(bundleCommandOptions, this.getBuiltInOptions(), async (program) => {
await this.makeCommand(bundleCommandOptions, this.getBuiltInOptions(), async (program) => {
const options = program.opts();

if (program.args.length > 0) {
Expand Down Expand Up @@ -430,11 +430,11 @@ class WebpackCLI {
process.exit(2);
}

const found = command.options.find((option) => distance(name, option.long.slice(2)) < 3);

if (found) {
logger.error(`Did you mean '--${found.name()}'?`);
}
command.options.forEach((option) => {
if (distance(name, option.long.slice(2)) < 3) {
logger.error(`Did you mean '--${option.name()}'?`);
}
});
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions test/unknown/unknown.test.js
Expand Up @@ -144,6 +144,21 @@ describe('unknown behaviour', () => {
expect(stdout).toBeFalsy();
});

it('should log an error if an unknown flag is passed and suggests the closest match to an unknown flag #3', () => {
const { exitCode, stderr, stdout } = run(__dirname, ['--output-library-auxiliary-comment-commnjs']);

expect(exitCode).toBe(2);
expect(stderr).toContain("unknown option '--output-library-auxiliary-comment-commnjs'");

if (isWebpack5) {
expect(stderr).toContain("Did you mean '--output-library-auxiliary-comment-commonjs'?");
expect(stderr).toContain("Did you mean '--output-library-auxiliary-comment-commonjs2'?");
}

expect(stderr).toContain("Run 'webpack --help' to see available commands and options");
expect(stdout).toBeFalsy();
});

it('should log an error if an unknown flag is passed and suggests the closest match to an unknown flag using "bundle" command', () => {
const { exitCode, stderr, stdout } = run(__dirname, ['bundle', '--entyr', './a.js']);

Expand Down

0 comments on commit 7314d6c

Please sign in to comment.