From bc12f1a2a833f09a0585050a0f5dd854da188f1d Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Mon, 19 Apr 2021 20:19:28 +0530 Subject: [PATCH] fix: parsing of empty `--env` flags (#2643) --- packages/webpack-cli/lib/webpack-cli.js | 26 +++++++++++----- .../function-with-env.test.js | 30 +++++++++++++++++++ .../type/function-with-env/webpack.config.js | 24 +++++++++++++++ .../__snapshots__/help.test.js.snap.webpack4 | 2 ++ .../__snapshots__/help.test.js.snap.webpack5 | 2 ++ test/help/help.test.js | 8 +++++ 6 files changed, 85 insertions(+), 7 deletions(-) diff --git a/packages/webpack-cli/lib/webpack-cli.js b/packages/webpack-cli/lib/webpack-cli.js index c5ba9ff9e15..449aa9b4ba6 100644 --- a/packages/webpack-cli/lib/webpack-cli.js +++ b/packages/webpack-cli/lib/webpack-cli.js @@ -373,6 +373,11 @@ class WebpackCLI { { name: 'env', type: (value, previous = {}) => { + // for https://github.com/webpack/webpack-cli/issues/2642 + if (value.endsWith('=')) { + value.concat('""'); + } + // This ensures we're only splitting by the first `=` const [allKeys, val] = value.split(/=(.+)/, 2); const splitKeys = allKeys.split(/\.(?!$)/); @@ -389,7 +394,11 @@ class WebpackCLI { } if (index === splitKeys.length - 1) { - prevRef[someKey] = val || true; + if (typeof val === 'string') { + prevRef[someKey] = val; + } else { + prevRef[someKey] = true; + } } prevRef = prevRef[someKey]; @@ -1212,13 +1221,13 @@ class WebpackCLI { const defaultCommandToRun = getCommandName(buildCommandOptions.name); const hasOperand = typeof operands[0] !== 'undefined'; const operand = hasOperand ? operands[0] : defaultCommandToRun; - + const isHelpOption = typeof options.help !== 'undefined'; const isHelpCommandSyntax = isCommand(operand, helpCommandOptions); - if (options.help || isHelpCommandSyntax) { + if (isHelpOption || isHelpCommandSyntax) { let isVerbose = false; - if (options.help) { + if (isHelpOption) { if (typeof options.help === 'string') { if (options.help !== 'verbose') { this.logger.error("Unknown value for '--help' option, please use '--help=verbose'"); @@ -1232,7 +1241,7 @@ class WebpackCLI { this.program.forHelp = true; const optionsForHelp = [] - .concat(options.help && hasOperand ? [operand] : []) + .concat(isHelpOption && hasOperand ? [operand] : []) // Syntax `webpack help [command]` .concat(operands.slice(1)) // Syntax `webpack help [option]` @@ -1243,9 +1252,12 @@ class WebpackCLI { await outputHelp(optionsForHelp, isVerbose, isHelpCommandSyntax, program); } - if (options.version || isCommand(operand, versionCommandOptions)) { + const isVersionOption = typeof options.version !== 'undefined'; + const isVersionCommandSyntax = isCommand(operand, versionCommandOptions); + + if (isVersionOption || isVersionCommandSyntax) { const optionsForVersion = [] - .concat(options.version ? [operand] : []) + .concat(isVersionOption ? [operand] : []) .concat(operands.slice(1)) .concat(unknown); diff --git a/test/build/config/type/function-with-env/function-with-env.test.js b/test/build/config/type/function-with-env/function-with-env.test.js index b31b2e546ad..539cc160684 100644 --- a/test/build/config/type/function-with-env/function-with-env.test.js +++ b/test/build/config/type/function-with-env/function-with-env.test.js @@ -117,6 +117,36 @@ describe('function configuration', () => { expect(existsSync(resolve(__dirname, './dist/true.js'))).toBeTruthy(); }); + it('Supports empty string', async () => { + const { exitCode, stderr, stdout } = await run(__dirname, ['--env', `foo=''`]); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toBeTruthy(); + // Should generate the appropriate files + expect(existsSync(resolve(__dirname, './dist/empty-string.js'))).toBeTruthy(); + }); + + it('Supports empty string with multiple "="', async () => { + const { exitCode, stderr, stdout } = await run(__dirname, ['--env', `foo=bar=''`]); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toBeTruthy(); + // Should generate the appropriate files + expect(existsSync(resolve(__dirname, './dist/new-empty-string.js'))).toBeTruthy(); + }); + + it('Supports env variable with "=" at the end', async () => { + const { exitCode, stderr, stdout } = await run(__dirname, ['--env', `foo=`]); + + expect(exitCode).toBe(0); + expect(stderr).toBeFalsy(); + expect(stdout).toBeTruthy(); + // Should generate the appropriate files + expect(existsSync(resolve(__dirname, './dist/equal-at-the-end.js'))).toBeTruthy(); + }); + it('is able to understand multiple env flags', async () => { const { exitCode, stderr, stdout } = await run(__dirname, ['--env', 'isDev', '--env', 'verboseStats', '--env', 'envMessage']); diff --git a/test/build/config/type/function-with-env/webpack.config.js b/test/build/config/type/function-with-env/webpack.config.js index 35efedbbb0d..5a726c711f9 100644 --- a/test/build/config/type/function-with-env/webpack.config.js +++ b/test/build/config/type/function-with-env/webpack.config.js @@ -9,6 +9,30 @@ module.exports = (env) => { }, }; } + if (env.foo === `''`) { + return { + entry: './a.js', + output: { + filename: 'empty-string.js', + }, + }; + } + if (env.foo === `bar=''`) { + return { + entry: './a.js', + output: { + filename: 'new-empty-string.js', + }, + }; + } + if (env['foo=']) { + return { + entry: './a.js', + output: { + filename: 'equal-at-the-end.js', + }, + }; + } return { entry: './a.js', mode: 'development', diff --git a/test/help/__snapshots__/help.test.js.snap.webpack4 b/test/help/__snapshots__/help.test.js.snap.webpack4 index a17dfec40c0..238420633fd 100644 --- a/test/help/__snapshots__/help.test.js.snap.webpack4 +++ b/test/help/__snapshots__/help.test.js.snap.webpack4 @@ -28,6 +28,8 @@ exports[`help should log error for invalid command using the "--help" option 1`] exports[`help should log error for invalid flag with the "--help" option #2 1`] = `"[webpack-cli] Unknown value for '--help' option, please use '--help=verbose'"`; +exports[`help should log error for invalid flag with the "--help" option #2 2`] = `"[webpack-cli] Unknown value for '--help' option, please use '--help=verbose'"`; + exports[`help should log error for invalid flag with the "--help" option 1`] = ` "[webpack-cli] Incorrect use of help [webpack-cli] Please use: 'webpack help [command] [option]' | 'webpack [command] --help' diff --git a/test/help/__snapshots__/help.test.js.snap.webpack5 b/test/help/__snapshots__/help.test.js.snap.webpack5 index 7297f62c0f0..444cffabc89 100644 --- a/test/help/__snapshots__/help.test.js.snap.webpack5 +++ b/test/help/__snapshots__/help.test.js.snap.webpack5 @@ -28,6 +28,8 @@ exports[`help should log error for invalid command using the "--help" option 1`] exports[`help should log error for invalid flag with the "--help" option #2 1`] = `"[webpack-cli] Unknown value for '--help' option, please use '--help=verbose'"`; +exports[`help should log error for invalid flag with the "--help" option #2 2`] = `"[webpack-cli] Unknown value for '--help' option, please use '--help=verbose'"`; + exports[`help should log error for invalid flag with the "--help" option 1`] = ` "[webpack-cli] Incorrect use of help [webpack-cli] Please use: 'webpack help [command] [option]' | 'webpack [command] --help' diff --git a/test/help/help.test.js b/test/help/help.test.js index 189fcf095d7..e3dbba1cf1d 100644 --- a/test/help/help.test.js +++ b/test/help/help.test.js @@ -402,4 +402,12 @@ describe('help', () => { expect(stderr).toMatchSnapshot(); expect(stdout).toBeFalsy(); }); + + it('should log error for invalid flag with the "--help" option #2', async () => { + const { exitCode, stderr, stdout } = await run(__dirname, ['--help=']); + + expect(exitCode).toBe(2); + expect(stderr).toMatchSnapshot(); + expect(stdout).toBeFalsy(); + }); });