parse method Null safety

ArgResults parse()

Parses the arguments. This can only be called once.

Implementation

ArgResults parse() {
  var arguments = _args.toList();
  if (_grammar.allowsAnything) {
    return newArgResults(
        _grammar, const {}, _commandName, null, arguments, arguments);
  }

  ArgResults? commandResults;

  // Parse the args.
  while (_args.isNotEmpty) {
    if (_current == '--') {
      // Reached the argument terminator, so stop here.
      _args.removeFirst();
      break;
    }

    // Try to parse the current argument as a command. This happens before
    // options so that commands can have option-like names.
    var command = _grammar.commands[_current];
    if (command != null) {
      _validate(_rest.isEmpty, 'Cannot specify arguments before a command.');
      var commandName = _args.removeFirst();
      var commandParser = Parser(commandName, command, _args, this, _rest);

      try {
        commandResults = commandParser.parse();
      } on ArgParserException catch (error) {
        throw ArgParserException(
            error.message, [commandName, ...error.commands]);
      }

      // All remaining arguments were passed to command so clear them here.
      _rest.clear();
      break;
    }

    // Try to parse the current argument as an option. Note that the order
    // here matters.
    if (_parseSoloOption()) continue;
    if (_parseAbbreviation(this)) continue;
    if (_parseLongOption()) continue;

    // This argument is neither option nor command, so stop parsing unless
    // the [allowTrailingOptions] option is set.
    if (!_grammar.allowTrailingOptions) break;
    _rest.add(_args.removeFirst());
  }

  // Check if mandatory and invoke existing callbacks.
  _grammar.options.forEach((name, option) {
    var parsedOption = _results[name];

    // Check if an option was mandatory and exist
    // if not throw an exception
    if (option.mandatory && parsedOption == null) {
      throw ArgParserException('Option $name is mandatory.', [name]);
    }

    var callback = option.callback;
    if (callback == null) return;
    callback(option.valueOrDefault(parsedOption));
  });

  // Add in the leftover arguments we didn't parse to the innermost command.
  _rest.addAll(_args);
  _args.clear();
  return newArgResults(
      _grammar, _results, _commandName, commandResults, _rest, arguments);
}