@plugjs/tsrun
Version:
A simple TypeScript runner --------------------------
4 lines • 87.5 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/cli.mts", "../node_modules/yargs-parser/build/lib/index.js", "../node_modules/yargs-parser/build/lib/string-utils.js", "../node_modules/yargs-parser/build/lib/tokenize-arg-string.js", "../node_modules/yargs-parser/build/lib/yargs-parser-types.js", "../node_modules/yargs-parser/build/lib/yargs-parser.js", "../src/parser.mts"],
"sourcesContent": ["import _childProcess from 'node:child_process'\nimport _module from 'node:module'\nimport _url from 'node:url'\nimport _util from 'node:util'\n\nimport yargs from './parser.mjs'\n\n/* ========================================================================== *\n * EXPORTS *\n * ========================================================================== */\n\n/** Bundled-in `yargs-parser` */\nexport const yargsParser = yargs\n\n/**\n * Wrap around the `main` process of a CLI.\n *\n * This function must be invoked with a script URL (the `import.meta.url`\n * variable of the script being executed) and a callback, which will be invoked\n * once the proper environment for TypeScript has been setup.\n *\n * The callback _might_ return a promise (can be asynchronous) which will be\n * awaited for potential rejections.\n */\nexport function main(\n scriptUrl: string,\n callback: (args: string[]) => void | Promise<void>,\n): void {\n const require = _module.createRequire(import.meta.url)\n const debug = _util.debuglog('plug:cli')\n\n /* Always enable source maps support */\n process.setSourceMapsEnabled(true)\n\n /* Process command line arguments, filtering any \"--force-...\" */\n const args = process.argv.slice(2).filter((arg: string): boolean => {\n if (arg === '--force-esm') {\n process.env.__TS_LOADER_FORCE_TYPE = 'module'\n return false\n } else if (arg === '--force-cjs') {\n process.env.__TS_LOADER_FORCE_TYPE = 'commonjs'\n return false\n } else {\n return true\n }\n })\n\n /* Assume that Typescript loading is _not_ enabled */\n let typeScriptEnabled = false\n\n /* If we have the \"_module.register\" hook in place we can work in-process */\n if (typeof _module.register === 'function') {\n debug('Enabling in-process TypeScript loader')\n\n /* Register the ESM loader and immediately require the CJS loader */\n _module.register('./loader-module.mjs', import.meta.url)\n require('./loader-commonjs.cjs')\n\n /* Add our preloader to the \"execArgv\" arguments to support forking */\n process.execArgv.push(`--import=${require.resolve('./preload.mjs')}`)\n\n /* Yep, typescript is enabled */\n typeScriptEnabled = true\n }\n\n /* If we don't have TypeScript enabled check the NodeJS command line */\n if (! typeScriptEnabled) {\n const cjsLoader = require.resolve('./loader-commonjs.cjs')\n const esmLoader = require.resolve('./loader-module.mjs')\n\n if (process.execArgv.includes(`--experimental-loader=${esmLoader}`)) {\n typeScriptEnabled = true\n } else if (process.execArgv.includes(`--loader=${esmLoader}`)) {\n typeScriptEnabled = true\n } else {\n process.execArgv.push(`--experimental-loader=${esmLoader}`)\n process.execArgv.push(`--require=${cjsLoader}`)\n process.execArgv.push('--no-warnings')\n typeScriptEnabled = false\n }\n }\n\n\n /* If TypeScript is enabled, then we can simply run now! */\n if (typeScriptEnabled) {\n /* Wrap into a promise to better catch errors from the real \"main\" */\n Promise.resolve().then(async () => {\n process.exitCode = 0\n await callback(args)\n }).catch((error) => {\n console.error(error)\n process.exitCode = 1\n\n setTimeout(() => {\n console.log('\\n\\nProcess %d did not exit in 5 seconds', process.pid)\n process.exit(2)\n }, 5000).unref()\n })\n\n return\n }\n\n /* If TypeScript is not enabled, then we have to fork with the new execArgh! */\n const script = _url.fileURLToPath(scriptUrl)\n debug('Forking', process.execPath, ...process.execArgv, script, ...process.argv.slice(2))\n const child = _childProcess.fork(script, [ ...process.argv.slice(2) ], {\n stdio: [ 'inherit', 'inherit', 'inherit', 'ipc' ],\n execArgv: process.execArgv,\n })\n\n /* Monitor child process... */\n child.on('error', (error) => {\n console.log('Error respawning CLI', error)\n process.exit(1)\n })\n\n child.on('exit', (code, signal) => {\n if (signal) {\n console.log(`CLI process exited with signal ${signal}`)\n process.exit(1)\n } else if (typeof code !== 'number') {\n console.log('CLI process failed for an unknown reason')\n process.exit(1)\n } else {\n process.exit(code)\n }\n })\n}\n", "/**\n * @fileoverview Main entrypoint for libraries using yargs-parser in Node.js\n * CJS and ESM environments.\n *\n * @license\n * Copyright (c) 2016, Contributors\n * SPDX-License-Identifier: ISC\n */\nvar _a, _b, _c;\nimport { format } from 'util';\nimport { normalize, resolve } from 'path';\nimport { camelCase, decamelize, looksLikeNumber } from './string-utils.js';\nimport { YargsParser } from './yargs-parser.js';\nimport { readFileSync } from 'fs';\n// See https://github.com/yargs/yargs-parser#supported-nodejs-versions for our\n// version support policy. The YARGS_MIN_NODE_VERSION is used for testing only.\nconst minNodeVersion = (process && process.env && process.env.YARGS_MIN_NODE_VERSION)\n ? Number(process.env.YARGS_MIN_NODE_VERSION)\n : 12;\nconst nodeVersion = (_b = (_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0 ? void 0 : _a.node) !== null && _b !== void 0 ? _b : (_c = process === null || process === void 0 ? void 0 : process.version) === null || _c === void 0 ? void 0 : _c.slice(1);\nif (nodeVersion) {\n const major = Number(nodeVersion.match(/^([^.]+)/)[1]);\n if (major < minNodeVersion) {\n throw Error(`yargs parser supports a minimum Node.js version of ${minNodeVersion}. Read our version support policy: https://github.com/yargs/yargs-parser#supported-nodejs-versions`);\n }\n}\n// Creates a yargs-parser instance using Node.js standard libraries:\nconst env = process ? process.env : {};\nconst parser = new YargsParser({\n cwd: process.cwd,\n env: () => {\n return env;\n },\n format,\n normalize,\n resolve,\n // TODO: figure out a way to combine ESM and CJS coverage, such that\n // we can exercise all the lines below:\n require: (path) => {\n if (typeof require !== 'undefined') {\n return require(path);\n }\n else if (path.match(/\\.json$/)) {\n // Addresses: https://github.com/yargs/yargs/issues/2040\n return JSON.parse(readFileSync(path, 'utf8'));\n }\n else {\n throw Error('only .json config files are supported in ESM');\n }\n }\n});\nconst yargsParser = function Parser(args, opts) {\n const result = parser.parse(args.slice(), opts);\n return result.argv;\n};\nyargsParser.detailed = function (args, opts) {\n return parser.parse(args.slice(), opts);\n};\nyargsParser.camelCase = camelCase;\nyargsParser.decamelize = decamelize;\nyargsParser.looksLikeNumber = looksLikeNumber;\nexport default yargsParser;\n", "/**\n * @license\n * Copyright (c) 2016, Contributors\n * SPDX-License-Identifier: ISC\n */\nexport function camelCase(str) {\n // Handle the case where an argument is provided as camel case, e.g., fooBar.\n // by ensuring that the string isn't already mixed case:\n const isCamelCase = str !== str.toLowerCase() && str !== str.toUpperCase();\n if (!isCamelCase) {\n str = str.toLowerCase();\n }\n if (str.indexOf('-') === -1 && str.indexOf('_') === -1) {\n return str;\n }\n else {\n let camelcase = '';\n let nextChrUpper = false;\n const leadingHyphens = str.match(/^-+/);\n for (let i = leadingHyphens ? leadingHyphens[0].length : 0; i < str.length; i++) {\n let chr = str.charAt(i);\n if (nextChrUpper) {\n nextChrUpper = false;\n chr = chr.toUpperCase();\n }\n if (i !== 0 && (chr === '-' || chr === '_')) {\n nextChrUpper = true;\n }\n else if (chr !== '-' && chr !== '_') {\n camelcase += chr;\n }\n }\n return camelcase;\n }\n}\nexport function decamelize(str, joinString) {\n const lowercase = str.toLowerCase();\n joinString = joinString || '-';\n let notCamelcase = '';\n for (let i = 0; i < str.length; i++) {\n const chrLower = lowercase.charAt(i);\n const chrString = str.charAt(i);\n if (chrLower !== chrString && i > 0) {\n notCamelcase += `${joinString}${lowercase.charAt(i)}`;\n }\n else {\n notCamelcase += chrString;\n }\n }\n return notCamelcase;\n}\nexport function looksLikeNumber(x) {\n if (x === null || x === undefined)\n return false;\n // if loaded from config, may already be a number.\n if (typeof x === 'number')\n return true;\n // hexadecimal.\n if (/^0x[0-9a-f]+$/i.test(x))\n return true;\n // don't treat 0123 as a number; as it drops the leading '0'.\n if (/^0[^.]/.test(x))\n return false;\n return /^[-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(e[-+]?\\d+)?$/.test(x);\n}\n", "/**\n * @license\n * Copyright (c) 2016, Contributors\n * SPDX-License-Identifier: ISC\n */\n// take an un-split argv string and tokenize it.\nexport function tokenizeArgString(argString) {\n if (Array.isArray(argString)) {\n return argString.map(e => typeof e !== 'string' ? e + '' : e);\n }\n argString = argString.trim();\n let i = 0;\n let prevC = null;\n let c = null;\n let opening = null;\n const args = [];\n for (let ii = 0; ii < argString.length; ii++) {\n prevC = c;\n c = argString.charAt(ii);\n // split on spaces unless we're in quotes.\n if (c === ' ' && !opening) {\n if (!(prevC === ' ')) {\n i++;\n }\n continue;\n }\n // don't split the string if we're in matching\n // opening or closing single and double quotes.\n if (c === opening) {\n opening = null;\n }\n else if ((c === \"'\" || c === '\"') && !opening) {\n opening = c;\n }\n if (!args[i])\n args[i] = '';\n args[i] += c;\n }\n return args;\n}\n", "/**\n * @license\n * Copyright (c) 2016, Contributors\n * SPDX-License-Identifier: ISC\n */\nexport var DefaultValuesForTypeKey;\n(function (DefaultValuesForTypeKey) {\n DefaultValuesForTypeKey[\"BOOLEAN\"] = \"boolean\";\n DefaultValuesForTypeKey[\"STRING\"] = \"string\";\n DefaultValuesForTypeKey[\"NUMBER\"] = \"number\";\n DefaultValuesForTypeKey[\"ARRAY\"] = \"array\";\n})(DefaultValuesForTypeKey || (DefaultValuesForTypeKey = {}));\n", "/**\n * @license\n * Copyright (c) 2016, Contributors\n * SPDX-License-Identifier: ISC\n */\nimport { tokenizeArgString } from './tokenize-arg-string.js';\nimport { DefaultValuesForTypeKey } from './yargs-parser-types.js';\nimport { camelCase, decamelize, looksLikeNumber } from './string-utils.js';\nlet mixin;\nexport class YargsParser {\n constructor(_mixin) {\n mixin = _mixin;\n }\n parse(argsInput, options) {\n const opts = Object.assign({\n alias: undefined,\n array: undefined,\n boolean: undefined,\n config: undefined,\n configObjects: undefined,\n configuration: undefined,\n coerce: undefined,\n count: undefined,\n default: undefined,\n envPrefix: undefined,\n narg: undefined,\n normalize: undefined,\n string: undefined,\n number: undefined,\n __: undefined,\n key: undefined\n }, options);\n // allow a string argument to be passed in rather\n // than an argv array.\n const args = tokenizeArgString(argsInput);\n // tokenizeArgString adds extra quotes to args if argsInput is a string\n // only strip those extra quotes in processValue if argsInput is a string\n const inputIsString = typeof argsInput === 'string';\n // aliases might have transitive relationships, normalize this.\n const aliases = combineAliases(Object.assign(Object.create(null), opts.alias));\n const configuration = Object.assign({\n 'boolean-negation': true,\n 'camel-case-expansion': true,\n 'combine-arrays': false,\n 'dot-notation': true,\n 'duplicate-arguments-array': true,\n 'flatten-duplicate-arrays': true,\n 'greedy-arrays': true,\n 'halt-at-non-option': false,\n 'nargs-eats-options': false,\n 'negation-prefix': 'no-',\n 'parse-numbers': true,\n 'parse-positional-numbers': true,\n 'populate--': false,\n 'set-placeholder-key': false,\n 'short-option-groups': true,\n 'strip-aliased': false,\n 'strip-dashed': false,\n 'unknown-options-as-args': false\n }, opts.configuration);\n const defaults = Object.assign(Object.create(null), opts.default);\n const configObjects = opts.configObjects || [];\n const envPrefix = opts.envPrefix;\n const notFlagsOption = configuration['populate--'];\n const notFlagsArgv = notFlagsOption ? '--' : '_';\n const newAliases = Object.create(null);\n const defaulted = Object.create(null);\n // allow a i18n handler to be passed in, default to a fake one (util.format).\n const __ = opts.__ || mixin.format;\n const flags = {\n aliases: Object.create(null),\n arrays: Object.create(null),\n bools: Object.create(null),\n strings: Object.create(null),\n numbers: Object.create(null),\n counts: Object.create(null),\n normalize: Object.create(null),\n configs: Object.create(null),\n nargs: Object.create(null),\n coercions: Object.create(null),\n keys: []\n };\n const negative = /^-([0-9]+(\\.[0-9]+)?|\\.[0-9]+)$/;\n const negatedBoolean = new RegExp('^--' + configuration['negation-prefix'] + '(.+)');\n [].concat(opts.array || []).filter(Boolean).forEach(function (opt) {\n const key = typeof opt === 'object' ? opt.key : opt;\n // assign to flags[bools|strings|numbers]\n const assignment = Object.keys(opt).map(function (key) {\n const arrayFlagKeys = {\n boolean: 'bools',\n string: 'strings',\n number: 'numbers'\n };\n return arrayFlagKeys[key];\n }).filter(Boolean).pop();\n // assign key to be coerced\n if (assignment) {\n flags[assignment][key] = true;\n }\n flags.arrays[key] = true;\n flags.keys.push(key);\n });\n [].concat(opts.boolean || []).filter(Boolean).forEach(function (key) {\n flags.bools[key] = true;\n flags.keys.push(key);\n });\n [].concat(opts.string || []).filter(Boolean).forEach(function (key) {\n flags.strings[key] = true;\n flags.keys.push(key);\n });\n [].concat(opts.number || []).filter(Boolean).forEach(function (key) {\n flags.numbers[key] = true;\n flags.keys.push(key);\n });\n [].concat(opts.count || []).filter(Boolean).forEach(function (key) {\n flags.counts[key] = true;\n flags.keys.push(key);\n });\n [].concat(opts.normalize || []).filter(Boolean).forEach(function (key) {\n flags.normalize[key] = true;\n flags.keys.push(key);\n });\n if (typeof opts.narg === 'object') {\n Object.entries(opts.narg).forEach(([key, value]) => {\n if (typeof value === 'number') {\n flags.nargs[key] = value;\n flags.keys.push(key);\n }\n });\n }\n if (typeof opts.coerce === 'object') {\n Object.entries(opts.coerce).forEach(([key, value]) => {\n if (typeof value === 'function') {\n flags.coercions[key] = value;\n flags.keys.push(key);\n }\n });\n }\n if (typeof opts.config !== 'undefined') {\n if (Array.isArray(opts.config) || typeof opts.config === 'string') {\n ;\n [].concat(opts.config).filter(Boolean).forEach(function (key) {\n flags.configs[key] = true;\n });\n }\n else if (typeof opts.config === 'object') {\n Object.entries(opts.config).forEach(([key, value]) => {\n if (typeof value === 'boolean' || typeof value === 'function') {\n flags.configs[key] = value;\n }\n });\n }\n }\n // create a lookup table that takes into account all\n // combinations of aliases: {f: ['foo'], foo: ['f']}\n extendAliases(opts.key, aliases, opts.default, flags.arrays);\n // apply default values to all aliases.\n Object.keys(defaults).forEach(function (key) {\n (flags.aliases[key] || []).forEach(function (alias) {\n defaults[alias] = defaults[key];\n });\n });\n let error = null;\n checkConfiguration();\n let notFlags = [];\n const argv = Object.assign(Object.create(null), { _: [] });\n // TODO(bcoe): for the first pass at removing object prototype we didn't\n // remove all prototypes from objects returned by this API, we might want\n // to gradually move towards doing so.\n const argvReturn = {};\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n const truncatedArg = arg.replace(/^-{3,}/, '---');\n let broken;\n let key;\n let letters;\n let m;\n let next;\n let value;\n // any unknown option (except for end-of-options, \"--\")\n if (arg !== '--' && /^-/.test(arg) && isUnknownOptionAsArg(arg)) {\n pushPositional(arg);\n // ---, ---=, ----, etc,\n }\n else if (truncatedArg.match(/^---+(=|$)/)) {\n // options without key name are invalid.\n pushPositional(arg);\n continue;\n // -- separated by =\n }\n else if (arg.match(/^--.+=/) || (!configuration['short-option-groups'] && arg.match(/^-.+=/))) {\n // Using [\\s\\S] instead of . because js doesn't support the\n // 'dotall' regex modifier. See:\n // http://stackoverflow.com/a/1068308/13216\n m = arg.match(/^--?([^=]+)=([\\s\\S]*)$/);\n // arrays format = '--f=a b c'\n if (m !== null && Array.isArray(m) && m.length >= 3) {\n if (checkAllAliases(m[1], flags.arrays)) {\n i = eatArray(i, m[1], args, m[2]);\n }\n else if (checkAllAliases(m[1], flags.nargs) !== false) {\n // nargs format = '--f=monkey washing cat'\n i = eatNargs(i, m[1], args, m[2]);\n }\n else {\n setArg(m[1], m[2], true);\n }\n }\n }\n else if (arg.match(negatedBoolean) && configuration['boolean-negation']) {\n m = arg.match(negatedBoolean);\n if (m !== null && Array.isArray(m) && m.length >= 2) {\n key = m[1];\n setArg(key, checkAllAliases(key, flags.arrays) ? [false] : false);\n }\n // -- separated by space.\n }\n else if (arg.match(/^--.+/) || (!configuration['short-option-groups'] && arg.match(/^-[^-]+/))) {\n m = arg.match(/^--?(.+)/);\n if (m !== null && Array.isArray(m) && m.length >= 2) {\n key = m[1];\n if (checkAllAliases(key, flags.arrays)) {\n // array format = '--foo a b c'\n i = eatArray(i, key, args);\n }\n else if (checkAllAliases(key, flags.nargs) !== false) {\n // nargs format = '--foo a b c'\n // should be truthy even if: flags.nargs[key] === 0\n i = eatNargs(i, key, args);\n }\n else {\n next = args[i + 1];\n if (next !== undefined && (!next.match(/^-/) ||\n next.match(negative)) &&\n !checkAllAliases(key, flags.bools) &&\n !checkAllAliases(key, flags.counts)) {\n setArg(key, next);\n i++;\n }\n else if (/^(true|false)$/.test(next)) {\n setArg(key, next);\n i++;\n }\n else {\n setArg(key, defaultValue(key));\n }\n }\n }\n // dot-notation flag separated by '='.\n }\n else if (arg.match(/^-.\\..+=/)) {\n m = arg.match(/^-([^=]+)=([\\s\\S]*)$/);\n if (m !== null && Array.isArray(m) && m.length >= 3) {\n setArg(m[1], m[2]);\n }\n // dot-notation flag separated by space.\n }\n else if (arg.match(/^-.\\..+/) && !arg.match(negative)) {\n next = args[i + 1];\n m = arg.match(/^-(.\\..+)/);\n if (m !== null && Array.isArray(m) && m.length >= 2) {\n key = m[1];\n if (next !== undefined && !next.match(/^-/) &&\n !checkAllAliases(key, flags.bools) &&\n !checkAllAliases(key, flags.counts)) {\n setArg(key, next);\n i++;\n }\n else {\n setArg(key, defaultValue(key));\n }\n }\n }\n else if (arg.match(/^-[^-]+/) && !arg.match(negative)) {\n letters = arg.slice(1, -1).split('');\n broken = false;\n for (let j = 0; j < letters.length; j++) {\n next = arg.slice(j + 2);\n if (letters[j + 1] && letters[j + 1] === '=') {\n value = arg.slice(j + 3);\n key = letters[j];\n if (checkAllAliases(key, flags.arrays)) {\n // array format = '-f=a b c'\n i = eatArray(i, key, args, value);\n }\n else if (checkAllAliases(key, flags.nargs) !== false) {\n // nargs format = '-f=monkey washing cat'\n i = eatNargs(i, key, args, value);\n }\n else {\n setArg(key, value);\n }\n broken = true;\n break;\n }\n if (next === '-') {\n setArg(letters[j], next);\n continue;\n }\n // current letter is an alphabetic character and next value is a number\n if (/[A-Za-z]/.test(letters[j]) &&\n /^-?\\d+(\\.\\d*)?(e-?\\d+)?$/.test(next) &&\n checkAllAliases(next, flags.bools) === false) {\n setArg(letters[j], next);\n broken = true;\n break;\n }\n if (letters[j + 1] && letters[j + 1].match(/\\W/)) {\n setArg(letters[j], next);\n broken = true;\n break;\n }\n else {\n setArg(letters[j], defaultValue(letters[j]));\n }\n }\n key = arg.slice(-1)[0];\n if (!broken && key !== '-') {\n if (checkAllAliases(key, flags.arrays)) {\n // array format = '-f a b c'\n i = eatArray(i, key, args);\n }\n else if (checkAllAliases(key, flags.nargs) !== false) {\n // nargs format = '-f a b c'\n // should be truthy even if: flags.nargs[key] === 0\n i = eatNargs(i, key, args);\n }\n else {\n next = args[i + 1];\n if (next !== undefined && (!/^(-|--)[^-]/.test(next) ||\n next.match(negative)) &&\n !checkAllAliases(key, flags.bools) &&\n !checkAllAliases(key, flags.counts)) {\n setArg(key, next);\n i++;\n }\n else if (/^(true|false)$/.test(next)) {\n setArg(key, next);\n i++;\n }\n else {\n setArg(key, defaultValue(key));\n }\n }\n }\n }\n else if (arg.match(/^-[0-9]$/) &&\n arg.match(negative) &&\n checkAllAliases(arg.slice(1), flags.bools)) {\n // single-digit boolean alias, e.g: xargs -0\n key = arg.slice(1);\n setArg(key, defaultValue(key));\n }\n else if (arg === '--') {\n notFlags = args.slice(i + 1);\n break;\n }\n else if (configuration['halt-at-non-option']) {\n notFlags = args.slice(i);\n break;\n }\n else {\n pushPositional(arg);\n }\n }\n // order of precedence:\n // 1. command line arg\n // 2. value from env var\n // 3. value from config file\n // 4. value from config objects\n // 5. configured default value\n applyEnvVars(argv, true); // special case: check env vars that point to config file\n applyEnvVars(argv, false);\n setConfig(argv);\n setConfigObjects();\n applyDefaultsAndAliases(argv, flags.aliases, defaults, true);\n applyCoercions(argv);\n if (configuration['set-placeholder-key'])\n setPlaceholderKeys(argv);\n // for any counts either not in args or without an explicit default, set to 0\n Object.keys(flags.counts).forEach(function (key) {\n if (!hasKey(argv, key.split('.')))\n setArg(key, 0);\n });\n // '--' defaults to undefined.\n if (notFlagsOption && notFlags.length)\n argv[notFlagsArgv] = [];\n notFlags.forEach(function (key) {\n argv[notFlagsArgv].push(key);\n });\n if (configuration['camel-case-expansion'] && configuration['strip-dashed']) {\n Object.keys(argv).filter(key => key !== '--' && key.includes('-')).forEach(key => {\n delete argv[key];\n });\n }\n if (configuration['strip-aliased']) {\n ;\n [].concat(...Object.keys(aliases).map(k => aliases[k])).forEach(alias => {\n if (configuration['camel-case-expansion'] && alias.includes('-')) {\n delete argv[alias.split('.').map(prop => camelCase(prop)).join('.')];\n }\n delete argv[alias];\n });\n }\n // Push argument into positional array, applying numeric coercion:\n function pushPositional(arg) {\n const maybeCoercedNumber = maybeCoerceNumber('_', arg);\n if (typeof maybeCoercedNumber === 'string' || typeof maybeCoercedNumber === 'number') {\n argv._.push(maybeCoercedNumber);\n }\n }\n // how many arguments should we consume, based\n // on the nargs option?\n function eatNargs(i, key, args, argAfterEqualSign) {\n let ii;\n let toEat = checkAllAliases(key, flags.nargs);\n // NaN has a special meaning for the array type, indicating that one or\n // more values are expected.\n toEat = typeof toEat !== 'number' || isNaN(toEat) ? 1 : toEat;\n if (toEat === 0) {\n if (!isUndefined(argAfterEqualSign)) {\n error = Error(__('Argument unexpected for: %s', key));\n }\n setArg(key, defaultValue(key));\n return i;\n }\n let available = isUndefined(argAfterEqualSign) ? 0 : 1;\n if (configuration['nargs-eats-options']) {\n // classic behavior, yargs eats positional and dash arguments.\n if (args.length - (i + 1) + available < toEat) {\n error = Error(__('Not enough arguments following: %s', key));\n }\n available = toEat;\n }\n else {\n // nargs will not consume flag arguments, e.g., -abc, --foo,\n // and terminates when one is observed.\n for (ii = i + 1; ii < args.length; ii++) {\n if (!args[ii].match(/^-[^0-9]/) || args[ii].match(negative) || isUnknownOptionAsArg(args[ii]))\n available++;\n else\n break;\n }\n if (available < toEat)\n error = Error(__('Not enough arguments following: %s', key));\n }\n let consumed = Math.min(available, toEat);\n if (!isUndefined(argAfterEqualSign) && consumed > 0) {\n setArg(key, argAfterEqualSign);\n consumed--;\n }\n for (ii = i + 1; ii < (consumed + i + 1); ii++) {\n setArg(key, args[ii]);\n }\n return (i + consumed);\n }\n // if an option is an array, eat all non-hyphenated arguments\n // following it... YUM!\n // e.g., --foo apple banana cat becomes [\"apple\", \"banana\", \"cat\"]\n function eatArray(i, key, args, argAfterEqualSign) {\n let argsToSet = [];\n let next = argAfterEqualSign || args[i + 1];\n // If both array and nargs are configured, enforce the nargs count:\n const nargsCount = checkAllAliases(key, flags.nargs);\n if (checkAllAliases(key, flags.bools) && !(/^(true|false)$/.test(next))) {\n argsToSet.push(true);\n }\n else if (isUndefined(next) ||\n (isUndefined(argAfterEqualSign) && /^-/.test(next) && !negative.test(next) && !isUnknownOptionAsArg(next))) {\n // for keys without value ==> argsToSet remains an empty []\n // set user default value, if available\n if (defaults[key] !== undefined) {\n const defVal = defaults[key];\n argsToSet = Array.isArray(defVal) ? defVal : [defVal];\n }\n }\n else {\n // value in --option=value is eaten as is\n if (!isUndefined(argAfterEqualSign)) {\n argsToSet.push(processValue(key, argAfterEqualSign, true));\n }\n for (let ii = i + 1; ii < args.length; ii++) {\n if ((!configuration['greedy-arrays'] && argsToSet.length > 0) ||\n (nargsCount && typeof nargsCount === 'number' && argsToSet.length >= nargsCount))\n break;\n next = args[ii];\n if (/^-/.test(next) && !negative.test(next) && !isUnknownOptionAsArg(next))\n break;\n i = ii;\n argsToSet.push(processValue(key, next, inputIsString));\n }\n }\n // If both array and nargs are configured, create an error if less than\n // nargs positionals were found. NaN has special meaning, indicating\n // that at least one value is required (more are okay).\n if (typeof nargsCount === 'number' && ((nargsCount && argsToSet.length < nargsCount) ||\n (isNaN(nargsCount) && argsToSet.length === 0))) {\n error = Error(__('Not enough arguments following: %s', key));\n }\n setArg(key, argsToSet);\n return i;\n }\n function setArg(key, val, shouldStripQuotes = inputIsString) {\n if (/-/.test(key) && configuration['camel-case-expansion']) {\n const alias = key.split('.').map(function (prop) {\n return camelCase(prop);\n }).join('.');\n addNewAlias(key, alias);\n }\n const value = processValue(key, val, shouldStripQuotes);\n const splitKey = key.split('.');\n setKey(argv, splitKey, value);\n // handle populating aliases of the full key\n if (flags.aliases[key]) {\n flags.aliases[key].forEach(function (x) {\n const keyProperties = x.split('.');\n setKey(argv, keyProperties, value);\n });\n }\n // handle populating aliases of the first element of the dot-notation key\n if (splitKey.length > 1 && configuration['dot-notation']) {\n ;\n (flags.aliases[splitKey[0]] || []).forEach(function (x) {\n let keyProperties = x.split('.');\n // expand alias with nested objects in key\n const a = [].concat(splitKey);\n a.shift(); // nuke the old key.\n keyProperties = keyProperties.concat(a);\n // populate alias only if is not already an alias of the full key\n // (already populated above)\n if (!(flags.aliases[key] || []).includes(keyProperties.join('.'))) {\n setKey(argv, keyProperties, value);\n }\n });\n }\n // Set normalize getter and setter when key is in 'normalize' but isn't an array\n if (checkAllAliases(key, flags.normalize) && !checkAllAliases(key, flags.arrays)) {\n const keys = [key].concat(flags.aliases[key] || []);\n keys.forEach(function (key) {\n Object.defineProperty(argvReturn, key, {\n enumerable: true,\n get() {\n return val;\n },\n set(value) {\n val = typeof value === 'string' ? mixin.normalize(value) : value;\n }\n });\n });\n }\n }\n function addNewAlias(key, alias) {\n if (!(flags.aliases[key] && flags.aliases[key].length)) {\n flags.aliases[key] = [alias];\n newAliases[alias] = true;\n }\n if (!(flags.aliases[alias] && flags.aliases[alias].length)) {\n addNewAlias(alias, key);\n }\n }\n function processValue(key, val, shouldStripQuotes) {\n // strings may be quoted, clean this up as we assign values.\n if (shouldStripQuotes) {\n val = stripQuotes(val);\n }\n // handle parsing boolean arguments --foo=true --bar false.\n if (checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) {\n if (typeof val === 'string')\n val = val === 'true';\n }\n let value = Array.isArray(val)\n ? val.map(function (v) { return maybeCoerceNumber(key, v); })\n : maybeCoerceNumber(key, val);\n // increment a count given as arg (either no value or value parsed as boolean)\n if (checkAllAliases(key, flags.counts) && (isUndefined(value) || typeof value === 'boolean')) {\n value = increment();\n }\n // Set normalized value when key is in 'normalize' and in 'arrays'\n if (checkAllAliases(key, flags.normalize) && checkAllAliases(key, flags.arrays)) {\n if (Array.isArray(val))\n value = val.map((val) => { return mixin.normalize(val); });\n else\n value = mixin.normalize(val);\n }\n return value;\n }\n function maybeCoerceNumber(key, value) {\n if (!configuration['parse-positional-numbers'] && key === '_')\n return value;\n if (!checkAllAliases(key, flags.strings) && !checkAllAliases(key, flags.bools) && !Array.isArray(value)) {\n const shouldCoerceNumber = looksLikeNumber(value) && configuration['parse-numbers'] && (Number.isSafeInteger(Math.floor(parseFloat(`${value}`))));\n if (shouldCoerceNumber || (!isUndefined(value) && checkAllAliases(key, flags.numbers))) {\n value = Number(value);\n }\n }\n return value;\n }\n // set args from config.json file, this should be\n // applied last so that defaults can be applied.\n function setConfig(argv) {\n const configLookup = Object.create(null);\n // expand defaults/aliases, in-case any happen to reference\n // the config.json file.\n applyDefaultsAndAliases(configLookup, flags.aliases, defaults);\n Object.keys(flags.configs).forEach(function (configKey) {\n const configPath = argv[configKey] || configLookup[configKey];\n if (configPath) {\n try {\n let config = null;\n const resolvedConfigPath = mixin.resolve(mixin.cwd(), configPath);\n const resolveConfig = flags.configs[configKey];\n if (typeof resolveConfig === 'function') {\n try {\n config = resolveConfig(resolvedConfigPath);\n }\n catch (e) {\n config = e;\n }\n if (config instanceof Error) {\n error = config;\n return;\n }\n }\n else {\n config = mixin.require(resolvedConfigPath);\n }\n setConfigObject(config);\n }\n catch (ex) {\n // Deno will receive a PermissionDenied error if an attempt is\n // made to load config without the --allow-read flag:\n if (ex.name === 'PermissionDenied')\n error = ex;\n else if (argv[configKey])\n error = Error(__('Invalid JSON config file: %s', configPath));\n }\n }\n });\n }\n // set args from config object.\n // it recursively checks nested objects.\n function setConfigObject(config, prev) {\n Object.keys(config).forEach(function (key) {\n const value = config[key];\n const fullKey = prev ? prev + '.' + key : key;\n // if the value is an inner object and we have dot-notation\n // enabled, treat inner objects in config the same as\n // heavily nested dot notations (foo.bar.apple).\n if (typeof value === 'object' && value !== null && !Array.isArray(value) && configuration['dot-notation']) {\n // if the value is an object but not an array, check nested object\n setConfigObject(value, fullKey);\n }\n else {\n // setting arguments via CLI takes precedence over\n // values within the config file.\n if (!hasKey(argv, fullKey.split('.')) || (checkAllAliases(fullKey, flags.arrays) && configuration['combine-arrays'])) {\n setArg(fullKey, value);\n }\n }\n });\n }\n // set all config objects passed in opts\n function setConfigObjects() {\n if (typeof configObjects !== 'undefined') {\n configObjects.forEach(function (configObject) {\n setConfigObject(configObject);\n });\n }\n }\n function applyEnvVars(argv, configOnly) {\n if (typeof envPrefix === 'undefined')\n return;\n const prefix = typeof envPrefix === 'string' ? envPrefix : '';\n const env = mixin.env();\n Object.keys(env).forEach(function (envVar) {\n if (prefix === '' || envVar.lastIndexOf(prefix, 0) === 0) {\n // get array of nested keys and convert them to camel case\n const keys = envVar.split('__').map(function (key, i) {\n if (i === 0) {\n key = key.substring(prefix.length);\n }\n return camelCase(key);\n });\n if (((configOnly && flags.configs[keys.join('.')]) || !configOnly) && !hasKey(argv, keys)) {\n setArg(keys.join('.'), env[envVar]);\n }\n }\n });\n }\n function applyCoercions(argv) {\n let coerce;\n const applied = new Set();\n Object.keys(argv).forEach(function (key) {\n if (!applied.has(key)) { // If we haven't already coerced this option via one of its aliases\n coerce = checkAllAliases(key, flags.coercions);\n if (typeof coerce === 'function') {\n try {\n const value = maybeCoerceNumber(key, coerce(argv[key]));\n ([].concat(flags.aliases[key] || [], key)).forEach(ali => {\n applied.add(ali);\n argv[ali] = value;\n });\n }\n catch (err) {\n error = err;\n }\n }\n }\n });\n }\n function setPlaceholderKeys(argv) {\n flags.keys.forEach((key) => {\n // don't set placeholder keys for dot notation options 'foo.bar'.\n if (~key.indexOf('.'))\n return;\n if (typeof argv[key] === 'undefined')\n argv[key] = undefined;\n });\n return argv;\n }\n function applyDefaultsAndAliases(obj, aliases, defaults, canLog = false) {\n Object.keys(defaults).forEach(function (key) {\n if (!hasKey(obj, key.split('.'))) {\n setKey(obj, key.split('.'), defaults[key]);\n if (canLog)\n defaulted[key] = true;\n (aliases[key] || []).forEach(function (x) {\n if (hasKey(obj, x.split('.')))\n return;\n setKey(obj, x.split('.'), defaults[key]);\n });\n }\n });\n }\n function hasKey(obj, keys) {\n let o = obj;\n if (!configuration['dot-notation'])\n keys = [keys.join('.')];\n keys.slice(0, -1).forEach(function (key) {\n o = (o[key] || {});\n });\n const key = keys[keys.length - 1];\n if (typeof o !== 'object')\n return false;\n else\n return key in o;\n }\n function setKey(obj, keys, value) {\n let o = obj;\n if (!configuration['dot-notation'])\n keys = [keys.join('.')];\n keys.slice(0, -1).forEach(function (key) {\n // TODO(bcoe): in the next major version of yargs, switch to\n // Object.create(null) for dot notation:\n key = sanitizeKey(key);\n if (typeof o === 'object' && o[key] === undefined) {\n o[key] = {};\n }\n if (typeof o[key] !== 'object' || Array.isArray(o[key])) {\n // ensure that o[key] is an array, and that the last item is an empty object.\n if (Array.isArray(o[key])) {\n o[key].push({});\n }\n else {\n o[key] = [o[key], {}];\n }\n // we want to update the empty object at the end of the o[key] array, so set o to that object\n o = o[key][o[key].length - 1];\n }\n else {\n o = o[key];\n }\n });\n // TODO(bcoe): in the next major version of yargs, switch to\n // Object.create(null) for dot notation:\n const key = sanitizeKey(keys[keys.length - 1]);\n const isTypeArray = checkAllAliases(keys.join('.'), flags.arrays);\n const isValueArray = Array.isArray(value);\n let duplicate = configuration['duplicate-arguments-array'];\n // nargs has higher priority than duplicate\n if (!duplicate && checkAllAliases(key, flags.nargs)) {\n duplicate = true;\n if ((!isUndefined(o[key]) && flags.nargs[key] === 1) || (Array.isArray(o[key]) && o[key].length === flags.nargs[key])) {\n o[key] = undefined;\n }\n }\n if (value === increment()) {\n o[key] = increment(o[key]);\n }\n else if (Array.isArray(o[key])) {\n if (duplicate && isTypeArray && isValueArray) {\n o[key] = configuration['flatten-duplicate-arrays'] ? o[key].concat(value) : (Array.isArray(o[key][0]) ? o[key] : [o[key]]).concat([value]);\n }\n else if (!duplicate && Boolean(isTypeArray) === Boolean(isValueArray)) {\n o[key] = value;\n }\n else {\n o[key] = o[key].concat([value]);\n }\n }\n else if (o[key] === undefined && isTypeArray) {\n o[key] = isValueArray ? value : [value];\n }\n else if (duplicate && !(o[key] === undefined ||\n checkAllAliases(key, flags.counts) ||\n checkAllAliases(key, flags.bools))) {\n o[key] = [o[key], value];\n }\n else {\n o[key] = value;\n }\n }\n // extend the aliases list with inferred aliases.\n function extendAliases(...args) {\n args.forEach(function (obj) {\n Object.keys(obj || {}).forEach(function (key) {\n // short-circuit if we've already added a key\n // to the aliases array, for example it might\n // exist in both 'opts.default' and 'opts.key'.\n if (flags.aliases[key])\n return;\n flags.aliases[key] = [].concat(aliases[key] || []);\n // For \"--option-name\", also set argv.optionName\n flags.aliases[key].concat(key).forEach(function (x) {\n if (/-/.test(x) && configuration['camel-case-expansion']) {\n const c = camelCase(x);\n if (c !== key && flags.aliases[key].indexOf(c) === -1) {\n flags.aliases[key].push(c);\n newAliases[c] = true;\n }\n }\n });\n // For \"--optionName\", also set argv['option-name']\n