Skip to content

passThroughOptions and unknown option handling #1936

@aweebit

Description

@aweebit

Is there a particular reason why .parseOptions() stops processing args when an unknown option is encountered in the passThroughOptions mode? That complicates the help option refactor I am currently working on in #1934 that aims to achieve maximum consistency between how the help option and all other options are handled, because help flags end up ignored if they come after an unknown option and there is no subcommand.

Checkout 02fde0e and run the following code for a demo:

const program = require('commander');
program
  .passThroughOptions()
  .allowUnknownOption();
program.parse(['--unknown', '--help'], { from: 'user' }); // no help displayed
console.log(program.args); // [ '--unknown', '--help' ]
program
  .allowUnknownOption(false);
program.parse(['--unknown', '--help'], { from: 'user' }); // expected help, got error: unknown option '--unknown'

I tried to change the behavior to the one implied by the docs and comments in code so that the processing is only stopped when a command-argument is encountered (see fcfbec1), but that resulted in a test failing.

Relevant test from tests/command.positionalOptions.test.js (line 423)

  test('when passThroughOptions and unknown option then arguments from unknown passed through', () => {
    const program = new commander.Command();
    program
      .passThroughOptions()
      .allowUnknownOption()
      .option('--debug');

    program.parse(['--unknown', '--debug'], { from: 'user' });
    expect(program.args).toEqual(['--unknown', '--debug']);
  });

The behavior I would expect: --debug is consumed and so program.opts() equals to { debug: true } while program.args equals to ['--unknown'].

Relevant lines in .parseOptions() code (on current develop branch)

      // If using passThroughOptions, stop processing options at first command-argument.
      if (this._passThroughOptions) {
        dest.push(arg);
        if (args.length > 0) dest.push(...args);
        break;
      }

The condition on line 2 should be this._passThroughOptions && !maybeOption(arg) so that the comment on line 1 describes what happens well and does not miss the fact the processing is also stopped at unknown options (currently missed in all explanations of passThroughOptions).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions