-
Notifications
You must be signed in to change notification settings - Fork 118
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
686ec15
commit 735c6b3
Showing
12 changed files
with
2,529 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/** | ||
* An object whose all properties have the same type, where each key is a string. | ||
*/ | ||
interface Dictionary<T = any> { | ||
[key: string]: T; | ||
} | ||
type ArgsInput = string | any[]; | ||
type ArgsOutput = (string | number)[]; | ||
interface Arguments { | ||
/** Non-option arguments */ | ||
_: ArgsOutput; | ||
/** Arguments after the end-of-options flag `--` */ | ||
"--"?: ArgsOutput; | ||
/** All remaining options */ | ||
[argName: string]: any; | ||
} | ||
interface DetailedArguments { | ||
/** An object representing the parsed value of `args` */ | ||
argv: Arguments; | ||
/** Populated with an error object if an exception occurred during parsing. */ | ||
error: Error | null; | ||
/** The inferred list of aliases built by combining lists in opts.alias. */ | ||
aliases: Dictionary<string[]>; | ||
/** Any new aliases added via camel-case expansion. */ | ||
newAliases: Dictionary<boolean>; | ||
/** Any new argument created by opts.default, no aliases included. */ | ||
defaulted: Dictionary<boolean>; | ||
/** The configuration loaded from the yargs stanza in package.json. */ | ||
configuration: Configuration; | ||
} | ||
interface Configuration { | ||
/** Should variables prefixed with --no be treated as negations? Default is `true` */ | ||
"boolean-negation": boolean; | ||
/** Should hyphenated arguments be expanded into camel-case aliases? Default is `true` */ | ||
"camel-case-expansion": boolean; | ||
/** Should arrays be combined when provided by both command line arguments and a configuration file? Default is `false` */ | ||
"combine-arrays": boolean; | ||
/** Should keys that contain `.` be treated as objects? Default is `true` */ | ||
"dot-notation": boolean; | ||
/** Should arguments be coerced into an array when duplicated? Default is `true` */ | ||
"duplicate-arguments-array": boolean; | ||
/** Should array arguments be coerced into a single array when duplicated? Default is `true` */ | ||
"flatten-duplicate-arrays": boolean; | ||
/** Should arrays consume more than one positional argument following their flag? Default is `true` */ | ||
"greedy-arrays": boolean; | ||
/** Should parsing stop at the first text argument? This is similar to how e.g. ssh parses its command line. Default is `false` */ | ||
"halt-at-non-option": boolean; | ||
/** Should nargs consume dash options as well as positional arguments? Default is `false` */ | ||
"nargs-eats-options": boolean; | ||
/** The prefix to use for negated boolean variables. Default is `'no-'` */ | ||
"negation-prefix": string; | ||
/** Should positional values that look like numbers be parsed? Default is `true` */ | ||
"parse-positional-numbers": boolean; | ||
/** Should keys that look like numbers be treated as such? Default is `true` */ | ||
"parse-numbers": boolean; | ||
/** Should unparsed flags be stored in -- or _? Default is `false` */ | ||
"populate--": boolean; | ||
/** Should a placeholder be added for keys not set via the corresponding CLI argument? Default is `false` */ | ||
"set-placeholder-key": boolean; | ||
/** Should a group of short-options be treated as boolean flags? Default is `true` */ | ||
"short-option-groups": boolean; | ||
/** Should aliases be removed before returning results? Default is `false` */ | ||
"strip-aliased": boolean; | ||
/** Should dashed keys be removed before returning results? This option has no effect if camel-case-expansion is disabled. Default is `false` */ | ||
"strip-dashed": boolean; | ||
/** Should unknown options be treated like regular arguments? An unknown option is one that is not configured in opts. Default is `false` */ | ||
"unknown-options-as-args": boolean; | ||
} | ||
type ArrayOption = string | { | ||
key: string; | ||
boolean?: boolean; | ||
string?: boolean; | ||
number?: boolean; | ||
integer?: boolean; | ||
}; | ||
type CoerceCallback = (arg: any) => any; | ||
type ConfigCallback = (configPath: string) => { | ||
[key: string]: any; | ||
} | Error; | ||
interface Options { | ||
/** An object representing the set of aliases for a key: `{ alias: { foo: ['f']} }`. */ | ||
alias: Dictionary<string | string[]>; | ||
/** | ||
* Indicate that keys should be parsed as an array: `{ array: ['foo', 'bar'] }`. | ||
* Indicate that keys should be parsed as an array and coerced to booleans / numbers: | ||
* { array: [ { key: 'foo', boolean: true }, {key: 'bar', number: true} ] }`. | ||
*/ | ||
array: ArrayOption | ArrayOption[]; | ||
/** Arguments should be parsed as booleans: `{ boolean: ['x', 'y'] }`. */ | ||
boolean: string | string[]; | ||
/** Indicate a key that represents a path to a configuration file (this file will be loaded and parsed). */ | ||
config: string | string[] | Dictionary<boolean | ConfigCallback>; | ||
/** configuration objects to parse, their properties will be set as arguments */ | ||
configObjects: Dictionary<any>[]; | ||
/** Provide configuration options to the yargs-parser. */ | ||
configuration: Partial<Configuration>; | ||
/** | ||
* Provide a custom synchronous function that returns a coerced value from the argument provided (or throws an error), e.g. | ||
* `{ coerce: { foo: function (arg) { return modifiedArg } } }`. | ||
*/ | ||
coerce: Dictionary<CoerceCallback>; | ||
/** Indicate a key that should be used as a counter, e.g., `-vvv = {v: 3}`. */ | ||
count: string | string[]; | ||
/** Provide default values for keys: `{ default: { x: 33, y: 'hello world!' } }`. */ | ||
default: Dictionary<any>; | ||
/** Environment variables (`process.env`) with the prefix provided should be parsed. */ | ||
envPrefix?: string; | ||
/** Specify that a key requires n arguments: `{ narg: {x: 2} }`. */ | ||
narg: Dictionary<number>; | ||
/** `path.normalize()` will be applied to values set to this key. */ | ||
normalize: string | string[]; | ||
/** Keys should be treated as strings (even if they resemble a number `-x 33`). */ | ||
string: string | string[]; | ||
/** Keys should be treated as numbers. */ | ||
number: string | string[]; | ||
/** i18n handler, defaults to util.format */ | ||
__: (format: any, ...param: any[]) => string; | ||
/** alias lookup table defaults */ | ||
key: Dictionary<any>; | ||
} | ||
interface Parser { | ||
(args: ArgsInput, opts?: Partial<Options>): Arguments; | ||
detailed(args: ArgsInput, opts?: Partial<Options>): DetailedArguments; | ||
camelCase(str: string): string; | ||
decamelize(str: string, joinString?: string): string; | ||
looksLikeNumber(x: null | undefined | number | string): boolean; | ||
} | ||
declare const yargsParser: Parser; | ||
export = yargsParser; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { Parser } from './yargs-parser-types.js'; | ||
declare const yargsParser: Parser; | ||
export default yargsParser; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Main entrypoint for libraries using yargs-parser in Node.js | ||
// CJS and ESM environments: | ||
import { format } from 'util'; | ||
import { readFileSync } from 'fs'; | ||
import { normalize, resolve } from 'path'; | ||
import { camelCase, decamelize, looksLikeNumber } from './string-utils.js'; | ||
import { YargsParser } from './yargs-parser.js'; | ||
// See https://github.com/yargs/yargs-parser#supported-nodejs-versions for our | ||
// version support policy. The YARGS_MIN_NODE_VERSION is used for testing only. | ||
const minNodeVersion = (process && process.env && process.env.YARGS_MIN_NODE_VERSION) | ||
? Number(process.env.YARGS_MIN_NODE_VERSION) | ||
: 10; | ||
if (process && process.version) { | ||
const major = Number(process.version.match(/v([^.]+)/)[1]); | ||
if (major < minNodeVersion) { | ||
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`); | ||
} | ||
} | ||
// Creates a yargs-parser instance using Node.js standard libraries: | ||
const env = process ? process.env : {}; | ||
const parser = new YargsParser({ | ||
cwd: process.cwd, | ||
env: () => { | ||
return env; | ||
}, | ||
format, | ||
normalize, | ||
resolve, | ||
// TODO: figure out a way to combine ESM and CJS coverage, such that | ||
// we can exercise all the lines below: | ||
require: (path) => { | ||
if (typeof require !== 'undefined') { | ||
return require(path); | ||
} | ||
else if (path.match(/\.json$/)) { | ||
return readFileSync(path, 'utf8'); | ||
} | ||
else { | ||
throw Error('only .json config files are supported in ESM'); | ||
} | ||
} | ||
}); | ||
const yargsParser = function Parser(args, opts) { | ||
const result = parser.parse(args.slice(), opts); | ||
return result.argv; | ||
}; | ||
yargsParser.detailed = function (args, opts) { | ||
return parser.parse(args.slice(), opts); | ||
}; | ||
yargsParser.camelCase = camelCase; | ||
yargsParser.decamelize = decamelize; | ||
yargsParser.looksLikeNumber = looksLikeNumber; | ||
export default yargsParser; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export declare function camelCase(str: string): string; | ||
export declare function decamelize(str: string, joinString?: string): string; | ||
export declare function looksLikeNumber(x: null | undefined | number | string): boolean; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
export function camelCase(str) { | ||
// Handle the case where an argument is provided as camel case, e.g., fooBar. | ||
// by ensuring that the string isn't already mixed case: | ||
const isCamelCase = str !== str.toLowerCase() && str !== str.toUpperCase(); | ||
if (!isCamelCase) { | ||
str = str.toLocaleLowerCase(); | ||
} | ||
if (str.indexOf('-') === -1 && str.indexOf('_') === -1) { | ||
return str; | ||
} | ||
else { | ||
let camelcase = ''; | ||
let nextChrUpper = false; | ||
const leadingHyphens = str.match(/^-+/); | ||
for (let i = leadingHyphens ? leadingHyphens[0].length : 0; i < str.length; i++) { | ||
let chr = str.charAt(i); | ||
if (nextChrUpper) { | ||
nextChrUpper = false; | ||
chr = chr.toLocaleUpperCase(); | ||
} | ||
if (i !== 0 && (chr === '-' || chr === '_')) { | ||
nextChrUpper = true; | ||
} | ||
else if (chr !== '-' && chr !== '_') { | ||
camelcase += chr; | ||
} | ||
} | ||
return camelcase; | ||
} | ||
} | ||
export function decamelize(str, joinString) { | ||
const lowercase = str.toLocaleLowerCase(); | ||
joinString = joinString || '-'; | ||
let notCamelcase = ''; | ||
for (let i = 0; i < str.length; i++) { | ||
const chrLower = lowercase.charAt(i); | ||
const chrString = str.charAt(i); | ||
if (chrLower !== chrString && i > 0) { | ||
notCamelcase += `${joinString}${lowercase.charAt(i)}`; | ||
} | ||
else { | ||
notCamelcase += chrString; | ||
} | ||
} | ||
return notCamelcase; | ||
} | ||
export function looksLikeNumber(x) { | ||
if (x === null || x === undefined) | ||
return false; | ||
// if loaded from config, may already be a number. | ||
if (typeof x === 'number') | ||
return true; | ||
// hexadecimal. | ||
if (/^0x[0-9a-f]+$/i.test(x)) | ||
return true; | ||
// don't treat 0123 as a number; as it drops the leading '0'. | ||
if (x.length > 1 && x[0] === '0') | ||
return false; | ||
return /^[-]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export declare function tokenizeArgString(argString: string | any[]): string[]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// take an un-split argv string and tokenize it. | ||
export function tokenizeArgString(argString) { | ||
if (Array.isArray(argString)) { | ||
return argString.map(e => typeof e !== 'string' ? e + '' : e); | ||
} | ||
argString = argString.trim(); | ||
let i = 0; | ||
let prevC = null; | ||
let c = null; | ||
let opening = null; | ||
const args = []; | ||
for (let ii = 0; ii < argString.length; ii++) { | ||
prevC = c; | ||
c = argString.charAt(ii); | ||
// split on spaces unless we're in quotes. | ||
if (c === ' ' && !opening) { | ||
if (!(prevC === ' ')) { | ||
i++; | ||
} | ||
continue; | ||
} | ||
// don't split the string if we're in matching | ||
// opening or closing single and double quotes. | ||
if (c === opening) { | ||
opening = null; | ||
} | ||
else if ((c === "'" || c === '"') && !opening) { | ||
opening = c; | ||
} | ||
if (!args[i]) | ||
args[i] = ''; | ||
args[i] += c; | ||
} | ||
return args; | ||
} |
Oops, something went wrong.