* Parse options from `argv` removing known options, * and return argv split into operands and unknown arguments. * * Side effects: modifies command by storing options. Does not reset state if called again. * * Examples: * * argv => operands, unknown * --known kkk op =
(args)
| 1758 | */ |
| 1759 | |
| 1760 | parseOptions(args) { |
| 1761 | const operands = []; // operands, not options or values |
| 1762 | const unknown = []; // first unknown option and remaining unknown args |
| 1763 | let dest = operands; |
| 1764 | |
| 1765 | function maybeOption(arg) { |
| 1766 | return arg.length > 1 && arg[0] === '-'; |
| 1767 | } |
| 1768 | |
| 1769 | const negativeNumberArg = (arg) => { |
| 1770 | // return false if not a negative number |
| 1771 | if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg)) return false; |
| 1772 | // negative number is ok unless digit used as an option in command hierarchy |
| 1773 | return !this._getCommandAndAncestors().some((cmd) => |
| 1774 | cmd.options |
| 1775 | .map((opt) => opt.short) |
| 1776 | .some((short) => /^-\d$/.test(short)), |
| 1777 | ); |
| 1778 | }; |
| 1779 | |
| 1780 | // parse options |
| 1781 | let activeVariadicOption = null; |
| 1782 | let activeGroup = null; // working through group of short options, like -abc |
| 1783 | let i = 0; |
| 1784 | while (i < args.length || activeGroup) { |
| 1785 | const arg = activeGroup ?? args[i++]; |
| 1786 | activeGroup = null; |
| 1787 | |
| 1788 | // literal |
| 1789 | if (arg === '--') { |
| 1790 | if (dest === unknown) dest.push(arg); |
| 1791 | dest.push(...args.slice(i)); |
| 1792 | break; |
| 1793 | } |
| 1794 | |
| 1795 | if ( |
| 1796 | activeVariadicOption && |
| 1797 | (!maybeOption(arg) || negativeNumberArg(arg)) |
| 1798 | ) { |
| 1799 | this.emit(`option:${activeVariadicOption.name()}`, arg); |
| 1800 | continue; |
| 1801 | } |
| 1802 | activeVariadicOption = null; |
| 1803 | |
| 1804 | if (maybeOption(arg)) { |
| 1805 | const option = this._findOption(arg); |
| 1806 | // recognised option, call listener to assign value with possible custom processing |
| 1807 | if (option) { |
| 1808 | if (option.required) { |
| 1809 | const value = args[i++]; |
| 1810 | if (value === undefined) this.optionMissingArgument(option); |
| 1811 | this.emit(`option:${option.name()}`, value); |
| 1812 | } else if (option.optional) { |
| 1813 | let value = null; |
| 1814 | // historical behaviour is optional value is following arg unless an option |
| 1815 | if ( |
| 1816 | i < args.length && |
| 1817 | (!maybeOption(args[i]) || negativeNumberArg(args[i])) |
no test coverage detected