From fc87c009806dcc98867f6b58efe29b042aa01dee Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Mon, 18 May 2026 23:10:59 +0800 Subject: node: update --- node_modules/argparse/argparse.js | 3707 ------------------------------------- 1 file changed, 3707 deletions(-) delete mode 100644 node_modules/argparse/argparse.js (limited to 'node_modules/argparse/argparse.js') diff --git a/node_modules/argparse/argparse.js b/node_modules/argparse/argparse.js deleted file mode 100644 index 2b8c8c63..00000000 --- a/node_modules/argparse/argparse.js +++ /dev/null @@ -1,3707 +0,0 @@ -// Port of python's argparse module, version 3.9.0: -// https://github.com/python/cpython/blob/v3.9.0rc1/Lib/argparse.py - -'use strict' - -// Copyright (C) 2010-2020 Python Software Foundation. -// Copyright (C) 2020 argparse.js authors - -/* - * Command-line parsing library - * - * This module is an optparse-inspired command-line parsing library that: - * - * - handles both optional and positional arguments - * - produces highly informative usage messages - * - supports parsers that dispatch to sub-parsers - * - * The following is a simple usage example that sums integers from the - * command-line and writes the result to a file:: - * - * parser = argparse.ArgumentParser( - * description='sum the integers at the command line') - * parser.add_argument( - * 'integers', metavar='int', nargs='+', type=int, - * help='an integer to be summed') - * parser.add_argument( - * '--log', default=sys.stdout, type=argparse.FileType('w'), - * help='the file where the sum should be written') - * args = parser.parse_args() - * args.log.write('%s' % sum(args.integers)) - * args.log.close() - * - * The module contains the following public classes: - * - * - ArgumentParser -- The main entry point for command-line parsing. As the - * example above shows, the add_argument() method is used to populate - * the parser with actions for optional and positional arguments. Then - * the parse_args() method is invoked to convert the args at the - * command-line into an object with attributes. - * - * - ArgumentError -- The exception raised by ArgumentParser objects when - * there are errors with the parser's actions. Errors raised while - * parsing the command-line are caught by ArgumentParser and emitted - * as command-line messages. - * - * - FileType -- A factory for defining types of files to be created. As the - * example above shows, instances of FileType are typically passed as - * the type= argument of add_argument() calls. - * - * - Action -- The base class for parser actions. Typically actions are - * selected by passing strings like 'store_true' or 'append_const' to - * the action= argument of add_argument(). However, for greater - * customization of ArgumentParser actions, subclasses of Action may - * be defined and passed as the action= argument. - * - * - HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter, - * ArgumentDefaultsHelpFormatter -- Formatter classes which - * may be passed as the formatter_class= argument to the - * ArgumentParser constructor. HelpFormatter is the default, - * RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser - * not to change the formatting for help text, and - * ArgumentDefaultsHelpFormatter adds information about argument defaults - * to the help. - * - * All other classes in this module are considered implementation details. - * (Also note that HelpFormatter and RawDescriptionHelpFormatter are only - * considered public as object names -- the API of the formatter objects is - * still considered an implementation detail.) - */ - -const SUPPRESS = '==SUPPRESS==' - -const OPTIONAL = '?' -const ZERO_OR_MORE = '*' -const ONE_OR_MORE = '+' -const PARSER = 'A...' -const REMAINDER = '...' -const _UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args' - - -// ================================== -// Utility functions used for porting -// ================================== -const assert = require('assert') -const util = require('util') -const fs = require('fs') -const sub = require('./lib/sub') -const path = require('path') -const repr = util.inspect - -function get_argv() { - // omit first argument (which is assumed to be interpreter - `node`, `coffee`, `ts-node`, etc.) - return process.argv.slice(1) -} - -function get_terminal_size() { - return { - columns: +process.env.COLUMNS || process.stdout.columns || 80 - } -} - -function hasattr(object, name) { - return Object.prototype.hasOwnProperty.call(object, name) -} - -function getattr(object, name, value) { - return hasattr(object, name) ? object[name] : value -} - -function setattr(object, name, value) { - object[name] = value -} - -function setdefault(object, name, value) { - if (!hasattr(object, name)) object[name] = value - return object[name] -} - -function delattr(object, name) { - delete object[name] -} - -function range(from, to, step=1) { - // range(10) is equivalent to range(0, 10) - if (arguments.length === 1) [ to, from ] = [ from, 0 ] - if (typeof from !== 'number' || typeof to !== 'number' || typeof step !== 'number') { - throw new TypeError('argument cannot be interpreted as an integer') - } - if (step === 0) throw new TypeError('range() arg 3 must not be zero') - - let result = [] - if (step > 0) { - for (let i = from; i < to; i += step) result.push(i) - } else { - for (let i = from; i > to; i += step) result.push(i) - } - return result -} - -function splitlines(str, keepends = false) { - let result - if (!keepends) { - result = str.split(/\r\n|[\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029]/) - } else { - result = [] - let parts = str.split(/(\r\n|[\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029])/) - for (let i = 0; i < parts.length; i += 2) { - result.push(parts[i] + (i + 1 < parts.length ? parts[i + 1] : '')) - } - } - if (!result[result.length - 1]) result.pop() - return result -} - -function _string_lstrip(string, prefix_chars) { - let idx = 0 - while (idx < string.length && prefix_chars.includes(string[idx])) idx++ - return idx ? string.slice(idx) : string -} - -function _string_split(string, sep, maxsplit) { - let result = string.split(sep) - if (result.length > maxsplit) { - result = result.slice(0, maxsplit).concat([ result.slice(maxsplit).join(sep) ]) - } - return result -} - -function _array_equal(array1, array2) { - if (array1.length !== array2.length) return false - for (let i = 0; i < array1.length; i++) { - if (array1[i] !== array2[i]) return false - } - return true -} - -function _array_remove(array, item) { - let idx = array.indexOf(item) - if (idx === -1) throw new TypeError(sub('%r not in list', item)) - array.splice(idx, 1) -} - -// normalize choices to array; -// this isn't required in python because `in` and `map` operators work with anything, -// but in js dealing with multiple types here is too clunky -function _choices_to_array(choices) { - if (choices === undefined) { - return [] - } else if (Array.isArray(choices)) { - return choices - } else if (choices !== null && typeof choices[Symbol.iterator] === 'function') { - return Array.from(choices) - } else if (typeof choices === 'object' && choices !== null) { - return Object.keys(choices) - } else { - throw new Error(sub('invalid choices value: %r', choices)) - } -} - -// decorator that allows a class to be called without new -function _callable(cls) { - let result = { // object is needed for inferred class name - [cls.name]: function (...args) { - let this_class = new.target === result || !new.target - return Reflect.construct(cls, args, this_class ? cls : new.target) - } - } - result[cls.name].prototype = cls.prototype - // fix default tag for toString, e.g. [object Action] instead of [object Object] - cls.prototype[Symbol.toStringTag] = cls.name - return result[cls.name] -} - -function _alias(object, from, to) { - try { - let name = object.constructor.name - Object.defineProperty(object, from, { - value: util.deprecate(object[to], sub('%s.%s() is renamed to %s.%s()', - name, from, name, to)), - enumerable: false - }) - } catch {} -} - -// decorator that allows snake_case class methods to be called with camelCase and vice versa -function _camelcase_alias(_class) { - for (let name of Object.getOwnPropertyNames(_class.prototype)) { - let camelcase = name.replace(/\w_[a-z]/g, s => s[0] + s[2].toUpperCase()) - if (camelcase !== name) _alias(_class.prototype, camelcase, name) - } - return _class -} - -function _to_legacy_name(key) { - key = key.replace(/\w_[a-z]/g, s => s[0] + s[2].toUpperCase()) - if (key === 'default') key = 'defaultValue' - if (key === 'const') key = 'constant' - return key -} - -function _to_new_name(key) { - if (key === 'defaultValue') key = 'default' - if (key === 'constant') key = 'const' - key = key.replace(/[A-Z]/g, c => '_' + c.toLowerCase()) - return key -} - -// parse options -let no_default = Symbol('no_default_value') -function _parse_opts(args, descriptor) { - function get_name() { - let stack = new Error().stack.split('\n') - .map(x => x.match(/^ at (.*) \(.*\)$/)) - .filter(Boolean) - .map(m => m[1]) - .map(fn => fn.match(/[^ .]*$/)[0]) - - if (stack.length && stack[0] === get_name.name) stack.shift() - if (stack.length && stack[0] === _parse_opts.name) stack.shift() - return stack.length ? stack[0] : '' - } - - args = Array.from(args) - let kwargs = {} - let result = [] - let last_opt = args.length && args[args.length - 1] - - if (typeof last_opt === 'object' && last_opt !== null && !Array.isArray(last_opt) && - (!last_opt.constructor || last_opt.constructor.name === 'Object')) { - kwargs = Object.assign({}, args.pop()) - } - - // LEGACY (v1 compatibility): camelcase - let renames = [] - for (let key of Object.keys(descriptor)) { - let old_name = _to_legacy_name(key) - if (old_name !== key && (old_name in kwargs)) { - if (key in kwargs) { - // default and defaultValue specified at the same time, happens often in old tests - //throw new TypeError(sub('%s() got multiple values for argument %r', get_name(), key)) - } else { - kwargs[key] = kwargs[old_name] - } - renames.push([ old_name, key ]) - delete kwargs[old_name] - } - } - if (renames.length) { - let name = get_name() - deprecate('camelcase_' + name, sub('%s(): following options are renamed: %s', - name, renames.map(([ a, b ]) => sub('%r -> %r', a, b)))) - } - // end - - let missing_positionals = [] - let positional_count = args.length - - for (let [ key, def ] of Object.entries(descriptor)) { - if (key[0] === '*') { - if (key.length > 0 && key[1] === '*') { - // LEGACY (v1 compatibility): camelcase - let renames = [] - for (let key of Object.keys(kwargs)) { - let new_name = _to_new_name(key) - if (new_name !== key && (key in kwargs)) { - if (new_name in kwargs) { - // default and defaultValue specified at the same time, happens often in old tests - //throw new TypeError(sub('%s() got multiple values for argument %r', get_name(), new_name)) - } else { - kwargs[new_name] = kwargs[key] - } - renames.push([ key, new_name ]) - delete kwargs[key] - } - } - if (renames.length) { - let name = get_name() - deprecate('camelcase_' + name, sub('%s(): following options are renamed: %s', - name, renames.map(([ a, b ]) => sub('%r -> %r', a, b)))) - } - // end - result.push(kwargs) - kwargs = {} - } else { - result.push(args) - args = [] - } - } else if (key in kwargs && args.length > 0) { - throw new TypeError(sub('%s() got multiple values for argument %r', get_name(), key)) - } else if (key in kwargs) { - result.push(kwargs[key]) - delete kwargs[key] - } else if (args.length > 0) { - result.push(args.shift()) - } else if (def !== no_default) { - result.push(def) - } else { - missing_positionals.push(key) - } - } - - if (Object.keys(kwargs).length) { - throw new TypeError(sub('%s() got an unexpected keyword argument %r', - get_name(), Object.keys(kwargs)[0])) - } - - if (args.length) { - let from = Object.entries(descriptor).filter(([ k, v ]) => k[0] !== '*' && v !== no_default).length - let to = Object.entries(descriptor).filter(([ k ]) => k[0] !== '*').length - throw new TypeError(sub('%s() takes %s positional argument%s but %s %s given', - get_name(), - from === to ? sub('from %s to %s', from, to) : to, - from === to && to === 1 ? '' : 's', - positional_count, - positional_count === 1 ? 'was' : 'were')) - } - - if (missing_positionals.length) { - let strs = missing_positionals.map(repr) - if (strs.length > 1) strs[strs.length - 1] = 'and ' + strs[strs.length - 1] - let str_joined = strs.join(strs.length === 2 ? '' : ', ') - throw new TypeError(sub('%s() missing %i required positional argument%s: %s', - get_name(), strs.length, strs.length === 1 ? '' : 's', str_joined)) - } - - return result -} - -let _deprecations = {} -function deprecate(id, string) { - _deprecations[id] = _deprecations[id] || util.deprecate(() => {}, string) - _deprecations[id]() -} - - -// ============================= -// Utility functions and classes -// ============================= -function _AttributeHolder(cls = Object) { - /* - * Abstract base class that provides __repr__. - * - * The __repr__ method returns a string in the format:: - * ClassName(attr=name, attr=name, ...) - * The attributes are determined either by a class-level attribute, - * '_kwarg_names', or by inspecting the instance __dict__. - */ - - return class _AttributeHolder extends cls { - [util.inspect.custom]() { - let type_name = this.constructor.name - let arg_strings = [] - let star_args = {} - for (let arg of this._get_args()) { - arg_strings.push(repr(arg)) - } - for (let [ name, value ] of this._get_kwargs()) { - if (/^[a-z_][a-z0-9_$]*$/i.test(name)) { - arg_strings.push(sub('%s=%r', name, value)) - } else { - star_args[name] = value - } - } - if (Object.keys(star_args).length) { - arg_strings.push(sub('**%s', repr(star_args))) - } - return sub('%s(%s)', type_name, arg_strings.join(', ')) - } - - toString() { - return this[util.inspect.custom]() - } - - _get_kwargs() { - return Object.entries(this) - } - - _get_args() { - return [] - } - } -} - - -function _copy_items(items) { - if (items === undefined) { - return [] - } - return items.slice(0) -} - - -// =============== -// Formatting Help -// =============== -const HelpFormatter = _camelcase_alias(_callable(class HelpFormatter { - /* - * Formatter for generating usage messages and argument help strings. - * - * Only the name of this class is considered a public API. All the methods - * provided by the class are considered an implementation detail. - */ - - constructor() { - let [ - prog, - indent_increment, - max_help_position, - width - ] = _parse_opts(arguments, { - prog: no_default, - indent_increment: 2, - max_help_position: 24, - width: undefined - }) - - // default setting for width - if (width === undefined) { - width = get_terminal_size().columns - width -= 2 - } - - this._prog = prog - this._indent_increment = indent_increment - this._max_help_position = Math.min(max_help_position, - Math.max(width - 20, indent_increment * 2)) - this._width = width - - this._current_indent = 0 - this._level = 0 - this._action_max_length = 0 - - this._root_section = this._Section(this, undefined) - this._current_section = this._root_section - - this._whitespace_matcher = /[ \t\n\r\f\v]+/g // equivalent to python /\s+/ with ASCII flag - this._long_break_matcher = /\n\n\n+/g - } - - // =============================== - // Section and indentation methods - // =============================== - _indent() { - this._current_indent += this._indent_increment - this._level += 1 - } - - _dedent() { - this._current_indent -= this._indent_increment - assert(this._current_indent >= 0, 'Indent decreased below 0.') - this._level -= 1 - } - - _add_item(func, args) { - this._current_section.items.push([ func, args ]) - } - - // ======================== - // Message building methods - // ======================== - start_section(heading) { - this._indent() - let section = this._Section(this, this._current_section, heading) - this._add_item(section.format_help.bind(section), []) - this._current_section = section - } - - end_section() { - this._current_section = this._current_section.parent - this._dedent() - } - - add_text(text) { - if (text !== SUPPRESS && text !== undefined) { - this._add_item(this._format_text.bind(this), [text]) - } - } - - add_usage(usage, actions, groups, prefix = undefined) { - if (usage !== SUPPRESS) { - let args = [ usage, actions, groups, prefix ] - this._add_item(this._format_usage.bind(this), args) - } - } - - add_argument(action) { - if (action.help !== SUPPRESS) { - - // find all invocations - let invocations = [this._format_action_invocation(action)] - for (let subaction of this._iter_indented_subactions(action)) { - invocations.push(this._format_action_invocation(subaction)) - } - - // update the maximum item length - let invocation_length = Math.max(...invocations.map(invocation => invocation.length)) - let action_length = invocation_length + this._current_indent - this._action_max_length = Math.max(this._action_max_length, - action_length) - - // add the item to the list - this._add_item(this._format_action.bind(this), [action]) - } - } - - add_arguments(actions) { - for (let action of actions) { - this.add_argument(action) - } - } - - // ======================= - // Help-formatting methods - // ======================= - format_help() { - let help = this._root_section.format_help() - if (help) { - help = help.replace(this._long_break_matcher, '\n\n') - help = help.replace(/^\n+|\n+$/g, '') + '\n' - } - return help - } - - _join_parts(part_strings) { - return part_strings.filter(part => part && part !== SUPPRESS).join('') - } - - _format_usage(usage, actions, groups, prefix) { - if (prefix === undefined) { - prefix = 'usage: ' - } - - // if usage is specified, use that - if (usage !== undefined) { - usage = sub(usage, { prog: this._prog }) - - // if no optionals or positionals are available, usage is just prog - } else if (usage === undefined && !actions.length) { - usage = sub('%(prog)s', { prog: this._prog }) - - // if optionals and positionals are available, calculate usage - } else if (usage === undefined) { - let prog = sub('%(prog)s', { prog: this._prog }) - - // split optionals from positionals - let optionals = [] - let positionals = [] - for (let action of actions) { - if (action.option_strings.length) { - optionals.push(action) - } else { - positionals.push(action) - } - } - - // build full usage string - let action_usage = this._format_actions_usage([].concat(optionals).concat(positionals), groups) - usage = [ prog, action_usage ].map(String).join(' ') - - // wrap the usage parts if it's too long - let text_width = this._width - this._current_indent - if (prefix.length + usage.length > text_width) { - - // break usage into wrappable parts - let part_regexp = /\(.*?\)+(?=\s|$)|\[.*?\]+(?=\s|$)|\S+/g - let opt_usage = this._format_actions_usage(optionals, groups) - let pos_usage = this._format_actions_usage(positionals, groups) - let opt_parts = opt_usage.match(part_regexp) || [] - let pos_parts = pos_usage.match(part_regexp) || [] - assert(opt_parts.join(' ') === opt_usage) - assert(pos_parts.join(' ') === pos_usage) - - // helper for wrapping lines - let get_lines = (parts, indent, prefix = undefined) => { - let lines = [] - let line = [] - let line_len - if (prefix !== undefined) { - line_len = prefix.length - 1 - } else { - line_len = indent.length - 1 - } - for (let part of parts) { - if (line_len + 1 + part.length > text_width && line) { - lines.push(indent + line.join(' ')) - line = [] - line_len = indent.length - 1 - } - line.push(part) - line_len += part.length + 1 - } - if (line.length) { - lines.push(indent + line.join(' ')) - } - if (prefix !== undefined) { - lines[0] = lines[0].slice(indent.length) - } - return lines - } - - let lines - - // if prog is short, follow it with optionals or positionals - if (prefix.length + prog.length <= 0.75 * text_width) { - let indent = ' '.repeat(prefix.length + prog.length + 1) - if (opt_parts.length) { - lines = get_lines([prog].concat(opt_parts), indent, prefix) - lines = lines.concat(get_lines(pos_parts, indent)) - } else if (pos_parts.length) { - lines = get_lines([prog].concat(pos_parts), indent, prefix) - } else { - lines = [prog] - } - - // if prog is long, put it on its own line - } else { - let indent = ' '.repeat(prefix.length) - let parts = [].concat(opt_parts).concat(pos_parts) - lines = get_lines(parts, indent) - if (lines.length > 1) { - lines = [] - lines = lines.concat(get_lines(opt_parts, indent)) - lines = lines.concat(get_lines(pos_parts, indent)) - } - lines = [prog].concat(lines) - } - - // join lines into usage - usage = lines.join('\n') - } - } - - // prefix with 'usage:' - return sub('%s%s\n\n', prefix, usage) - } - - _format_actions_usage(actions, groups) { - // find group indices and identify actions in groups - let group_actions = new Set() - let inserts = {} - for (let group of groups) { - let start = actions.indexOf(group._group_actions[0]) - if (start === -1) { - continue - } else { - let end = start + group._group_actions.length - if (_array_equal(actions.slice(start, end), group._group_actions)) { - for (let action of group._group_actions) { - group_actions.add(action) - } - if (!group.required) { - if (start in inserts) { - inserts[start] += ' [' - } else { - inserts[start] = '[' - } - if (end in inserts) { - inserts[end] += ']' - } else { - inserts[end] = ']' - } - } else { - if (start in inserts) { - inserts[start] += ' (' - } else { - inserts[start] = '(' - } - if (end in inserts) { - inserts[end] += ')' - } else { - inserts[end] = ')' - } - } - for (let i of range(start + 1, end)) { - inserts[i] = '|' - } - } - } - } - - // collect all actions format strings - let parts = [] - for (let [ i, action ] of Object.entries(actions)) { - - // suppressed arguments are marked with None - // remove | separators for suppressed arguments - if (action.help === SUPPRESS) { - parts.push(undefined) - if (inserts[+i] === '|') { - delete inserts[+i] - } else if (inserts[+i + 1] === '|') { - delete inserts[+i + 1] - } - - // produce all arg strings - } else if (!action.option_strings.length) { - let default_value = this._get_default_metavar_for_positional(action) - let part = this._format_args(action, default_value) - - // if it's in a group, strip the outer [] - if (group_actions.has(action)) { - if (part[0] === '[' && part[part.length - 1] === ']') { - part = part.slice(1, -1) - } - } - - // add the action string to the list - parts.push(part) - - // produce the first way to invoke the option in brackets - } else { - let option_string = action.option_strings[0] - let part - - // if the Optional doesn't take a value, format is: - // -s or --long - if (action.nargs === 0) { - part = action.format_usage() - - // if the Optional takes a value, format is: - // -s ARGS or --long ARGS - } else { - let default_value = this._get_default_metavar_for_optional(action) - let args_string = this._format_args(action, default_value) - part = sub('%s %s', option_string, args_string) - } - - // make it look optional if it's not required or in a group - if (!action.required && !group_actions.has(action)) { - part = sub('[%s]', part) - } - - // add the action string to the list - parts.push(part) - } - } - - // insert things at the necessary indices - for (let i of Object.keys(inserts).map(Number).sort((a, b) => b - a)) { - parts.splice(+i, 0, inserts[+i]) - } - - // join all the action items with spaces - let text = parts.filter(Boolean).join(' ') - - // clean up separators for mutually exclusive groups - text = text.replace(/([\[(]) /g, '$1') - text = text.replace(/ ([\])])/g, '$1') - text = text.replace(/[\[(] *[\])]/g, '') - text = text.replace(/\(([^|]*)\)/g, '$1', text) - text = text.trim() - - // return the text - return text - } - - _format_text(text) { - if (text.includes('%(prog)')) { - text = sub(text, { prog: this._prog }) - } - let text_width = Math.max(this._width - this._current_indent, 11) - let indent = ' '.repeat(this._current_indent) - return this._fill_text(text, text_width, indent) + '\n\n' - } - - _format_action(action) { - // determine the required width and the entry label - let help_position = Math.min(this._action_max_length + 2, - this._max_help_position) - let help_width = Math.max(this._width - help_position, 11) - let action_width = help_position - this._current_indent - 2 - let action_header = this._format_action_invocation(action) - let indent_first - - // no help; start on same line and add a final newline - if (!action.help) { - let tup = [ this._current_indent, '', action_header ] - action_header = sub('%*s%s\n', ...tup) - - // short action name; start on the same line and pad two spaces - } else if (action_header.length <= action_width) { - let tup = [ this._current_indent, '', action_width, action_header ] - action_header = sub('%*s%-*s ', ...tup) - indent_first = 0 - - // long action name; start on the next line - } else { - let tup = [ this._current_indent, '', action_header ] - action_header = sub('%*s%s\n', ...tup) - indent_first = help_position - } - - // collect the pieces of the action help - let parts = [action_header] - - // if there was help for the action, add lines of help text - if (action.help) { - let help_text = this._expand_help(action) - let help_lines = this._split_lines(help_text, help_width) - parts.push(sub('%*s%s\n', indent_first, '', help_lines[0])) - for (let line of help_lines.slice(1)) { - parts.push(sub('%*s%s\n', help_position, '', line)) - } - - // or add a newline if the description doesn't end with one - } else if (!action_header.endsWith('\n')) { - parts.push('\n') - } - - // if there are any sub-actions, add their help as well - for (let subaction of this._iter_indented_subactions(action)) { - parts.push(this._format_action(subaction)) - } - - // return a single string - return this._join_parts(parts) - } - - _format_action_invocation(action) { - if (!action.option_strings.length) { - let default_value = this._get_default_metavar_for_positional(action) - let metavar = this._metavar_formatter(action, default_value)(1)[0] - return metavar - - } else { - let parts = [] - - // if the Optional doesn't take a value, format is: - // -s, --long - if (action.nargs === 0) { - parts = parts.concat(action.option_strings) - - // if the Optional takes a value, format is: - // -s ARGS, --long ARGS - } else { - let default_value = this._get_default_metavar_for_optional(action) - let args_string = this._format_args(action, default_value) - for (let option_string of action.option_strings) { - parts.push(sub('%s %s', option_string, args_string)) - } - } - - return parts.join(', ') - } - } - - _metavar_formatter(action, default_metavar) { - let result - if (action.metavar !== undefined) { - result = action.metavar - } else if (action.choices !== undefined) { - let choice_strs = _choices_to_array(action.choices).map(String) - result = sub('{%s}', choice_strs.join(',')) - } else { - result = default_metavar - } - - function format(tuple_size) { - if (Array.isArray(result)) { - return result - } else { - return Array(tuple_size).fill(result) - } - } - return format - } - - _format_args(action, default_metavar) { - let get_metavar = this._metavar_formatter(action, default_metavar) - let result - if (action.nargs === undefined) { - result = sub('%s', ...get_metavar(1)) - } else if (action.nargs === OPTIONAL) { - result = sub('[%s]', ...get_metavar(1)) - } else if (action.nargs === ZERO_OR_MORE) { - let metavar = get_metavar(1) - if (metavar.length === 2) { - result = sub('[%s [%s ...]]', ...metavar) - } else { - result = sub('[%s ...]', ...metavar) - } - } else if (action.nargs === ONE_OR_MORE) { - result = sub('%s [%s ...]', ...get_metavar(2)) - } else if (action.nargs === REMAINDER) { - result = '...' - } else if (action.nargs === PARSER) { - result = sub('%s ...', ...get_metavar(1)) - } else if (action.nargs === SUPPRESS) { - result = '' - } else { - let formats - try { - formats = range(action.nargs).map(() => '%s') - } catch (err) { - throw new TypeError('invalid nargs value') - } - result = sub(formats.join(' '), ...get_metavar(action.nargs)) - } - return result - } - - _expand_help(action) { - let params = Object.assign({ prog: this._prog }, action) - for (let name of Object.keys(params)) { - if (params[name] === SUPPRESS) { - delete params[name] - } - } - for (let name of Object.keys(params)) { - if (params[name] && params[name].name) { - params[name] = params[name].name - } - } - if (params.choices !== undefined) { - let choices_str = _choices_to_array(params.choices).map(String).join(', ') - params.choices = choices_str - } - // LEGACY (v1 compatibility): camelcase - for (let key of Object.keys(params)) { - let old_name = _to_legacy_name(key) - if (old_name !== key) { - params[old_name] = params[key] - } - } - // end - return sub(this._get_help_string(action), params) - } - - * _iter_indented_subactions(action) { - if (typeof action._get_subactions === 'function') { - this._indent() - yield* action._get_subactions() - this._dedent() - } - } - - _split_lines(text, width) { - text = text.replace(this._whitespace_matcher, ' ').trim() - // The textwrap module is used only for formatting help. - // Delay its import for speeding up the common usage of argparse. - let textwrap = require('./lib/textwrap') - return textwrap.wrap(text, { width }) - } - - _fill_text(text, width, indent) { - text = text.replace(this._whitespace_matcher, ' ').trim() - let textwrap = require('./lib/textwrap') - return textwrap.fill(text, { width, - initial_indent: indent, - subsequent_indent: indent }) - } - - _get_help_string(action) { - return action.help - } - - _get_default_metavar_for_optional(action) { - return action.dest.toUpperCase() - } - - _get_default_metavar_for_positional(action) { - return action.dest - } -})) - -HelpFormatter.prototype._Section = _callable(class _Section { - - constructor(formatter, parent, heading = undefined) { - this.formatter = formatter - this.parent = parent - this.heading = heading - this.items = [] - } - - format_help() { - // format the indented section - if (this.parent !== undefined) { - this.formatter._indent() - } - let item_help = this.formatter._join_parts(this.items.map(([ func, args ]) => func.apply(null, args))) - if (this.parent !== undefined) { - this.formatter._dedent() - } - - // return nothing if the section was empty - if (!item_help) { - return '' - } - - // add the heading if the section was non-empty - let heading - if (this.heading !== SUPPRESS && this.heading !== undefined) { - let current_indent = this.formatter._current_indent - heading = sub('%*s%s:\n', current_indent, '', this.heading) - } else { - heading = '' - } - - // join the section-initial newline, the heading and the help - return this.formatter._join_parts(['\n', heading, item_help, '\n']) - } -}) - - -const RawDescriptionHelpFormatter = _camelcase_alias(_callable(class RawDescriptionHelpFormatter extends HelpFormatter { - /* - * Help message formatter which retains any formatting in descriptions. - * - * Only the name of this class is considered a public API. All the methods - * provided by the class are considered an implementation detail. - */ - - _fill_text(text, width, indent) { - return splitlines(text, true).map(line => indent + line).join('') - } -})) - - -const RawTextHelpFormatter = _camelcase_alias(_callable(class RawTextHelpFormatter extends RawDescriptionHelpFormatter { - /* - * Help message formatter which retains formatting of all help text. - * - * Only the name of this class is considered a public API. All the methods - * provided by the class are considered an implementation detail. - */ - - _split_lines(text/*, width*/) { - return splitlines(text) - } -})) - - -const ArgumentDefaultsHelpFormatter = _camelcase_alias(_callable(class ArgumentDefaultsHelpFormatter extends HelpFormatter { - /* - * Help message formatter which adds default values to argument help. - * - * Only the name of this class is considered a public API. All the methods - * provided by the class are considered an implementation detail. - */ - - _get_help_string(action) { - let help = action.help - // LEGACY (v1 compatibility): additional check for defaultValue needed - if (!action.help.includes('%(default)') && !action.help.includes('%(defaultValue)')) { - if (action.default !== SUPPRESS) { - let defaulting_nargs = [OPTIONAL, ZERO_OR_MORE] - if (action.option_strings.length || defaulting_nargs.includes(action.nargs)) { - help += ' (default: %(default)s)' - } - } - } - return help - } -})) - - -const MetavarTypeHelpFormatter = _camelcase_alias(_callable(class MetavarTypeHelpFormatter extends HelpFormatter { - /* - * Help message formatter which uses the argument 'type' as the default - * metavar value (instead of the argument 'dest') - * - * Only the name of this class is considered a public API. All the methods - * provided by the class are considered an implementation detail. - */ - - _get_default_metavar_for_optional(action) { - return typeof action.type === 'function' ? action.type.name : action.type - } - - _get_default_metavar_for_positional(action) { - return typeof action.type === 'function' ? action.type.name : action.type - } -})) - - -// ===================== -// Options and Arguments -// ===================== -function _get_action_name(argument) { - if (argument === undefined) { - return undefined - } else if (argument.option_strings.length) { - return argument.option_strings.join('/') - } else if (![ undefined, SUPPRESS ].includes(argument.metavar)) { - return argument.metavar - } else if (![ undefined, SUPPRESS ].includes(argument.dest)) { - return argument.dest - } else { - return undefined - } -} - - -const ArgumentError = _callable(class ArgumentError extends Error { - /* - * An error from creating or using an argument (optional or positional). - * - * The string value of this exception is the message, augmented with - * information about the argument that caused it. - */ - - constructor(argument, message) { - super() - this.name = 'ArgumentError' - this._argument_name = _get_action_name(argument) - this._message = message - this.message = this.str() - } - - str() { - let format - if (this._argument_name === undefined) { - format = '%(message)s' - } else { - format = 'argument %(argument_name)s: %(message)s' - } - return sub(format, { message: this._message, - argument_name: this._argument_name }) - } -}) - - -const ArgumentTypeError = _callable(class ArgumentTypeError extends Error { - /* - * An error from trying to convert a command line string to a type. - */ - - constructor(message) { - super(message) - this.name = 'ArgumentTypeError' - } -}) - - -// ============== -// Action classes -// ============== -const Action = _camelcase_alias(_callable(class Action extends _AttributeHolder(Function) { - /* - * Information about how to convert command line strings to Python objects. - * - * Action objects are used by an ArgumentParser to represent the information - * needed to parse a single argument from one or more strings from the - * command line. The keyword arguments to the Action constructor are also - * all attributes of Action instances. - * - * Keyword Arguments: - * - * - option_strings -- A list of command-line option strings which - * should be associated with this action. - * - * - dest -- The name of the attribute to hold the created object(s) - * - * - nargs -- The number of command-line arguments that should be - * consumed. By default, one argument will be consumed and a single - * value will be produced. Other values include: - * - N (an integer) consumes N arguments (and produces a list) - * - '?' consumes zero or one arguments - * - '*' consumes zero or more arguments (and produces a list) - * - '+' consumes one or more arguments (and produces a list) - * Note that the difference between the default and nargs=1 is that - * with the default, a single value will be produced, while with - * nargs=1, a list containing a single value will be produced. - * - * - const -- The value to be produced if the option is specified and the - * option uses an action that takes no values. - * - * - default -- The value to be produced if the option is not specified. - * - * - type -- A callable that accepts a single string argument, and - * returns the converted value. The standard Python types str, int, - * float, and complex are useful examples of such callables. If None, - * str is used. - * - * - choices -- A container of values that should be allowed. If not None, - * after a command-line argument has been converted to the appropriate - * type, an exception will be raised if it is not a member of this - * collection. - * - * - required -- True if the action must always be specified at the - * command line. This is only meaningful for optional command-line - * arguments. - * - * - help -- The help string describing the argument. - * - * - metavar -- The name to be used for the option's argument with the - * help string. If None, the 'dest' value will be used as the name. - */ - - constructor() { - let [ - option_strings, - dest, - nargs, - const_value, - default_value, - type, - choices, - required, - help, - metavar - ] = _parse_opts(arguments, { - option_strings: no_default, - dest: no_default, - nargs: undefined, - const: undefined, - default: undefined, - type: undefined, - choices: undefined, - required: false, - help: undefined, - metavar: undefined - }) - - // when this class is called as a function, redirect it to .call() method of itself - super('return arguments.callee.call.apply(arguments.callee, arguments)') - - this.option_strings = option_strings - this.dest = dest - this.nargs = nargs - this.const = const_value - this.default = default_value - this.type = type - this.choices = choices - this.required = required - this.help = help - this.metavar = metavar - } - - _get_kwargs() { - let names = [ - 'option_strings', - 'dest', - 'nargs', - 'const', - 'default', - 'type', - 'choices', - 'help', - 'metavar' - ] - return names.map(name => [ name, getattr(this, name) ]) - } - - format_usage() { - return this.option_strings[0] - } - - call(/*parser, namespace, values, option_string = undefined*/) { - throw new Error('.call() not defined') - } -})) - - -const BooleanOptionalAction = _camelcase_alias(_callable(class BooleanOptionalAction extends Action { - - constructor() { - let [ - option_strings, - dest, - default_value, - type, - choices, - required, - help, - metavar - ] = _parse_opts(arguments, { - option_strings: no_default, - dest: no_default, - default: undefined, - type: undefined, - choices: undefined, - required: false, - help: undefined, - metavar: undefined - }) - - let _option_strings = [] - for (let option_string of option_strings) { - _option_strings.push(option_string) - - if (option_string.startsWith('--')) { - option_string = '--no-' + option_string.slice(2) - _option_strings.push(option_string) - } - } - - if (help !== undefined && default_value !== undefined) { - help += ` (default: ${default_value})` - } - - super({ - option_strings: _option_strings, - dest, - nargs: 0, - default: default_value, - type, - choices, - required, - help, - metavar - }) - } - - call(parser, namespace, values, option_string = undefined) { - if (this.option_strings.includes(option_string)) { - setattr(namespace, this.dest, !option_string.startsWith('--no-')) - } - } - - format_usage() { - return this.option_strings.join(' | ') - } -})) - - -const _StoreAction = _callable(class _StoreAction extends Action { - - constructor() { - let [ - option_strings, - dest, - nargs, - const_value, - default_value, - type, - choices, - required, - help, - metavar - ] = _parse_opts(arguments, { - option_strings: no_default, - dest: no_default, - nargs: undefined, - const: undefined, - default: undefined, - type: undefined, - choices: undefined, - required: false, - help: undefined, - metavar: undefined - }) - - if (nargs === 0) { - throw new TypeError('nargs for store actions must be != 0; if you ' + - 'have nothing to store, actions such as store ' + - 'true or store const may be more appropriate') - } - if (const_value !== undefined && nargs !== OPTIONAL) { - throw new TypeError(sub('nargs must be %r to supply const', OPTIONAL)) - } - super({ - option_strings, - dest, - nargs, - const: const_value, - default: default_value, - type, - choices, - required, - help, - metavar - }) - } - - call(parser, namespace, values/*, option_string = undefined*/) { - setattr(namespace, this.dest, values) - } -}) - - -const _StoreConstAction = _callable(class _StoreConstAction extends Action { - - constructor() { - let [ - option_strings, - dest, - const_value, - default_value, - required, - help - //, metavar - ] = _parse_opts(arguments, { - option_strings: no_default, - dest: no_default, - const: no_default, - default: undefined, - required: false, - help: undefined, - metavar: undefined - }) - - super({ - option_strings, - dest, - nargs: 0, - const: const_value, - default: default_value, - required, - help - }) - } - - call(parser, namespace/*, values, option_string = undefined*/) { - setattr(namespace, this.dest, this.const) - } -}) - - -const _StoreTrueAction = _callable(class _StoreTrueAction extends _StoreConstAction { - - constructor() { - let [ - option_strings, - dest, - default_value, - required, - help - ] = _parse_opts(arguments, { - option_strings: no_default, - dest: no_default, - default: false, - required: false, - help: undefined - }) - - super({ - option_strings, - dest, - const: true, - default: default_value, - required, - help - }) - } -}) - - -const _StoreFalseAction = _callable(class _StoreFalseAction extends _StoreConstAction { - - constructor() { - let [ - option_strings, - dest, - default_value, - required, - help - ] = _parse_opts(arguments, { - option_strings: no_default, - dest: no_default, - default: true, - required: false, - help: undefined - }) - - super({ - option_strings, - dest, - const: false, - default: default_value, - required, - help - }) - } -}) - - -const _AppendAction = _callable(class _AppendAction extends Action { - - constructor() { - let [ - option_strings, - dest, - nargs, - const_value, - default_value, - type, - choices, - required, - help, - metavar - ] = _parse_opts(arguments, { - option_strings: no_default, - dest: no_default, - nargs: undefined, - const: undefined, - default: undefined, - type: undefined, - choices: undefined, - required: false, - help: undefined, - metavar: undefined - }) - - if (nargs === 0) { - throw new TypeError('nargs for append actions must be != 0; if arg ' + - 'strings are not supplying the value to append, ' + - 'the append const action may be more appropriate') - } - if (const_value !== undefined && nargs !== OPTIONAL) { - throw new TypeError(sub('nargs must be %r to supply const', OPTIONAL)) - } - super({ - option_strings, - dest, - nargs, - const: const_value, - default: default_value, - type, - choices, - required, - help, - metavar - }) - } - - call(parser, namespace, values/*, option_string = undefined*/) { - let items = getattr(namespace, this.dest, undefined) - items = _copy_items(items) - items.push(values) - setattr(namespace, this.dest, items) - } -}) - - -const _AppendConstAction = _callable(class _AppendConstAction extends Action { - - constructor() { - let [ - option_strings, - dest, - const_value, - default_value, - required, - help, - metavar - ] = _parse_opts(arguments, { - option_strings: no_default, - dest: no_default, - const: no_default, - default: undefined, - required: false, - help: undefined, - metavar: undefined - }) - - super({ - option_strings, - dest, - nargs: 0, - const: const_value, - default: default_value, - required, - help, - metavar - }) - } - - call(parser, namespace/*, values, option_string = undefined*/) { - let items = getattr(namespace, this.dest, undefined) - items = _copy_items(items) - items.push(this.const) - setattr(namespace, this.dest, items) - } -}) - - -const _CountAction = _callable(class _CountAction extends Action { - - constructor() { - let [ - option_strings, - dest, - default_value, - required, - help - ] = _parse_opts(arguments, { - option_strings: no_default, - dest: no_default, - default: undefined, - required: false, - help: undefined - }) - - super({ - option_strings, - dest, - nargs: 0, - default: default_value, - required, - help - }) - } - - call(parser, namespace/*, values, option_string = undefined*/) { - let count = getattr(namespace, this.dest, undefined) - if (count === undefined) { - count = 0 - } - setattr(namespace, this.dest, count + 1) - } -}) - - -const _HelpAction = _callable(class _HelpAction extends Action { - - constructor() { - let [ - option_strings, - dest, - default_value, - help - ] = _parse_opts(arguments, { - option_strings: no_default, - dest: SUPPRESS, - default: SUPPRESS, - help: undefined - }) - - super({ - option_strings, - dest, - default: default_value, - nargs: 0, - help - }) - } - - call(parser/*, namespace, values, option_string = undefined*/) { - parser.print_help() - parser.exit() - } -}) - - -const _VersionAction = _callable(class _VersionAction extends Action { - - constructor() { - let [ - option_strings, - version, - dest, - default_value, - help - ] = _parse_opts(arguments, { - option_strings: no_default, - version: undefined, - dest: SUPPRESS, - default: SUPPRESS, - help: "show program's version number and exit" - }) - - super({ - option_strings, - dest, - default: default_value, - nargs: 0, - help - }) - this.version = version - } - - call(parser/*, namespace, values, option_string = undefined*/) { - let version = this.version - if (version === undefined) { - version = parser.version - } - let formatter = parser._get_formatter() - formatter.add_text(version) - parser._print_message(formatter.format_help(), process.stdout) - parser.exit() - } -}) - - -const _SubParsersAction = _camelcase_alias(_callable(class _SubParsersAction extends Action { - - constructor() { - let [ - option_strings, - prog, - parser_class, - dest, - required, - help, - metavar - ] = _parse_opts(arguments, { - option_strings: no_default, - prog: no_default, - parser_class: no_default, - dest: SUPPRESS, - required: false, - help: undefined, - metavar: undefined - }) - - let name_parser_map = {} - - super({ - option_strings, - dest, - nargs: PARSER, - choices: name_parser_map, - required, - help, - metavar - }) - - this._prog_prefix = prog - this._parser_class = parser_class - this._name_parser_map = name_parser_map - this._choices_actions = [] - } - - add_parser() { - let [ - name, - kwargs - ] = _parse_opts(arguments, { - name: no_default, - '**kwargs': no_default - }) - - // set prog from the existing prefix - if (kwargs.prog === undefined) { - kwargs.prog = sub('%s %s', this._prog_prefix, name) - } - - let aliases = getattr(kwargs, 'aliases', []) - delete kwargs.aliases - - // create a pseudo-action to hold the choice help - if ('help' in kwargs) { - let help = kwargs.help - delete kwargs.help - let choice_action = this._ChoicesPseudoAction(name, aliases, help) - this._choices_actions.push(choice_action) - } - - // create the parser and add it to the map - let parser = new this._parser_class(kwargs) - this._name_parser_map[name] = parser - - // make parser available under aliases also - for (let alias of aliases) { - this._name_parser_map[alias] = parser - } - - return parser - } - - _get_subactions() { - return this._choices_actions - } - - call(parser, namespace, values/*, option_string = undefined*/) { - let parser_name = values[0] - let arg_strings = values.slice(1) - - // set the parser name if requested - if (this.dest !== SUPPRESS) { - setattr(namespace, this.dest, parser_name) - } - - // select the parser - if (hasattr(this._name_parser_map, parser_name)) { - parser = this._name_parser_map[parser_name] - } else { - let args = {parser_name, - choices: this._name_parser_map.join(', ')} - let msg = sub('unknown parser %(parser_name)r (choices: %(choices)s)', args) - throw new ArgumentError(this, msg) - } - - // parse all the remaining options into the namespace - // store any unrecognized options on the object, so that the top - // level parser can decide what to do with them - - // In case this subparser defines new defaults, we parse them - // in a new namespace object and then update the original - // namespace for the relevant parts. - let subnamespace - [ subnamespace, arg_strings ] = parser.parse_known_args(arg_strings, undefined) - for (let [ key, value ] of Object.entries(subnamespace)) { - setattr(namespace, key, value) - } - - if (arg_strings.length) { - setdefault(namespace, _UNRECOGNIZED_ARGS_ATTR, []) - getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).push(...arg_strings) - } - } -})) - - -_SubParsersAction.prototype._ChoicesPseudoAction = _callable(class _ChoicesPseudoAction extends Action { - constructor(name, aliases, help) { - let metavar = name, dest = name - if (aliases.length) { - metavar += sub(' (%s)', aliases.join(', ')) - } - super({ option_strings: [], dest, help, metavar }) - } -}) - - -const _ExtendAction = _callable(class _ExtendAction extends _AppendAction { - call(parser, namespace, values/*, option_string = undefined*/) { - let items = getattr(namespace, this.dest, undefined) - items = _copy_items(items) - items = items.concat(values) - setattr(namespace, this.dest, items) - } -}) - - -// ============== -// Type classes -// ============== -const FileType = _callable(class FileType extends Function { - /* - * Factory for creating file object types - * - * Instances of FileType are typically passed as type= arguments to the - * ArgumentParser add_argument() method. - * - * Keyword Arguments: - * - mode -- A string indicating how the file is to be opened. Accepts the - * same values as the builtin open() function. - * - bufsize -- The file's desired buffer size. Accepts the same values as - * the builtin open() function. - * - encoding -- The file's encoding. Accepts the same values as the - * builtin open() function. - * - errors -- A string indicating how encoding and decoding errors are to - * be handled. Accepts the same value as the builtin open() function. - */ - - constructor() { - let [ - flags, - encoding, - mode, - autoClose, - emitClose, - start, - end, - highWaterMark, - fs - ] = _parse_opts(arguments, { - flags: 'r', - encoding: undefined, - mode: undefined, // 0o666 - autoClose: undefined, // true - emitClose: undefined, // false - start: undefined, // 0 - end: undefined, // Infinity - highWaterMark: undefined, // 64 * 1024 - fs: undefined - }) - - // when this class is called as a function, redirect it to .call() method of itself - super('return arguments.callee.call.apply(arguments.callee, arguments)') - - Object.defineProperty(this, 'name', { - get() { - return sub('FileType(%r)', flags) - } - }) - this._flags = flags - this._options = {} - if (encoding !== undefined) this._options.encoding = encoding - if (mode !== undefined) this._options.mode = mode - if (autoClose !== undefined) this._options.autoClose = autoClose - if (emitClose !== undefined) this._options.emitClose = emitClose - if (start !== undefined) this._options.start = start - if (end !== undefined) this._options.end = end - if (highWaterMark !== undefined) this._options.highWaterMark = highWaterMark - if (fs !== undefined) this._options.fs = fs - } - - call(string) { - // the special argument "-" means sys.std{in,out} - if (string === '-') { - if (this._flags.includes('r')) { - return process.stdin - } else if (this._flags.includes('w')) { - return process.stdout - } else { - let msg = sub('argument "-" with mode %r', this._flags) - throw new TypeError(msg) - } - } - - // all other arguments are used as file names - let fd - try { - fd = fs.openSync(string, this._flags, this._options.mode) - } catch (e) { - let args = { filename: string, error: e.message } - let message = "can't open '%(filename)s': %(error)s" - throw new ArgumentTypeError(sub(message, args)) - } - - let options = Object.assign({ fd, flags: this._flags }, this._options) - if (this._flags.includes('r')) { - return fs.createReadStream(undefined, options) - } else if (this._flags.includes('w')) { - return fs.createWriteStream(undefined, options) - } else { - let msg = sub('argument "%s" with mode %r', string, this._flags) - throw new TypeError(msg) - } - } - - [util.inspect.custom]() { - let args = [ this._flags ] - let kwargs = Object.entries(this._options).map(([ k, v ]) => { - if (k === 'mode') v = { value: v, [util.inspect.custom]() { return '0o' + this.value.toString(8) } } - return [ k, v ] - }) - let args_str = [] - .concat(args.filter(arg => arg !== -1).map(repr)) - .concat(kwargs.filter(([/*kw*/, arg]) => arg !== undefined) - .map(([kw, arg]) => sub('%s=%r', kw, arg))) - .join(', ') - return sub('%s(%s)', this.constructor.name, args_str) - } - - toString() { - return this[util.inspect.custom]() - } -}) - -// =========================== -// Optional and Positional Parsing -// =========================== -const Namespace = _callable(class Namespace extends _AttributeHolder() { - /* - * Simple object for storing attributes. - * - * Implements equality by attribute names and values, and provides a simple - * string representation. - */ - - constructor(options = {}) { - super() - Object.assign(this, options) - } -}) - -// unset string tag to mimic plain object -Namespace.prototype[Symbol.toStringTag] = undefined - - -const _ActionsContainer = _camelcase_alias(_callable(class _ActionsContainer { - - constructor() { - let [ - description, - prefix_chars, - argument_default, - conflict_handler - ] = _parse_opts(arguments, { - description: no_default, - prefix_chars: no_default, - argument_default: no_default, - conflict_handler: no_default - }) - - this.description = description - this.argument_default = argument_default - this.prefix_chars = prefix_chars - this.conflict_handler = conflict_handler - - // set up registries - this._registries = {} - - // register actions - this.register('action', undefined, _StoreAction) - this.register('action', 'store', _StoreAction) - this.register('action', 'store_const', _StoreConstAction) - this.register('action', 'store_true', _StoreTrueAction) - this.register('action', 'store_false', _StoreFalseAction) - this.register('action', 'append', _AppendAction) - this.register('action', 'append_const', _AppendConstAction) - this.register('action', 'count', _CountAction) - this.register('action', 'help', _HelpAction) - this.register('action', 'version', _VersionAction) - this.register('action', 'parsers', _SubParsersAction) - this.register('action', 'extend', _ExtendAction) - // LEGACY (v1 compatibility): camelcase variants - ;[ 'storeConst', 'storeTrue', 'storeFalse', 'appendConst' ].forEach(old_name => { - let new_name = _to_new_name(old_name) - this.register('action', old_name, util.deprecate(this._registry_get('action', new_name), - sub('{action: "%s"} is renamed to {action: "%s"}', old_name, new_name))) - }) - // end - - // raise an exception if the conflict handler is invalid - this._get_handler() - - // action storage - this._actions = [] - this._option_string_actions = {} - - // groups - this._action_groups = [] - this._mutually_exclusive_groups = [] - - // defaults storage - this._defaults = {} - - // determines whether an "option" looks like a negative number - this._negative_number_matcher = /^-\d+$|^-\d*\.\d+$/ - - // whether or not there are any optionals that look like negative - // numbers -- uses a list so it can be shared and edited - this._has_negative_number_optionals = [] - } - - // ==================== - // Registration methods - // ==================== - register(registry_name, value, object) { - let registry = setdefault(this._registries, registry_name, {}) - registry[value] = object - } - - _registry_get(registry_name, value, default_value = undefined) { - return getattr(this._registries[registry_name], value, default_value) - } - - // ================================== - // Namespace default accessor methods - // ================================== - set_defaults(kwargs) { - Object.assign(this._defaults, kwargs) - - // if these defaults match any existing arguments, replace - // the previous default on the object with the new one - for (let action of this._actions) { - if (action.dest in kwargs) { - action.default = kwargs[action.dest] - } - } - } - - get_default(dest) { - for (let action of this._actions) { - if (action.dest === dest && action.default !== undefined) { - return action.default - } - } - return this._defaults[dest] - } - - - // ======================= - // Adding argument actions - // ======================= - add_argument() { - /* - * add_argument(dest, ..., name=value, ...) - * add_argument(option_string, option_string, ..., name=value, ...) - */ - let [ - args, - kwargs - ] = _parse_opts(arguments, { - '*args': no_default, - '**kwargs': no_default - }) - // LEGACY (v1 compatibility), old-style add_argument([ args ], { options }) - if (args.length === 1 && Array.isArray(args[0])) { - args = args[0] - deprecate('argument-array', - sub('use add_argument(%(args)s, {...}) instead of add_argument([ %(args)s ], { ... })', { - args: args.map(repr).join(', ') - })) - } - // end - - // if no positional args are supplied or only one is supplied and - // it doesn't look like an option string, parse a positional - // argument - let chars = this.prefix_chars - if (!args.length || args.length === 1 && !chars.includes(args[0][0])) { - if (args.length && 'dest' in kwargs) { - throw new TypeError('dest supplied twice for positional argument') - } - kwargs = this._get_positional_kwargs(...args, kwargs) - - // otherwise, we're adding an optional argument - } else { - kwargs = this._get_optional_kwargs(...args, kwargs) - } - - // if no default was supplied, use the parser-level default - if (!('default' in kwargs)) { - let dest = kwargs.dest - if (dest in this._defaults) { - kwargs.default = this._defaults[dest] - } else if (this.argument_default !== undefined) { - kwargs.default = this.argument_default - } - } - - // create the action object, and add it to the parser - let action_class = this._pop_action_class(kwargs) - if (typeof action_class !== 'function') { - throw new TypeError(sub('unknown action "%s"', action_class)) - } - // eslint-disable-next-line new-cap - let action = new action_class(kwargs) - - // raise an error if the action type is not callable - let type_func = this._registry_get('type', action.type, action.type) - if (typeof type_func !== 'function') { - throw new TypeError(sub('%r is not callable', type_func)) - } - - if (type_func === FileType) { - throw new TypeError(sub('%r is a FileType class object, instance of it' + - ' must be passed', type_func)) - } - - // raise an error if the metavar does not match the type - if ('_get_formatter' in this) { - try { - this._get_formatter()._format_args(action, undefined) - } catch (err) { - // check for 'invalid nargs value' is an artifact of TypeError and ValueError in js being the same - if (err instanceof TypeError && err.message !== 'invalid nargs value') { - throw new TypeError('length of metavar tuple does not match nargs') - } else { - throw err - } - } - } - - return this._add_action(action) - } - - add_argument_group() { - let group = _ArgumentGroup(this, ...arguments) - this._action_groups.push(group) - return group - } - - add_mutually_exclusive_group() { - // eslint-disable-next-line no-use-before-define - let group = _MutuallyExclusiveGroup(this, ...arguments) - this._mutually_exclusive_groups.push(group) - return group - } - - _add_action(action) { - // resolve any conflicts - this._check_conflict(action) - - // add to actions list - this._actions.push(action) - action.container = this - - // index the action by any option strings it has - for (let option_string of action.option_strings) { - this._option_string_actions[option_string] = action - } - - // set the flag if any option strings look like negative numbers - for (let option_string of action.option_strings) { - if (this._negative_number_matcher.test(option_string)) { - if (!this._has_negative_number_optionals.length) { - this._has_negative_number_optionals.push(true) - } - } - } - - // return the created action - return action - } - - _remove_action(action) { - _array_remove(this._actions, action) - } - - _add_container_actions(container) { - // collect groups by titles - let title_group_map = {} - for (let group of this._action_groups) { - if (group.title in title_group_map) { - let msg = 'cannot merge actions - two groups are named %r' - throw new TypeError(sub(msg, group.title)) - } - title_group_map[group.title] = group - } - - // map each action to its group - let group_map = new Map() - for (let group of container._action_groups) { - - // if a group with the title exists, use that, otherwise - // create a new group matching the container's group - if (!(group.title in title_group_map)) { - title_group_map[group.title] = this.add_argument_group({ - title: group.title, - description: group.description, - conflict_handler: group.conflict_handler - }) - } - - // map the actions to their new group - for (let action of group._group_actions) { - group_map.set(action, title_group_map[group.title]) - } - } - - // add container's mutually exclusive groups - // NOTE: if add_mutually_exclusive_group ever gains title= and - // description= then this code will need to be expanded as above - for (let group of container._mutually_exclusive_groups) { - let mutex_group = this.add_mutually_exclusive_group({ - required: group.required - }) - - // map the actions to their new mutex group - for (let action of group._group_actions) { - group_map.set(action, mutex_group) - } - } - - // add all actions to this container or their group - for (let action of container._actions) { - group_map.get(action)._add_action(action) - } - } - - _get_positional_kwargs() { - let [ - dest, - kwargs - ] = _parse_opts(arguments, { - dest: no_default, - '**kwargs': no_default - }) - - // make sure required is not specified - if ('required' in kwargs) { - let msg = "'required' is an invalid argument for positionals" - throw new TypeError(msg) - } - - // mark positional arguments as required if at least one is - // always required - if (![OPTIONAL, ZERO_OR_MORE].includes(kwargs.nargs)) { - kwargs.required = true - } - if (kwargs.nargs === ZERO_OR_MORE && !('default' in kwargs)) { - kwargs.required = true - } - - // return the keyword arguments with no option strings - return Object.assign(kwargs, { dest, option_strings: [] }) - } - - _get_optional_kwargs() { - let [ - args, - kwargs - ] = _parse_opts(arguments, { - '*args': no_default, - '**kwargs': no_default - }) - - // determine short and long option strings - let option_strings = [] - let long_option_strings = [] - let option_string - for (option_string of args) { - // error on strings that don't start with an appropriate prefix - if (!this.prefix_chars.includes(option_string[0])) { - let args = {option: option_string, - prefix_chars: this.prefix_chars} - let msg = 'invalid option string %(option)r: ' + - 'must start with a character %(prefix_chars)r' - throw new TypeError(sub(msg, args)) - } - - // strings starting with two prefix characters are long options - option_strings.push(option_string) - if (option_string.length > 1 && this.prefix_chars.includes(option_string[1])) { - long_option_strings.push(option_string) - } - } - - // infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x' - let dest = kwargs.dest - delete kwargs.dest - if (dest === undefined) { - let dest_option_string - if (long_option_strings.length) { - dest_option_string = long_option_strings[0] - } else { - dest_option_string = option_strings[0] - } - dest = _string_lstrip(dest_option_string, this.prefix_chars) - if (!dest) { - let msg = 'dest= is required for options like %r' - throw new TypeError(sub(msg, option_string)) - } - dest = dest.replace(/-/g, '_') - } - - // return the updated keyword arguments - return Object.assign(kwargs, { dest, option_strings }) - } - - _pop_action_class(kwargs, default_value = undefined) { - let action = getattr(kwargs, 'action', default_value) - delete kwargs.action - return this._registry_get('action', action, action) - } - - _get_handler() { - // determine function from conflict handler string - let handler_func_name = sub('_handle_conflict_%s', this.conflict_handler) - if (typeof this[handler_func_name] === 'function') { - return this[handler_func_name] - } else { - let msg = 'invalid conflict_resolution value: %r' - throw new TypeError(sub(msg, this.conflict_handler)) - } - } - - _check_conflict(action) { - - // find all options that conflict with this option - let confl_optionals = [] - for (let option_string of action.option_strings) { - if (hasattr(this._option_string_actions, option_string)) { - let confl_optional = this._option_string_actions[option_string] - confl_optionals.push([ option_string, confl_optional ]) - } - } - - // resolve any conflicts - if (confl_optionals.length) { - let conflict_handler = this._get_handler() - conflict_handler.call(this, action, confl_optionals) - } - } - - _handle_conflict_error(action, conflicting_actions) { - let message = conflicting_actions.length === 1 ? - 'conflicting option string: %s' : - 'conflicting option strings: %s' - let conflict_string = conflicting_actions.map(([ option_string/*, action*/ ]) => option_string).join(', ') - throw new ArgumentError(action, sub(message, conflict_string)) - } - - _handle_conflict_resolve(action, conflicting_actions) { - - // remove all conflicting options - for (let [ option_string, action ] of conflicting_actions) { - - // remove the conflicting option - _array_remove(action.option_strings, option_string) - delete this._option_string_actions[option_string] - - // if the option now has no option string, remove it from the - // container holding it - if (!action.option_strings.length) { - action.container._remove_action(action) - } - } - } -})) - - -const _ArgumentGroup = _callable(class _ArgumentGroup extends _ActionsContainer { - - constructor() { - let [ - container, - title, - description, - kwargs - ] = _parse_opts(arguments, { - container: no_default, - title: undefined, - description: undefined, - '**kwargs': no_default - }) - - // add any missing keyword arguments by checking the container - setdefault(kwargs, 'conflict_handler', container.conflict_handler) - setdefault(kwargs, 'prefix_chars', container.prefix_chars) - setdefault(kwargs, 'argument_default', container.argument_default) - super(Object.assign({ description }, kwargs)) - - // group attributes - this.title = title - this._group_actions = [] - - // share most attributes with the container - this._registries = container._registries - this._actions = container._actions - this._option_string_actions = container._option_string_actions - this._defaults = container._defaults - this._has_negative_number_optionals = - container._has_negative_number_optionals - this._mutually_exclusive_groups = container._mutually_exclusive_groups - } - - _add_action(action) { - action = super._add_action(action) - this._group_actions.push(action) - return action - } - - _remove_action(action) { - super._remove_action(action) - _array_remove(this._group_actions, action) - } -}) - - -const _MutuallyExclusiveGroup = _callable(class _MutuallyExclusiveGroup extends _ArgumentGroup { - - constructor() { - let [ - container, - required - ] = _parse_opts(arguments, { - container: no_default, - required: false - }) - - super(container) - this.required = required - this._container = container - } - - _add_action(action) { - if (action.required) { - let msg = 'mutually exclusive arguments must be optional' - throw new TypeError(msg) - } - action = this._container._add_action(action) - this._group_actions.push(action) - return action - } - - _remove_action(action) { - this._container._remove_action(action) - _array_remove(this._group_actions, action) - } -}) - - -const ArgumentParser = _camelcase_alias(_callable(class ArgumentParser extends _AttributeHolder(_ActionsContainer) { - /* - * Object for parsing command line strings into Python objects. - * - * Keyword Arguments: - * - prog -- The name of the program (default: sys.argv[0]) - * - usage -- A usage message (default: auto-generated from arguments) - * - description -- A description of what the program does - * - epilog -- Text following the argument descriptions - * - parents -- Parsers whose arguments should be copied into this one - * - formatter_class -- HelpFormatter class for printing help messages - * - prefix_chars -- Characters that prefix optional arguments - * - fromfile_prefix_chars -- Characters that prefix files containing - * additional arguments - * - argument_default -- The default value for all arguments - * - conflict_handler -- String indicating how to handle conflicts - * - add_help -- Add a -h/-help option - * - allow_abbrev -- Allow long options to be abbreviated unambiguously - * - exit_on_error -- Determines whether or not ArgumentParser exits with - * error info when an error occurs - */ - - constructor() { - let [ - prog, - usage, - description, - epilog, - parents, - formatter_class, - prefix_chars, - fromfile_prefix_chars, - argument_default, - conflict_handler, - add_help, - allow_abbrev, - exit_on_error, - debug, // LEGACY (v1 compatibility), debug mode - version // LEGACY (v1 compatibility), version - ] = _parse_opts(arguments, { - prog: undefined, - usage: undefined, - description: undefined, - epilog: undefined, - parents: [], - formatter_class: HelpFormatter, - prefix_chars: '-', - fromfile_prefix_chars: undefined, - argument_default: undefined, - conflict_handler: 'error', - add_help: true, - allow_abbrev: true, - exit_on_error: true, - debug: undefined, // LEGACY (v1 compatibility), debug mode - version: undefined // LEGACY (v1 compatibility), version - }) - - // LEGACY (v1 compatibility) - if (debug !== undefined) { - deprecate('debug', - 'The "debug" argument to ArgumentParser is deprecated. Please ' + - 'override ArgumentParser.exit function instead.' - ) - } - - if (version !== undefined) { - deprecate('version', - 'The "version" argument to ArgumentParser is deprecated. Please use ' + - "add_argument(..., { action: 'version', version: 'N', ... }) instead." - ) - } - // end - - super({ - description, - prefix_chars, - argument_default, - conflict_handler - }) - - // default setting for prog - if (prog === undefined) { - prog = path.basename(get_argv()[0] || '') - } - - this.prog = prog - this.usage = usage - this.epilog = epilog - this.formatter_class = formatter_class - this.fromfile_prefix_chars = fromfile_prefix_chars - this.add_help = add_help - this.allow_abbrev = allow_abbrev - this.exit_on_error = exit_on_error - // LEGACY (v1 compatibility), debug mode - this.debug = debug - // end - - this._positionals = this.add_argument_group('positional arguments') - this._optionals = this.add_argument_group('optional arguments') - this._subparsers = undefined - - // register types - function identity(string) { - return string - } - this.register('type', undefined, identity) - this.register('type', null, identity) - this.register('type', 'auto', identity) - this.register('type', 'int', function (x) { - let result = Number(x) - if (!Number.isInteger(result)) { - throw new TypeError(sub('could not convert string to int: %r', x)) - } - return result - }) - this.register('type', 'float', function (x) { - let result = Number(x) - if (isNaN(result)) { - throw new TypeError(sub('could not convert string to float: %r', x)) - } - return result - }) - this.register('type', 'str', String) - // LEGACY (v1 compatibility): custom types - this.register('type', 'string', - util.deprecate(String, 'use {type:"str"} or {type:String} instead of {type:"string"}')) - // end - - // add help argument if necessary - // (using explicit default to override global argument_default) - let default_prefix = prefix_chars.includes('-') ? '-' : prefix_chars[0] - if (this.add_help) { - this.add_argument( - default_prefix + 'h', - default_prefix.repeat(2) + 'help', - { - action: 'help', - default: SUPPRESS, - help: 'show this help message and exit' - } - ) - } - // LEGACY (v1 compatibility), version - if (version) { - this.add_argument( - default_prefix + 'v', - default_prefix.repeat(2) + 'version', - { - action: 'version', - default: SUPPRESS, - version: this.version, - help: "show program's version number and exit" - } - ) - } - // end - - // add parent arguments and defaults - for (let parent of parents) { - this._add_container_actions(parent) - Object.assign(this._defaults, parent._defaults) - } - } - - // ======================= - // Pretty __repr__ methods - // ======================= - _get_kwargs() { - let names = [ - 'prog', - 'usage', - 'description', - 'formatter_class', - 'conflict_handler', - 'add_help' - ] - return names.map(name => [ name, getattr(this, name) ]) - } - - // ================================== - // Optional/Positional adding methods - // ================================== - add_subparsers() { - let [ - kwargs - ] = _parse_opts(arguments, { - '**kwargs': no_default - }) - - if (this._subparsers !== undefined) { - this.error('cannot have multiple subparser arguments') - } - - // add the parser class to the arguments if it's not present - setdefault(kwargs, 'parser_class', this.constructor) - - if ('title' in kwargs || 'description' in kwargs) { - let title = getattr(kwargs, 'title', 'subcommands') - let description = getattr(kwargs, 'description', undefined) - delete kwargs.title - delete kwargs.description - this._subparsers = this.add_argument_group(title, description) - } else { - this._subparsers = this._positionals - } - - // prog defaults to the usage message of this parser, skipping - // optional arguments and with no "usage:" prefix - if (kwargs.prog === undefined) { - let formatter = this._get_formatter() - let positionals = this._get_positional_actions() - let groups = this._mutually_exclusive_groups - formatter.add_usage(this.usage, positionals, groups, '') - kwargs.prog = formatter.format_help().trim() - } - - // create the parsers action and add it to the positionals list - let parsers_class = this._pop_action_class(kwargs, 'parsers') - // eslint-disable-next-line new-cap - let action = new parsers_class(Object.assign({ option_strings: [] }, kwargs)) - this._subparsers._add_action(action) - - // return the created parsers action - return action - } - - _add_action(action) { - if (action.option_strings.length) { - this._optionals._add_action(action) - } else { - this._positionals._add_action(action) - } - return action - } - - _get_optional_actions() { - return this._actions.filter(action => action.option_strings.length) - } - - _get_positional_actions() { - return this._actions.filter(action => !action.option_strings.length) - } - - // ===================================== - // Command line argument parsing methods - // ===================================== - parse_args(args = undefined, namespace = undefined) { - let argv - [ args, argv ] = this.parse_known_args(args, namespace) - if (argv && argv.length > 0) { - let msg = 'unrecognized arguments: %s' - this.error(sub(msg, argv.join(' '))) - } - return args - } - - parse_known_args(args = undefined, namespace = undefined) { - if (args === undefined) { - args = get_argv().slice(1) - } - - // default Namespace built from parser defaults - if (namespace === undefined) { - namespace = new Namespace() - } - - // add any action defaults that aren't present - for (let action of this._actions) { - if (action.dest !== SUPPRESS) { - if (!hasattr(namespace, action.dest)) { - if (action.default !== SUPPRESS) { - setattr(namespace, action.dest, action.default) - } - } - } - } - - // add any parser defaults that aren't present - for (let dest of Object.keys(this._defaults)) { - if (!hasattr(namespace, dest)) { - setattr(namespace, dest, this._defaults[dest]) - } - } - - // parse the arguments and exit if there are any errors - if (this.exit_on_error) { - try { - [ namespace, args ] = this._parse_known_args(args, namespace) - } catch (err) { - if (err instanceof ArgumentError) { - this.error(err.message) - } else { - throw err - } - } - } else { - [ namespace, args ] = this._parse_known_args(args, namespace) - } - - if (hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) { - args = args.concat(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) - delattr(namespace, _UNRECOGNIZED_ARGS_ATTR) - } - - return [ namespace, args ] - } - - _parse_known_args(arg_strings, namespace) { - // replace arg strings that are file references - if (this.fromfile_prefix_chars !== undefined) { - arg_strings = this._read_args_from_files(arg_strings) - } - - // map all mutually exclusive arguments to the other arguments - // they can't occur with - let action_conflicts = new Map() - for (let mutex_group of this._mutually_exclusive_groups) { - let group_actions = mutex_group._group_actions - for (let [ i, mutex_action ] of Object.entries(mutex_group._group_actions)) { - let conflicts = action_conflicts.get(mutex_action) || [] - conflicts = conflicts.concat(group_actions.slice(0, +i)) - conflicts = conflicts.concat(group_actions.slice(+i + 1)) - action_conflicts.set(mutex_action, conflicts) - } - } - - // find all option indices, and determine the arg_string_pattern - // which has an 'O' if there is an option at an index, - // an 'A' if there is an argument, or a '-' if there is a '--' - let option_string_indices = {} - let arg_string_pattern_parts = [] - let arg_strings_iter = Object.entries(arg_strings)[Symbol.iterator]() - for (let [ i, arg_string ] of arg_strings_iter) { - - // all args after -- are non-options - if (arg_string === '--') { - arg_string_pattern_parts.push('-') - for ([ i, arg_string ] of arg_strings_iter) { - arg_string_pattern_parts.push('A') - } - - // otherwise, add the arg to the arg strings - // and note the index if it was an option - } else { - let option_tuple = this._parse_optional(arg_string) - let pattern - if (option_tuple === undefined) { - pattern = 'A' - } else { - option_string_indices[i] = option_tuple - pattern = 'O' - } - arg_string_pattern_parts.push(pattern) - } - } - - // join the pieces together to form the pattern - let arg_strings_pattern = arg_string_pattern_parts.join('') - - // converts arg strings to the appropriate and then takes the action - let seen_actions = new Set() - let seen_non_default_actions = new Set() - let extras - - let take_action = (action, argument_strings, option_string = undefined) => { - seen_actions.add(action) - let argument_values = this._get_values(action, argument_strings) - - // error if this argument is not allowed with other previously - // seen arguments, assuming that actions that use the default - // value don't really count as "present" - if (argument_values !== action.default) { - seen_non_default_actions.add(action) - for (let conflict_action of action_conflicts.get(action) || []) { - if (seen_non_default_actions.has(conflict_action)) { - let msg = 'not allowed with argument %s' - let action_name = _get_action_name(conflict_action) - throw new ArgumentError(action, sub(msg, action_name)) - } - } - } - - // take the action if we didn't receive a SUPPRESS value - // (e.g. from a default) - if (argument_values !== SUPPRESS) { - action(this, namespace, argument_values, option_string) - } - } - - // function to convert arg_strings into an optional action - let consume_optional = start_index => { - - // get the optional identified at this index - let option_tuple = option_string_indices[start_index] - let [ action, option_string, explicit_arg ] = option_tuple - - // identify additional optionals in the same arg string - // (e.g. -xyz is the same as -x -y -z if no args are required) - let action_tuples = [] - let stop - for (;;) { - - // if we found no optional action, skip it - if (action === undefined) { - extras.push(arg_strings[start_index]) - return start_index + 1 - } - - // if there is an explicit argument, try to match the - // optional's string arguments to only this - if (explicit_arg !== undefined) { - let arg_count = this._match_argument(action, 'A') - - // if the action is a single-dash option and takes no - // arguments, try to parse more single-dash options out - // of the tail of the option string - let chars = this.prefix_chars - if (arg_count === 0 && !chars.includes(option_string[1])) { - action_tuples.push([ action, [], option_string ]) - let char = option_string[0] - option_string = char + explicit_arg[0] - let new_explicit_arg = explicit_arg.slice(1) || undefined - let optionals_map = this._option_string_actions - if (hasattr(optionals_map, option_string)) { - action = optionals_map[option_string] - explicit_arg = new_explicit_arg - } else { - let msg = 'ignored explicit argument %r' - throw new ArgumentError(action, sub(msg, explicit_arg)) - } - - // if the action expect exactly one argument, we've - // successfully matched the option; exit the loop - } else if (arg_count === 1) { - stop = start_index + 1 - let args = [ explicit_arg ] - action_tuples.push([ action, args, option_string ]) - break - - // error if a double-dash option did not use the - // explicit argument - } else { - let msg = 'ignored explicit argument %r' - throw new ArgumentError(action, sub(msg, explicit_arg)) - } - - // if there is no explicit argument, try to match the - // optional's string arguments with the following strings - // if successful, exit the loop - } else { - let start = start_index + 1 - let selected_patterns = arg_strings_pattern.slice(start) - let arg_count = this._match_argument(action, selected_patterns) - stop = start + arg_count - let args = arg_strings.slice(start, stop) - action_tuples.push([ action, args, option_string ]) - break - } - } - - // add the Optional to the list and return the index at which - // the Optional's string args stopped - assert(action_tuples.length) - for (let [ action, args, option_string ] of action_tuples) { - take_action(action, args, option_string) - } - return stop - } - - // the list of Positionals left to be parsed; this is modified - // by consume_positionals() - let positionals = this._get_positional_actions() - - // function to convert arg_strings into positional actions - let consume_positionals = start_index => { - // match as many Positionals as possible - let selected_pattern = arg_strings_pattern.slice(start_index) - let arg_counts = this._match_arguments_partial(positionals, selected_pattern) - - // slice off the appropriate arg strings for each Positional - // and add the Positional and its args to the list - for (let i = 0; i < positionals.length && i < arg_counts.length; i++) { - let action = positionals[i] - let arg_count = arg_counts[i] - let args = arg_strings.slice(start_index, start_index + arg_count) - start_index += arg_count - take_action(action, args) - } - - // slice off the Positionals that we just parsed and return the - // index at which the Positionals' string args stopped - positionals = positionals.slice(arg_counts.length) - return start_index - } - - // consume Positionals and Optionals alternately, until we have - // passed the last option string - extras = [] - let start_index = 0 - let max_option_string_index = Math.max(-1, ...Object.keys(option_string_indices).map(Number)) - while (start_index <= max_option_string_index) { - - // consume any Positionals preceding the next option - let next_option_string_index = Math.min( - // eslint-disable-next-line no-loop-func - ...Object.keys(option_string_indices).map(Number).filter(index => index >= start_index) - ) - if (start_index !== next_option_string_index) { - let positionals_end_index = consume_positionals(start_index) - - // only try to parse the next optional if we didn't consume - // the option string during the positionals parsing - if (positionals_end_index > start_index) { - start_index = positionals_end_index - continue - } else { - start_index = positionals_end_index - } - } - - // if we consumed all the positionals we could and we're not - // at the index of an option string, there were extra arguments - if (!(start_index in option_string_indices)) { - let strings = arg_strings.slice(start_index, next_option_string_index) - extras = extras.concat(strings) - start_index = next_option_string_index - } - - // consume the next optional and any arguments for it - start_index = consume_optional(start_index) - } - - // consume any positionals following the last Optional - let stop_index = consume_positionals(start_index) - - // if we didn't consume all the argument strings, there were extras - extras = extras.concat(arg_strings.slice(stop_index)) - - // make sure all required actions were present and also convert - // action defaults which were not given as arguments - let required_actions = [] - for (let action of this._actions) { - if (!seen_actions.has(action)) { - if (action.required) { - required_actions.push(_get_action_name(action)) - } else { - // Convert action default now instead of doing it before - // parsing arguments to avoid calling convert functions - // twice (which may fail) if the argument was given, but - // only if it was defined already in the namespace - if (action.default !== undefined && - typeof action.default === 'string' && - hasattr(namespace, action.dest) && - action.default === getattr(namespace, action.dest)) { - setattr(namespace, action.dest, - this._get_value(action, action.default)) - } - } - } - } - - if (required_actions.length) { - this.error(sub('the following arguments are required: %s', - required_actions.join(', '))) - } - - // make sure all required groups had one option present - for (let group of this._mutually_exclusive_groups) { - if (group.required) { - let no_actions_used = true - for (let action of group._group_actions) { - if (seen_non_default_actions.has(action)) { - no_actions_used = false - break - } - } - - // if no actions were used, report the error - if (no_actions_used) { - let names = group._group_actions - .filter(action => action.help !== SUPPRESS) - .map(action => _get_action_name(action)) - let msg = 'one of the arguments %s is required' - this.error(sub(msg, names.join(' '))) - } - } - } - - // return the updated namespace and the extra arguments - return [ namespace, extras ] - } - - _read_args_from_files(arg_strings) { - // expand arguments referencing files - let new_arg_strings = [] - for (let arg_string of arg_strings) { - - // for regular arguments, just add them back into the list - if (!arg_string || !this.fromfile_prefix_chars.includes(arg_string[0])) { - new_arg_strings.push(arg_string) - - // replace arguments referencing files with the file content - } else { - try { - let args_file = fs.readFileSync(arg_string.slice(1), 'utf8') - let arg_strings = [] - for (let arg_line of splitlines(args_file)) { - for (let arg of this.convert_arg_line_to_args(arg_line)) { - arg_strings.push(arg) - } - } - arg_strings = this._read_args_from_files(arg_strings) - new_arg_strings = new_arg_strings.concat(arg_strings) - } catch (err) { - this.error(err.message) - } - } - } - - // return the modified argument list - return new_arg_strings - } - - convert_arg_line_to_args(arg_line) { - return [arg_line] - } - - _match_argument(action, arg_strings_pattern) { - // match the pattern for this action to the arg strings - let nargs_pattern = this._get_nargs_pattern(action) - let match = arg_strings_pattern.match(new RegExp('^' + nargs_pattern)) - - // raise an exception if we weren't able to find a match - if (match === null) { - let nargs_errors = { - undefined: 'expected one argument', - [OPTIONAL]: 'expected at most one argument', - [ONE_OR_MORE]: 'expected at least one argument' - } - let msg = nargs_errors[action.nargs] - if (msg === undefined) { - msg = sub(action.nargs === 1 ? 'expected %s argument' : 'expected %s arguments', action.nargs) - } - throw new ArgumentError(action, msg) - } - - // return the number of arguments matched - return match[1].length - } - - _match_arguments_partial(actions, arg_strings_pattern) { - // progressively shorten the actions list by slicing off the - // final actions until we find a match - let result = [] - for (let i of range(actions.length, 0, -1)) { - let actions_slice = actions.slice(0, i) - let pattern = actions_slice.map(action => this._get_nargs_pattern(action)).join('') - let match = arg_strings_pattern.match(new RegExp('^' + pattern)) - if (match !== null) { - result = result.concat(match.slice(1).map(string => string.length)) - break - } - } - - // return the list of arg string counts - return result - } - - _parse_optional(arg_string) { - // if it's an empty string, it was meant to be a positional - if (!arg_string) { - return undefined - } - - // if it doesn't start with a prefix, it was meant to be positional - if (!this.prefix_chars.includes(arg_string[0])) { - return undefined - } - - // if the option string is present in the parser, return the action - if (arg_string in this._option_string_actions) { - let action = this._option_string_actions[arg_string] - return [ action, arg_string, undefined ] - } - - // if it's just a single character, it was meant to be positional - if (arg_string.length === 1) { - return undefined - } - - // if the option string before the "=" is present, return the action - if (arg_string.includes('=')) { - let [ option_string, explicit_arg ] = _string_split(arg_string, '=', 1) - if (option_string in this._option_string_actions) { - let action = this._option_string_actions[option_string] - return [ action, option_string, explicit_arg ] - } - } - - // search through all possible prefixes of the option string - // and all actions in the parser for possible interpretations - let option_tuples = this._get_option_tuples(arg_string) - - // if multiple actions match, the option string was ambiguous - if (option_tuples.length > 1) { - let options = option_tuples.map(([ /*action*/, option_string/*, explicit_arg*/ ]) => option_string).join(', ') - let args = {option: arg_string, matches: options} - let msg = 'ambiguous option: %(option)s could match %(matches)s' - this.error(sub(msg, args)) - - // if exactly one action matched, this segmentation is good, - // so return the parsed action - } else if (option_tuples.length === 1) { - let [ option_tuple ] = option_tuples - return option_tuple - } - - // if it was not found as an option, but it looks like a negative - // number, it was meant to be positional - // unless there are negative-number-like options - if (this._negative_number_matcher.test(arg_string)) { - if (!this._has_negative_number_optionals.length) { - return undefined - } - } - - // if it contains a space, it was meant to be a positional - if (arg_string.includes(' ')) { - return undefined - } - - // it was meant to be an optional but there is no such option - // in this parser (though it might be a valid option in a subparser) - return [ undefined, arg_string, undefined ] - } - - _get_option_tuples(option_string) { - let result = [] - - // option strings starting with two prefix characters are only - // split at the '=' - let chars = this.prefix_chars - if (chars.includes(option_string[0]) && chars.includes(option_string[1])) { - if (this.allow_abbrev) { - let option_prefix, explicit_arg - if (option_string.includes('=')) { - [ option_prefix, explicit_arg ] = _string_split(option_string, '=', 1) - } else { - option_prefix = option_string - explicit_arg = undefined - } - for (let option_string of Object.keys(this._option_string_actions)) { - if (option_string.startsWith(option_prefix)) { - let action = this._option_string_actions[option_string] - let tup = [ action, option_string, explicit_arg ] - result.push(tup) - } - } - } - - // single character options can be concatenated with their arguments - // but multiple character options always have to have their argument - // separate - } else if (chars.includes(option_string[0]) && !chars.includes(option_string[1])) { - let option_prefix = option_string - let explicit_arg = undefined - let short_option_prefix = option_string.slice(0, 2) - let short_explicit_arg = option_string.slice(2) - - for (let option_string of Object.keys(this._option_string_actions)) { - if (option_string === short_option_prefix) { - let action = this._option_string_actions[option_string] - let tup = [ action, option_string, short_explicit_arg ] - result.push(tup) - } else if (option_string.startsWith(option_prefix)) { - let action = this._option_string_actions[option_string] - let tup = [ action, option_string, explicit_arg ] - result.push(tup) - } - } - - // shouldn't ever get here - } else { - this.error(sub('unexpected option string: %s', option_string)) - } - - // return the collected option tuples - return result - } - - _get_nargs_pattern(action) { - // in all examples below, we have to allow for '--' args - // which are represented as '-' in the pattern - let nargs = action.nargs - let nargs_pattern - - // the default (None) is assumed to be a single argument - if (nargs === undefined) { - nargs_pattern = '(-*A-*)' - - // allow zero or one arguments - } else if (nargs === OPTIONAL) { - nargs_pattern = '(-*A?-*)' - - // allow zero or more arguments - } else if (nargs === ZERO_OR_MORE) { - nargs_pattern = '(-*[A-]*)' - - // allow one or more arguments - } else if (nargs === ONE_OR_MORE) { - nargs_pattern = '(-*A[A-]*)' - - // allow any number of options or arguments - } else if (nargs === REMAINDER) { - nargs_pattern = '([-AO]*)' - - // allow one argument followed by any number of options or arguments - } else if (nargs === PARSER) { - nargs_pattern = '(-*A[-AO]*)' - - // suppress action, like nargs=0 - } else if (nargs === SUPPRESS) { - nargs_pattern = '(-*-*)' - - // all others should be integers - } else { - nargs_pattern = sub('(-*%s-*)', 'A'.repeat(nargs).split('').join('-*')) - } - - // if this is an optional action, -- is not allowed - if (action.option_strings.length) { - nargs_pattern = nargs_pattern.replace(/-\*/g, '') - nargs_pattern = nargs_pattern.replace(/-/g, '') - } - - // return the pattern - return nargs_pattern - } - - // ======================== - // Alt command line argument parsing, allowing free intermix - // ======================== - - parse_intermixed_args(args = undefined, namespace = undefined) { - let argv - [ args, argv ] = this.parse_known_intermixed_args(args, namespace) - if (argv.length) { - let msg = 'unrecognized arguments: %s' - this.error(sub(msg, argv.join(' '))) - } - return args - } - - parse_known_intermixed_args(args = undefined, namespace = undefined) { - // returns a namespace and list of extras - // - // positional can be freely intermixed with optionals. optionals are - // first parsed with all positional arguments deactivated. The 'extras' - // are then parsed. If the parser definition is incompatible with the - // intermixed assumptions (e.g. use of REMAINDER, subparsers) a - // TypeError is raised. - // - // positionals are 'deactivated' by setting nargs and default to - // SUPPRESS. This blocks the addition of that positional to the - // namespace - - let extras - let positionals = this._get_positional_actions() - let a = positionals.filter(action => [ PARSER, REMAINDER ].includes(action.nargs)) - if (a.length) { - throw new TypeError(sub('parse_intermixed_args: positional arg' + - ' with nargs=%s', a[0].nargs)) - } - - for (let group of this._mutually_exclusive_groups) { - for (let action of group._group_actions) { - if (positionals.includes(action)) { - throw new TypeError('parse_intermixed_args: positional in' + - ' mutuallyExclusiveGroup') - } - } - } - - let save_usage - try { - save_usage = this.usage - let remaining_args - try { - if (this.usage === undefined) { - // capture the full usage for use in error messages - this.usage = this.format_usage().slice(7) - } - for (let action of positionals) { - // deactivate positionals - action.save_nargs = action.nargs - // action.nargs = 0 - action.nargs = SUPPRESS - action.save_default = action.default - action.default = SUPPRESS - } - [ namespace, remaining_args ] = this.parse_known_args(args, - namespace) - for (let action of positionals) { - // remove the empty positional values from namespace - let attr = getattr(namespace, action.dest) - if (Array.isArray(attr) && attr.length === 0) { - // eslint-disable-next-line no-console - console.warn(sub('Do not expect %s in %s', action.dest, namespace)) - delattr(namespace, action.dest) - } - } - } finally { - // restore nargs and usage before exiting - for (let action of positionals) { - action.nargs = action.save_nargs - action.default = action.save_default - } - } - let optionals = this._get_optional_actions() - try { - // parse positionals. optionals aren't normally required, but - // they could be, so make sure they aren't. - for (let action of optionals) { - action.save_required = action.required - action.required = false - } - for (let group of this._mutually_exclusive_groups) { - group.save_required = group.required - group.required = false - } - [ namespace, extras ] = this.parse_known_args(remaining_args, - namespace) - } finally { - // restore parser values before exiting - for (let action of optionals) { - action.required = action.save_required - } - for (let group of this._mutually_exclusive_groups) { - group.required = group.save_required - } - } - } finally { - this.usage = save_usage - } - return [ namespace, extras ] - } - - // ======================== - // Value conversion methods - // ======================== - _get_values(action, arg_strings) { - // for everything but PARSER, REMAINDER args, strip out first '--' - if (![PARSER, REMAINDER].includes(action.nargs)) { - try { - _array_remove(arg_strings, '--') - } catch (err) {} - } - - let value - // optional argument produces a default when not present - if (!arg_strings.length && action.nargs === OPTIONAL) { - if (action.option_strings.length) { - value = action.const - } else { - value = action.default - } - if (typeof value === 'string') { - value = this._get_value(action, value) - this._check_value(action, value) - } - - // when nargs='*' on a positional, if there were no command-line - // args, use the default if it is anything other than None - } else if (!arg_strings.length && action.nargs === ZERO_OR_MORE && - !action.option_strings.length) { - if (action.default !== undefined) { - value = action.default - } else { - value = arg_strings - } - this._check_value(action, value) - - // single argument or optional argument produces a single value - } else if (arg_strings.length === 1 && [undefined, OPTIONAL].includes(action.nargs)) { - let arg_string = arg_strings[0] - value = this._get_value(action, arg_string) - this._check_value(action, value) - - // REMAINDER arguments convert all values, checking none - } else if (action.nargs === REMAINDER) { - value = arg_strings.map(v => this._get_value(action, v)) - - // PARSER arguments convert all values, but check only the first - } else if (action.nargs === PARSER) { - value = arg_strings.map(v => this._get_value(action, v)) - this._check_value(action, value[0]) - - // SUPPRESS argument does not put anything in the namespace - } else if (action.nargs === SUPPRESS) { - value = SUPPRESS - - // all other types of nargs produce a list - } else { - value = arg_strings.map(v => this._get_value(action, v)) - for (let v of value) { - this._check_value(action, v) - } - } - - // return the converted value - return value - } - - _get_value(action, arg_string) { - let type_func = this._registry_get('type', action.type, action.type) - if (typeof type_func !== 'function') { - let msg = '%r is not callable' - throw new ArgumentError(action, sub(msg, type_func)) - } - - // convert the value to the appropriate type - let result - try { - try { - result = type_func(arg_string) - } catch (err) { - // Dear TC39, why would you ever consider making es6 classes not callable? - // We had one universal interface, [[Call]], which worked for anything - // (with familiar this-instanceof guard for classes). Now we have two. - if (err instanceof TypeError && - /Class constructor .* cannot be invoked without 'new'/.test(err.message)) { - // eslint-disable-next-line new-cap - result = new type_func(arg_string) - } else { - throw err - } - } - - } catch (err) { - // ArgumentTypeErrors indicate errors - if (err instanceof ArgumentTypeError) { - //let name = getattr(action.type, 'name', repr(action.type)) - let msg = err.message - throw new ArgumentError(action, msg) - - // TypeErrors or ValueErrors also indicate errors - } else if (err instanceof TypeError) { - let name = getattr(action.type, 'name', repr(action.type)) - let args = {type: name, value: arg_string} - let msg = 'invalid %(type)s value: %(value)r' - throw new ArgumentError(action, sub(msg, args)) - } else { - throw err - } - } - - // return the converted value - return result - } - - _check_value(action, value) { - // converted value must be one of the choices (if specified) - if (action.choices !== undefined && !_choices_to_array(action.choices).includes(value)) { - let args = {value, - choices: _choices_to_array(action.choices).map(repr).join(', ')} - let msg = 'invalid choice: %(value)r (choose from %(choices)s)' - throw new ArgumentError(action, sub(msg, args)) - } - } - - // ======================= - // Help-formatting methods - // ======================= - format_usage() { - let formatter = this._get_formatter() - formatter.add_usage(this.usage, this._actions, - this._mutually_exclusive_groups) - return formatter.format_help() - } - - format_help() { - let formatter = this._get_formatter() - - // usage - formatter.add_usage(this.usage, this._actions, - this._mutually_exclusive_groups) - - // description - formatter.add_text(this.description) - - // positionals, optionals and user-defined groups - for (let action_group of this._action_groups) { - formatter.start_section(action_group.title) - formatter.add_text(action_group.description) - formatter.add_arguments(action_group._group_actions) - formatter.end_section() - } - - // epilog - formatter.add_text(this.epilog) - - // determine help from format above - return formatter.format_help() - } - - _get_formatter() { - // eslint-disable-next-line new-cap - return new this.formatter_class({ prog: this.prog }) - } - - // ===================== - // Help-printing methods - // ===================== - print_usage(file = undefined) { - if (file === undefined) file = process.stdout - this._print_message(this.format_usage(), file) - } - - print_help(file = undefined) { - if (file === undefined) file = process.stdout - this._print_message(this.format_help(), file) - } - - _print_message(message, file = undefined) { - if (message) { - if (file === undefined) file = process.stderr - file.write(message) - } - } - - // =============== - // Exiting methods - // =============== - exit(status = 0, message = undefined) { - if (message) { - this._print_message(message, process.stderr) - } - process.exit(status) - } - - error(message) { - /* - * error(message: string) - * - * Prints a usage message incorporating the message to stderr and - * exits. - * - * If you override this in a subclass, it should not return -- it - * should either exit or raise an exception. - */ - - // LEGACY (v1 compatibility), debug mode - if (this.debug === true) throw new Error(message) - // end - this.print_usage(process.stderr) - let args = {prog: this.prog, message: message} - this.exit(2, sub('%(prog)s: error: %(message)s\n', args)) - } -})) - - -module.exports = { - ArgumentParser, - ArgumentError, - ArgumentTypeError, - BooleanOptionalAction, - FileType, - HelpFormatter, - ArgumentDefaultsHelpFormatter, - RawDescriptionHelpFormatter, - RawTextHelpFormatter, - MetavarTypeHelpFormatter, - Namespace, - Action, - ONE_OR_MORE, - OPTIONAL, - PARSER, - REMAINDER, - SUPPRESS, - ZERO_OR_MORE -} - -// LEGACY (v1 compatibility), Const alias -Object.defineProperty(module.exports, 'Const', { - get() { - let result = {} - Object.entries({ ONE_OR_MORE, OPTIONAL, PARSER, REMAINDER, SUPPRESS, ZERO_OR_MORE }).forEach(([ n, v ]) => { - Object.defineProperty(result, n, { - get() { - deprecate(n, sub('use argparse.%s instead of argparse.Const.%s', n, n)) - return v - } - }) - }) - Object.entries({ _UNRECOGNIZED_ARGS_ATTR }).forEach(([ n, v ]) => { - Object.defineProperty(result, n, { - get() { - deprecate(n, sub('argparse.Const.%s is an internal symbol and will no longer be available', n)) - return v - } - }) - }) - return result - }, - enumerable: false -}) -// end -- cgit v1.2.3