// Generated by CoffeeScript 2.3.0
(function() {
  var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat,
    splice = [].splice;

  ({repeat} = require('./helpers'));

  // A simple **OptionParser** class to parse option flags from the command-line.
  // Use it like so:

  //     parser  = new OptionParser switches, helpBanner
  //     options = parser.parse process.argv

  // The first non-option is considered to be the start of the file (and file
  // option) list, and all subsequent arguments are left unparsed.

  // The `coffee` command uses an instance of **OptionParser** to parse its
  // command-line arguments in `src/command.coffee`.
  exports.OptionParser = OptionParser = class OptionParser {
    // Initialize with a list of valid options, in the form:

    //     [short-flag, long-flag, description]

    // Along with an optional banner for the usage help.
    constructor(ruleDeclarations, banner) {
      this.banner = banner;
      this.rules = buildRules(ruleDeclarations);
    }

    // Parse the list of arguments, populating an `options` object with all of the
    // specified options, and return it. Options after the first non-option
    // argument are treated as arguments. `options.arguments` will be an array
    // containing the remaining arguments. This is a simpler API than many option
    // parsers that allow you to attach callback actions for every flag. Instead,
    // you're responsible for interpreting the options object.
    parse(args) {
      var argument, hasArgument, i, isList, len, name, options, positional, rules;
      // The CoffeeScript option parser is a little odd; options after the first
      // non-option argument are treated as non-option arguments themselves.
      // Optional arguments are normalized by expanding merged flags into multiple
      // flags. This allows you to have `-wl` be the same as `--watch --lint`.
      // Note that executable scripts with a shebang (`#!`) line should use the
      // line `#!/usr/bin/env coffee`, or `#!/absolute/path/to/coffee`, without a
      // `--` argument after, because that will fail on Linux (see #3946).
      ({rules, positional} = normalizeArguments(args, this.rules.flagDict));
      options = {};
// The `argument` field is added to the rule instance non-destructively by
// `normalizeArguments`.
      for (i = 0, len = rules.length; i < len; i++) {
        ({hasArgument, argument, isList, name} = rules[i]);
        if (hasArgument) {
          if (isList) {
            if (options[name] == null) {
              options[name] = [];
            }
            options[name].push(argument);
          } else {
            options[name] = argument;
          }
        } else {
          options[name] = true;
        }
      }
      if (positional[0] === '--') {
        options.doubleDashed = true;
        positional = positional.slice(1);
      }
      options.arguments = positional;
      return options;
    }

    // Return the help text for this **OptionParser**, listing and describing all
    // of the valid options, for `--help` and such.
    help() {
      var i, len, letPart, lines, ref, rule, spaces;
      lines = [];
      if (this.banner) {
        lines.unshift(`${this.banner}\n`);
      }
      ref = this.rules.ruleList;
      for (i = 0, len = ref.length; i < len; i++) {
        rule = ref[i];
        spaces = 15 - rule.longFlag.length;
        spaces = spaces > 0 ? repeat(' ', spaces) : '';
        letPart = rule.shortFlag ? rule.shortFlag + ', ' : '    ';
        lines.push('  ' + letPart + rule.longFlag + spaces + rule.description);
      }
      return `\n${lines.join('\n')}\n`;
    }

  };

  // Helpers
  // -------

  // Regex matchers for option flags on the command line and their rules.
  LONG_FLAG = /^(--\w[\w\-]*)/;

  SHORT_FLAG = /^(-\w)$/;

  MULTI_FLAG = /^-(\w{2,})/;

  // Matches the long flag part of a rule for an option with an argument. Not
  // applied to anything in process.argv.
  OPTIONAL = /\[(\w+(\*?))\]/;

  // Build and return the list of option rules. If the optional *short-flag* is
  // unspecified, leave it out by padding with `null`.
  buildRules = function(ruleDeclarations) {
    var flag, flagDict, i, j, len, len1, ref, rule, ruleList, tuple;
    ruleList = (function() {
      var i, len, results;
      results = [];
      for (i = 0, len = ruleDeclarations.length; i < len; i++) {
        tuple = ruleDeclarations[i];
        if (tuple.length < 3) {
          tuple.unshift(null);
        }
        results.push(buildRule(...tuple));
      }
      return results;
    })();
    flagDict = {};
    for (i = 0, len = ruleList.length; i < len; i++) {
      rule = ruleList[i];
      ref = [rule.shortFlag, rule.longFlag];
      // `shortFlag` is null if not provided in the rule.
      for (j = 0, len1 = ref.length; j < len1; j++) {
        flag = ref[j];
        if (!(flag != null)) {
          continue;
        }
        if (flagDict[flag] != null) {
          throw new Error(`flag ${flag} for switch ${rule.name} was already declared for switch ${flagDict[flag].name}`);
        }
        flagDict[flag] = rule;
      }
    }
    return {ruleList, flagDict};
  };

  // Build a rule from a `-o` short flag, a `--output [DIR]` long flag, and the
  // description of what the option does.
  buildRule = function(shortFlag, longFlag, description) {
    var match;
    match = longFlag.match(OPTIONAL);
    shortFlag = shortFlag != null ? shortFlag.match(SHORT_FLAG)[1] : void 0;
    longFlag = longFlag.match(LONG_FLAG)[1];
    return {
      name: longFlag.replace(/^--/, ''),
      shortFlag: shortFlag,
      longFlag: longFlag,
      description: description,
      hasArgument: !!(match && match[1]),
      isList: !!(match && match[2])
    };
  };

  normalizeArguments = function(args, flagDict) {
    var arg, argIndex, flag, i, innerOpts, j, lastOpt, len, len1, multiFlags, multiOpts, needsArgOpt, positional, ref, rule, rules, singleRule, withArg;
    rules = [];
    positional = [];
    needsArgOpt = null;
    for (argIndex = i = 0, len = args.length; i < len; argIndex = ++i) {
      arg = args[argIndex];
      // If the previous argument given to the script was an option that uses the
      // next command-line argument as its argument, create copy of the option’s
      // rule with an `argument` field.
      if (needsArgOpt != null) {
        withArg = Object.assign({}, needsArgOpt.rule, {
          argument: arg
        });
        rules.push(withArg);
        needsArgOpt = null;
        continue;
      }
      multiFlags = (ref = arg.match(MULTI_FLAG)) != null ? ref[1].split('').map(function(flagName) {
        return `-${flagName}`;
      }) : void 0;
      if (multiFlags != null) {
        multiOpts = multiFlags.map(function(flag) {
          var rule;
          rule = flagDict[flag];
          if (rule == null) {
            throw new Error(`unrecognized option ${flag} in multi-flag ${arg}`);
          }
          return {rule, flag};
        });
        // Only the last flag in a multi-flag may have an argument.
        [...innerOpts] = multiOpts, [lastOpt] = splice.call(innerOpts, -1);
        for (j = 0, len1 = innerOpts.length; j < len1; j++) {
          ({rule, flag} = innerOpts[j]);
          if (rule.hasArgument) {
            throw new Error(`cannot use option ${flag} in multi-flag ${arg} except as the last option, because it needs an argument`);
          }
          rules.push(rule);
        }
        if (lastOpt.rule.hasArgument) {
          needsArgOpt = lastOpt;
        } else {
          rules.push(lastOpt.rule);
        }
      } else if ([LONG_FLAG, SHORT_FLAG].some(function(pat) {
        return arg.match(pat) != null;
      })) {
        singleRule = flagDict[arg];
        if (singleRule == null) {
          throw new Error(`unrecognized option ${arg}`);
        }
        if (singleRule.hasArgument) {
          needsArgOpt = {
            rule: singleRule,
            flag: arg
          };
        } else {
          rules.push(singleRule);
        }
      } else {
        // This is a positional argument.
        positional = args.slice(argIndex);
        break;
      }
    }
    if (needsArgOpt != null) {
      throw new Error(`value required for ${needsArgOpt.flag}, but it was the last argument provided`);
    }
    return {rules, positional};
  };

}).call(this);
