summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/@pkgjs/parseargs/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/@pkgjs/parseargs/index.js')
-rw-r--r--deps/npm/node_modules/@pkgjs/parseargs/index.js396
1 files changed, 396 insertions, 0 deletions
diff --git a/deps/npm/node_modules/@pkgjs/parseargs/index.js b/deps/npm/node_modules/@pkgjs/parseargs/index.js
new file mode 100644
index 0000000000..b1004c7b72
--- /dev/null
+++ b/deps/npm/node_modules/@pkgjs/parseargs/index.js
@@ -0,0 +1,396 @@
+'use strict';
+
+const {
+ ArrayPrototypeForEach,
+ ArrayPrototypeIncludes,
+ ArrayPrototypeMap,
+ ArrayPrototypePush,
+ ArrayPrototypePushApply,
+ ArrayPrototypeShift,
+ ArrayPrototypeSlice,
+ ArrayPrototypeUnshiftApply,
+ ObjectEntries,
+ ObjectPrototypeHasOwnProperty: ObjectHasOwn,
+ StringPrototypeCharAt,
+ StringPrototypeIndexOf,
+ StringPrototypeSlice,
+ StringPrototypeStartsWith,
+} = require('./internal/primordials');
+
+const {
+ validateArray,
+ validateBoolean,
+ validateBooleanArray,
+ validateObject,
+ validateString,
+ validateStringArray,
+ validateUnion,
+} = require('./internal/validators');
+
+const {
+ kEmptyObject,
+} = require('./internal/util');
+
+const {
+ findLongOptionForShort,
+ isLoneLongOption,
+ isLoneShortOption,
+ isLongOptionAndValue,
+ isOptionValue,
+ isOptionLikeValue,
+ isShortOptionAndValue,
+ isShortOptionGroup,
+ useDefaultValueOption,
+ objectGetOwn,
+ optionsGetOwn,
+} = require('./utils');
+
+const {
+ codes: {
+ ERR_INVALID_ARG_VALUE,
+ ERR_PARSE_ARGS_INVALID_OPTION_VALUE,
+ ERR_PARSE_ARGS_UNKNOWN_OPTION,
+ ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL,
+ },
+} = require('./internal/errors');
+
+function getMainArgs() {
+ // Work out where to slice process.argv for user supplied arguments.
+
+ // Check node options for scenarios where user CLI args follow executable.
+ const execArgv = process.execArgv;
+ if (ArrayPrototypeIncludes(execArgv, '-e') ||
+ ArrayPrototypeIncludes(execArgv, '--eval') ||
+ ArrayPrototypeIncludes(execArgv, '-p') ||
+ ArrayPrototypeIncludes(execArgv, '--print')) {
+ return ArrayPrototypeSlice(process.argv, 1);
+ }
+
+ // Normally first two arguments are executable and script, then CLI arguments
+ return ArrayPrototypeSlice(process.argv, 2);
+}
+
+/**
+ * In strict mode, throw for possible usage errors like --foo --bar
+ *
+ * @param {object} token - from tokens as available from parseArgs
+ */
+function checkOptionLikeValue(token) {
+ if (!token.inlineValue && isOptionLikeValue(token.value)) {
+ // Only show short example if user used short option.
+ const example = StringPrototypeStartsWith(token.rawName, '--') ?
+ `'${token.rawName}=-XYZ'` :
+ `'--${token.name}=-XYZ' or '${token.rawName}-XYZ'`;
+ const errorMessage = `Option '${token.rawName}' argument is ambiguous.
+Did you forget to specify the option argument for '${token.rawName}'?
+To specify an option argument starting with a dash use ${example}.`;
+ throw new ERR_PARSE_ARGS_INVALID_OPTION_VALUE(errorMessage);
+ }
+}
+
+/**
+ * In strict mode, throw for usage errors.
+ *
+ * @param {object} config - from config passed to parseArgs
+ * @param {object} token - from tokens as available from parseArgs
+ */
+function checkOptionUsage(config, token) {
+ if (!ObjectHasOwn(config.options, token.name)) {
+ throw new ERR_PARSE_ARGS_UNKNOWN_OPTION(
+ token.rawName, config.allowPositionals);
+ }
+
+ const short = optionsGetOwn(config.options, token.name, 'short');
+ const shortAndLong = `${short ? `-${short}, ` : ''}--${token.name}`;
+ const type = optionsGetOwn(config.options, token.name, 'type');
+ if (type === 'string' && typeof token.value !== 'string') {
+ throw new ERR_PARSE_ARGS_INVALID_OPTION_VALUE(`Option '${shortAndLong} <value>' argument missing`);
+ }
+ // (Idiomatic test for undefined||null, expecting undefined.)
+ if (type === 'boolean' && token.value != null) {
+ throw new ERR_PARSE_ARGS_INVALID_OPTION_VALUE(`Option '${shortAndLong}' does not take an argument`);
+ }
+}
+
+
+/**
+ * Store the option value in `values`.
+ *
+ * @param {string} longOption - long option name e.g. 'foo'
+ * @param {string|undefined} optionValue - value from user args
+ * @param {object} options - option configs, from parseArgs({ options })
+ * @param {object} values - option values returned in `values` by parseArgs
+ */
+function storeOption(longOption, optionValue, options, values) {
+ if (longOption === '__proto__') {
+ return; // No. Just no.
+ }
+
+ // We store based on the option value rather than option type,
+ // preserving the users intent for author to deal with.
+ const newValue = optionValue ?? true;
+ if (optionsGetOwn(options, longOption, 'multiple')) {
+ // Always store value in array, including for boolean.
+ // values[longOption] starts out not present,
+ // first value is added as new array [newValue],
+ // subsequent values are pushed to existing array.
+ // (note: values has null prototype, so simpler usage)
+ if (values[longOption]) {
+ ArrayPrototypePush(values[longOption], newValue);
+ } else {
+ values[longOption] = [newValue];
+ }
+ } else {
+ values[longOption] = newValue;
+ }
+}
+
+/**
+ * Store the default option value in `values`.
+ *
+ * @param {string} longOption - long option name e.g. 'foo'
+ * @param {string
+ * | boolean
+ * | string[]
+ * | boolean[]} optionValue - default value from option config
+ * @param {object} values - option values returned in `values` by parseArgs
+ */
+function storeDefaultOption(longOption, optionValue, values) {
+ if (longOption === '__proto__') {
+ return; // No. Just no.
+ }
+
+ values[longOption] = optionValue;
+}
+
+/**
+ * Process args and turn into identified tokens:
+ * - option (along with value, if any)
+ * - positional
+ * - option-terminator
+ *
+ * @param {string[]} args - from parseArgs({ args }) or mainArgs
+ * @param {object} options - option configs, from parseArgs({ options })
+ */
+function argsToTokens(args, options) {
+ const tokens = [];
+ let index = -1;
+ let groupCount = 0;
+
+ const remainingArgs = ArrayPrototypeSlice(args);
+ while (remainingArgs.length > 0) {
+ const arg = ArrayPrototypeShift(remainingArgs);
+ const nextArg = remainingArgs[0];
+ if (groupCount > 0)
+ groupCount--;
+ else
+ index++;
+
+ // Check if `arg` is an options terminator.
+ // Guideline 10 in https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
+ if (arg === '--') {
+ // Everything after a bare '--' is considered a positional argument.
+ ArrayPrototypePush(tokens, { kind: 'option-terminator', index });
+ ArrayPrototypePushApply(
+ tokens, ArrayPrototypeMap(remainingArgs, (arg) => {
+ return { kind: 'positional', index: ++index, value: arg };
+ })
+ );
+ break; // Finished processing args, leave while loop.
+ }
+
+ if (isLoneShortOption(arg)) {
+ // e.g. '-f'
+ const shortOption = StringPrototypeCharAt(arg, 1);
+ const longOption = findLongOptionForShort(shortOption, options);
+ let value;
+ let inlineValue;
+ if (optionsGetOwn(options, longOption, 'type') === 'string' &&
+ isOptionValue(nextArg)) {
+ // e.g. '-f', 'bar'
+ value = ArrayPrototypeShift(remainingArgs);
+ inlineValue = false;
+ }
+ ArrayPrototypePush(
+ tokens,
+ { kind: 'option', name: longOption, rawName: arg,
+ index, value, inlineValue });
+ if (value != null) ++index;
+ continue;
+ }
+
+ if (isShortOptionGroup(arg, options)) {
+ // Expand -fXzy to -f -X -z -y
+ const expanded = [];
+ for (let index = 1; index < arg.length; index++) {
+ const shortOption = StringPrototypeCharAt(arg, index);
+ const longOption = findLongOptionForShort(shortOption, options);
+ if (optionsGetOwn(options, longOption, 'type') !== 'string' ||
+ index === arg.length - 1) {
+ // Boolean option, or last short in group. Well formed.
+ ArrayPrototypePush(expanded, `-${shortOption}`);
+ } else {
+ // String option in middle. Yuck.
+ // Expand -abfFILE to -a -b -fFILE
+ ArrayPrototypePush(expanded, `-${StringPrototypeSlice(arg, index)}`);
+ break; // finished short group
+ }
+ }
+ ArrayPrototypeUnshiftApply(remainingArgs, expanded);
+ groupCount = expanded.length;
+ continue;
+ }
+
+ if (isShortOptionAndValue(arg, options)) {
+ // e.g. -fFILE
+ const shortOption = StringPrototypeCharAt(arg, 1);
+ const longOption = findLongOptionForShort(shortOption, options);
+ const value = StringPrototypeSlice(arg, 2);
+ ArrayPrototypePush(
+ tokens,
+ { kind: 'option', name: longOption, rawName: `-${shortOption}`,
+ index, value, inlineValue: true });
+ continue;
+ }
+
+ if (isLoneLongOption(arg)) {
+ // e.g. '--foo'
+ const longOption = StringPrototypeSlice(arg, 2);
+ let value;
+ let inlineValue;
+ if (optionsGetOwn(options, longOption, 'type') === 'string' &&
+ isOptionValue(nextArg)) {
+ // e.g. '--foo', 'bar'
+ value = ArrayPrototypeShift(remainingArgs);
+ inlineValue = false;
+ }
+ ArrayPrototypePush(
+ tokens,
+ { kind: 'option', name: longOption, rawName: arg,
+ index, value, inlineValue });
+ if (value != null) ++index;
+ continue;
+ }
+
+ if (isLongOptionAndValue(arg)) {
+ // e.g. --foo=bar
+ const equalIndex = StringPrototypeIndexOf(arg, '=');
+ const longOption = StringPrototypeSlice(arg, 2, equalIndex);
+ const value = StringPrototypeSlice(arg, equalIndex + 1);
+ ArrayPrototypePush(
+ tokens,
+ { kind: 'option', name: longOption, rawName: `--${longOption}`,
+ index, value, inlineValue: true });
+ continue;
+ }
+
+ ArrayPrototypePush(tokens, { kind: 'positional', index, value: arg });
+ }
+
+ return tokens;
+}
+
+const parseArgs = (config = kEmptyObject) => {
+ const args = objectGetOwn(config, 'args') ?? getMainArgs();
+ const strict = objectGetOwn(config, 'strict') ?? true;
+ const allowPositionals = objectGetOwn(config, 'allowPositionals') ?? !strict;
+ const returnTokens = objectGetOwn(config, 'tokens') ?? false;
+ const options = objectGetOwn(config, 'options') ?? { __proto__: null };
+ // Bundle these up for passing to strict-mode checks.
+ const parseConfig = { args, strict, options, allowPositionals };
+
+ // Validate input configuration.
+ validateArray(args, 'args');
+ validateBoolean(strict, 'strict');
+ validateBoolean(allowPositionals, 'allowPositionals');
+ validateBoolean(returnTokens, 'tokens');
+ validateObject(options, 'options');
+ ArrayPrototypeForEach(
+ ObjectEntries(options),
+ ({ 0: longOption, 1: optionConfig }) => {
+ validateObject(optionConfig, `options.${longOption}`);
+
+ // type is required
+ const optionType = objectGetOwn(optionConfig, 'type');
+ validateUnion(optionType, `options.${longOption}.type`, ['string', 'boolean']);
+
+ if (ObjectHasOwn(optionConfig, 'short')) {
+ const shortOption = optionConfig.short;
+ validateString(shortOption, `options.${longOption}.short`);
+ if (shortOption.length !== 1) {
+ throw new ERR_INVALID_ARG_VALUE(
+ `options.${longOption}.short`,
+ shortOption,
+ 'must be a single character'
+ );
+ }
+ }
+
+ const multipleOption = objectGetOwn(optionConfig, 'multiple');
+ if (ObjectHasOwn(optionConfig, 'multiple')) {
+ validateBoolean(multipleOption, `options.${longOption}.multiple`);
+ }
+
+ const defaultValue = objectGetOwn(optionConfig, 'default');
+ if (defaultValue !== undefined) {
+ let validator;
+ switch (optionType) {
+ case 'string':
+ validator = multipleOption ? validateStringArray : validateString;
+ break;
+
+ case 'boolean':
+ validator = multipleOption ? validateBooleanArray : validateBoolean;
+ break;
+ }
+ validator(defaultValue, `options.${longOption}.default`);
+ }
+ }
+ );
+
+ // Phase 1: identify tokens
+ const tokens = argsToTokens(args, options);
+
+ // Phase 2: process tokens into parsed option values and positionals
+ const result = {
+ values: { __proto__: null },
+ positionals: [],
+ };
+ if (returnTokens) {
+ result.tokens = tokens;
+ }
+ ArrayPrototypeForEach(tokens, (token) => {
+ if (token.kind === 'option') {
+ if (strict) {
+ checkOptionUsage(parseConfig, token);
+ checkOptionLikeValue(token);
+ }
+ storeOption(token.name, token.value, options, result.values);
+ } else if (token.kind === 'positional') {
+ if (!allowPositionals) {
+ throw new ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL(token.value);
+ }
+ ArrayPrototypePush(result.positionals, token.value);
+ }
+ });
+
+ // Phase 3: fill in default values for missing args
+ ArrayPrototypeForEach(ObjectEntries(options), ({ 0: longOption,
+ 1: optionConfig }) => {
+ const mustSetDefault = useDefaultValueOption(longOption,
+ optionConfig,
+ result.values);
+ if (mustSetDefault) {
+ storeDefaultOption(longOption,
+ objectGetOwn(optionConfig, 'default'),
+ result.values);
+ }
+ });
+
+
+ return result;
+};
+
+module.exports = {
+ parseArgs,
+};