Atlas › Test

completion, --get-yargs-completions, …) completes choices if previous option or one of its aliases requires a choice|occurrence=1

Exact test identity: mocha:v1|namespace=yargs@4153e0f097aeaf43a71a2530db6dda51dff2c544:main|file=test/completion.mjs|title=Completion default completion behavior calling yargs(./completion, --get-yargs-completions, …) completes choices if previous option or one of its aliases requires a choice|occurrence=1

Package
mocha:v1|namespace=yargs@4153e0f097aeaf43a71a2530db6dda51dff2c544:main|file=test/completion.mjs|title=Completion default completion behavior calling yargs(.
Suite / test hierarchy
completion, --get-yargs-completions, …) completes choices if previous option or one of its aliases requires a choice|occurrence=1
Test
completion, --get-yargs-completions, …) completes choices if previous option or one of its aliases requires a choice|occurrence=1
Introduced at
completion, --get-yargs-completions, …) completes choices if previous option or one of its aliases requires a choice|occurrence=1 Frontier kind: Test frontier
Covered ranges
526
Covered lines
2704
Covered files
18

Covered source

Expand a file to inspect source; the > gutter marks covered lines.

lib/yargs-factory.ts 1336 covered LOC · 272 ranges

Open complete file

1 > /* eslint-disable @typescript-eslint/no-unused-vars */ yargs-factory.ts
2 > // Platform agnostic entrypoint for yargs, i.e., this factory is used to
3 > // create an instance of yargs for CJS, ESM, Deno.
4 > //
5 > // Works by accepting a shim which shims methods that contain platform
6 > // specific logic.
7 > import {
8 > command as Command,
9 > CommandInstance,
10 > CommandHandler,
11 > CommandBuilderDefinition,
12 > CommandBuilder,
13 > CommandHandlerCallback,
14 > CommandHandlerDefinition,
15 > DefinitionOrCommandName,
16 > } from './command.js';
17 > import type {
18 > Dictionary,
19 > KeyOf,
20 > DictionaryKeyof,
21 > ValueOf,
22 > RequireDirectoryOptions,
23 > PlatformShim,
24 > RequireType,
25 > nil,
26 > } from './typings/common-types.js';
27 > import {
28 > assertNotStrictEqual,
29 > assertSingleKey,
30 > objectKeys,
31 > } from './typings/common-types.js';
32 > import {
33 > ArgsOutput,
34 > DetailedArguments as ParserDetailedArguments,
35 > Configuration as ParserConfiguration,
36 > Options as ParserOptions,
37 > ConfigCallback,
38 > CoerceCallback,
39 > } from './typings/yargs-parser-types.js';
40 > import {YError} from './yerror.js';
41 > import {UsageInstance, FailureFunction, usage as Usage} from './usage.js';
42 > import {argsert} from './argsert.js';
43 > import {
44 > completion as Completion,
45 > CompletionInstance,
46 > CompletionFunction,
47 > } from './completion.js';
48 > import {
49 > validation as Validation,
50 > ValidationInstance,
51 > KeyOrPos,
52 > } from './validation.js';
53 > import {objFilter} from './utils/obj-filter.js';
54 > import {applyExtends} from './utils/apply-extends.js';
55 > import {
56 > applyMiddleware,
57 > GlobalMiddleware,
58 > MiddlewareCallback,
59 > Middleware,
60 > } from './middleware.js';
61 > import {isPromise} from './utils/is-promise.js';
62 > import {maybeAsyncResult} from './utils/maybe-async-result.js';
63 > import setBlocking from './utils/set-blocking.js';
64 >
65 > export function YargsFactory(_shim: PlatformShim) {
66 > return (
67 > processArgs: string | string[] = [], yargs-factory.ts
68 > cwd = _shim.process.cwd(),
69 > parentRequire?: RequireType
70 > ): YargsInstance => {
71 > const yargs = new YargsInstance(processArgs, cwd, parentRequire, _shim);
72 > // Legacy yargs.argv interface, it's recommended that you use .parse().
73 > Object.defineProperty(yargs, 'argv', {
74 > get: () => {
75 > return yargs.parse(); yargs-factory.ts
77 > enumerable: true,
78 > });
79 > // an app should almost always have --version and --help,
80 > // if you *really* want to disable this use .help(false)/.version(false).
81 > yargs.help();
82 > yargs.version();
83 > return yargs;
85 > }
86 >
87 > // Used to expose private methods to other module-level classes,
88 > // such as the command parser and usage printer.
89 > const kCopyDoubleDash = Symbol('copyDoubleDash');
90 > const kCreateLogger = Symbol('copyDoubleDash');
91 > const kDeleteFromParserHintObject = Symbol('deleteFromParserHintObject');
92 > const kEmitWarning = Symbol('emitWarning');
93 > const kFreeze = Symbol('freeze');
94 > const kGetDollarZero = Symbol('getDollarZero');
95 > const kGetParserConfiguration = Symbol('getParserConfiguration');
96 > const kGetUsageConfiguration = Symbol('getUsageConfiguration');
97 > const kGuessLocale = Symbol('guessLocale');
98 > const kGuessVersion = Symbol('guessVersion');
99 > const kParsePositionalNumbers = Symbol('parsePositionalNumbers');
100 > const kPkgUp = Symbol('pkgUp');
101 > const kPopulateParserHintArray = Symbol('populateParserHintArray');
102 > const kPopulateParserHintSingleValueDictionary = Symbol(
103 > 'populateParserHintSingleValueDictionary'
104 > );
105 > const kPopulateParserHintArrayDictionary = Symbol(
106 > 'populateParserHintArrayDictionary'
107 > );
108 > const kPopulateParserHintDictionary = Symbol('populateParserHintDictionary');
109 > const kSanitizeKey = Symbol('sanitizeKey');
110 > const kSetKey = Symbol('setKey');
111 > const kUnfreeze = Symbol('unfreeze');
112 > const kValidateAsync = Symbol('validateAsync');
113 > const kGetCommandInstance = Symbol('getCommandInstance');
114 > const kGetContext = Symbol('getContext');
115 > const kGetHasOutput = Symbol('getHasOutput');
116 > const kGetLoggerInstance = Symbol('getLoggerInstance');
117 > const kGetParseContext = Symbol('getParseContext');
118 > const kGetUsageInstance = Symbol('getUsageInstance');
119 > const kGetValidationInstance = Symbol('getValidationInstance');
120 > const kHasParseCallback = Symbol('hasParseCallback');
121 > const kIsGlobalContext = Symbol('isGlobalContext');
122 > const kPostProcess = Symbol('postProcess');
123 > const kRebase = Symbol('rebase');
124 > const kReset = Symbol('reset');
125 > const kRunYargsParserAndExecuteCommands = Symbol(
126 > 'runYargsParserAndExecuteCommands'
127 > );
128 > const kRunValidation = Symbol('runValidation');
129 > const kSetHasOutput = Symbol('setHasOutput');
130 > const kTrackManuallySetKeys = Symbol('kTrackManuallySetKeys');
131 > const DEFAULT_LOCALE = 'en_US';
132 >
133 > export interface YargsInternalMethods {
134 > getCommandInstance(): CommandInstance;
135 > getContext(): Context;
136 > getHasOutput(): boolean;
137 > getLoggerInstance(): LoggerInstance;
138 > getParseContext(): object;
139 > getParserConfiguration(): Configuration;
140 > getUsageConfiguration(): UsageConfiguration;
141 > getUsageInstance(): UsageInstance;
142 > getValidationInstance(): ValidationInstance;
143 > hasParseCallback(): boolean;
144 > isGlobalContext(): boolean;
145 > postProcess<T extends Arguments | Promise<Arguments>>(
146 > argv: Arguments | Promise<Arguments>,
147 > populateDoubleDash: boolean,
148 > calledFromCommand: boolean,
149 > runGlobalMiddleware: boolean
150 > ): any;
151 > reset(aliases?: Aliases): YargsInstance;
152 > runValidation(
153 > aliases: Dictionary<string[]>,
154 > positionalMap: Dictionary<string[]>,
155 > parseErrors: Error | null,
156 > isDefaultCommand?: boolean
157 > ): (argv: Arguments) => void;
158 > runYargsParserAndExecuteCommands(
159 > args: string | string[] | null,
160 > shortCircuit?: boolean | null,
161 > calledFromCommand?: boolean,
162 > commandIndex?: number,
163 > helpOnly?: boolean
164 > ): Arguments | Promise<Arguments>;
165 > setHasOutput(): void;
166 > }
167 >
168 > export class YargsInstance {
169 > $0: string;
170 > argv?: Arguments;
171 > customScriptName = false;
172 > parsed: DetailedArguments | false = false;
173 >
174 > #command: CommandInstance;
175 > #cwd: string;
176 > // use context object to keep track of resets, subcommand execution, etc.,
177 > // submodules should modify and check the state of context as necessary:
178 > #context: Context = {commands: [], fullCommands: []};
179 > #completion: CompletionInstance | null = null;
180 > #completionCommand: string | null = null;
181 > #defaultShowHiddenOpt = 'show-hidden';
182 > #exitError: YError | string | nil = null;
183 > #detectLocale = true;
184 > #emittedWarnings: Dictionary<boolean> = {};
185 > #exitProcess = true;
186 > #frozens: FrozenYargsInstance[] = [];
187 > #globalMiddleware: GlobalMiddleware;
188 > #groups: Dictionary<string[]> = {};
189 > #hasOutput = false;
190 > #helpOpt: string | null = null;
191 > #isGlobalContext = true;
192 > #logger: LoggerInstance;
193 > #output = '';
194 > #options: Options;
195 > #parentRequire?: RequireType;
196 > #parserConfig: Configuration = {};
197 > #parseFn: ParseCallback | null = null;
198 > #parseContext: object | null = null;
199 > #pkgs: Dictionary<{[key: string]: string | {[key: string]: string}}> = {};
200 > #preservedGroups: Dictionary<string[]> = {};
201 > #processArgs: string | string[];
202 > #recommendCommands = false;
203 > #shim: PlatformShim;
204 > #strict = false;
205 > #strictCommands = false;
206 > #strictOptions = false;
207 > #usage: UsageInstance;
208 > #usageConfig: UsageConfiguration = {};
209 > #versionOpt: string | null = null;
210 > #validation: ValidationInstance;
211 >
212 > constructor(
213 > processArgs: string | string[] = [], yargs-factory.ts
214 > cwd: string,
215 > parentRequire: RequireType | undefined,
216 > shim: PlatformShim
217 > ) {
218 > this.#shim = shim;
219 > this.#processArgs = processArgs;
220 > this.#cwd = cwd;
221 > this.#parentRequire = parentRequire;
222 > this.#globalMiddleware = new GlobalMiddleware(this);
223 > this.$0 = this[kGetDollarZero]();
224 > // #command, #validation, and #usage are initialized on first reset:
225 > this[kReset]();
226 > this.#command = this!.#command;
227 > this.#usage = this!.#usage;
228 > this.#validation = this!.#validation;
229 > this.#options = this!.#options;
230 > this.#options.showHiddenOpt = this.#defaultShowHiddenOpt;
231 > this.#logger = this[kCreateLogger]();
232 > // y18n is a singleton intentionally, to prevent locales
233 > // from being loaded multiple times off disk. We reset
234 > // the language code whenever a new YargsInstance
235 > // is created mainly for unit tests.
236 > this.#shim.y18n.setLocale(DEFAULT_LOCALE);
237 > }
238 > addHelpOpt(opt?: string | false, msg?: string): YargsInstance { yargs-factory.ts
239 > const defaultHelpOpt = 'help'; yargs-factory.ts
240 > argsert('[string|boolean] [string]', [opt, msg], arguments.length);
241 >
242 > // nuke the key previously configured
243 > // to return help.
244 > if (this.#helpOpt) {
245 this[kDeleteFromParserHintObject](this.#helpOpt);
246 this.#helpOpt = null;
247 }
249 > if (opt === false && msg === undefined) return this;
250 >
251 > // use arguments, fallback to defaults for opt and msg
252 > this.#helpOpt = typeof opt === 'string' ? opt : defaultHelpOpt;
253 > this.boolean(this.#helpOpt);
254 > this.describe(
255 > this.#helpOpt,
256 > msg || this.#usage.deferY18nLookup('Show help')
257 > );
258 > return this;
259 > }
260 > help(opt?: string, msg?: string): YargsInstance { yargs-factory.ts
261 > return this.addHelpOpt(opt, msg); yargs-factory.ts
262 > }
264 > addShowHiddenOpt(opt?: string | false, msg?: string): YargsInstance {
265 argsert('[string|boolean] [string]', [opt, msg], arguments.length);
266 if (opt === false && msg === undefined) return this;
275 return this;
276 }
277 > showHidden(opt?: string | false, msg?: string): YargsInstance { yargs-factory.ts
278 return this.addShowHiddenOpt(opt, msg);
279 }
281 > alias(
282 > key: string | string[] | Dictionary<string | string[]>, yargs-factory.ts
283 > value?: string | string[]
284 > ): YargsInstance {
285 > argsert(
286 > '<object|string|array> [string|array]',
287 > [key, value],
288 > arguments.length
289 > );
290 > this[kPopulateParserHintArrayDictionary](
291 > this.alias.bind(this),
292 > 'alias',
293 > key,
294 > value
295 > );
296 > return this;
297 > }
298 > array(keys: string | string[]): YargsInstance { yargs-factory.ts
299 argsert('<array|string>', [keys], arguments.length);
300 this[kPopulateParserHintArray]('array', keys);
302 return this;
303 }
304 > boolean(keys: string | string[]): YargsInstance { yargs-factory.ts
305 > argsert('<array|string>', [keys], arguments.length); yargs-factory.ts
306 > this[kPopulateParserHintArray]('boolean', keys);
307 > this[kTrackManuallySetKeys](keys);
308 > return this;
309 > }
310 > check( yargs-factory.ts
311 f: (argv: Arguments, options: Options) => any,
312 global?: boolean
345 return this;
346 }
347 > choices( yargs-factory.ts
348 > key: string | string[] | Dictionary<string | string[]>, yargs-factory.ts
349 > value?: string | string[]
350 > ): YargsInstance {
351 > argsert(
352 > '<object|string|array> [string|array]',
353 > [key, value],
354 > arguments.length
355 > );
356 > this[kPopulateParserHintArrayDictionary](
357 > this.choices.bind(this),
358 > 'choices',
359 > key,
360 > value
361 > );
362 > return this;
363 > }
364 > coerce( yargs-factory.ts
365 keys: string | string[] | Dictionary<CoerceCallback>,
366 value?: CoerceCallback
432 return this;
433 }
434 > conflicts( yargs-factory.ts
435 key1: string | Dictionary<string | string[]>,
436 key2?: string | string[]
440 return this;
441 }
442 > config( yargs-factory.ts
443 key: string | string[] | Dictionary = 'config',
444 msg?: string | ConfigCallback,
480 return this;
481 }
482 > completion( yargs-factory.ts
483 > cmd?: string, yargs-factory.ts
484 > desc?: string | false | CompletionFunction,
485 > fn?: CompletionFunction
486 > ): YargsInstance {
487 > argsert(
488 > '[string] [string|boolean|function] [function]',
489 > [cmd, desc, fn],
490 > arguments.length
491 > );
492 >
493 > // a function to execute when generating
494 > // completions can be provided as the second
495 > // or third argument to completion.
496 > if (typeof desc === 'function') {
497 fn = desc;
498 desc = undefined;
499 }
501 > // register the completion command.
502 > this.#completionCommand = cmd || this.#completionCommand || 'completion';
503 > if (!desc && desc !== false) {
504 desc = 'generate completion script';
505 }
506 > this.command(this.#completionCommand, desc); yargs-factory.ts
507 >
508 > // a function can be provided
509 > if (fn) this.#completion!.registerFunction(fn);
510 >
511 > return this;
512 > }
513 > command( yargs-factory.ts
514 > cmd: string | CommandHandlerDefinition | DefinitionOrCommandName[], yargs-factory.ts
515 > description?: CommandHandler['description'],
516 > builder?: CommandBuilderDefinition | CommandBuilder,
517 > handler?: CommandHandlerCallback,
518 > middlewares?: Middleware[],
519 > deprecated?: boolean
520 > ): YargsInstance {
521 > argsert(
522 > '<string|array|object> [string|boolean] [function|object] [function] [array] [boolean|string]',
523 > [cmd, description, builder, handler, middlewares, deprecated],
524 > arguments.length
525 > );
526 > this.#command.addHandler(
527 > cmd,
528 > description,
529 > builder,
530 > handler,
531 > middlewares,
532 > deprecated
533 > );
534 > return this;
535 > }
536 > commands( yargs-factory.ts
537 cmd: string | CommandHandlerDefinition | DefinitionOrCommandName[],
538 description?: CommandHandler['description'],
551 );
552 }
553 > commandDir(dir: string, opts?: RequireDirectoryOptions): YargsInstance { yargs-factory.ts
554 argsert('<string> [object]', [dir, opts], arguments.length);
555 const req = this.#parentRequire || this.#shim.require;
557 return this;
558 }
559 > count(keys: string | string[]): YargsInstance { yargs-factory.ts
560 argsert('<array|string>', [keys], arguments.length);
561 this[kPopulateParserHintArray]('count', keys);
563 return this;
564 }
565 > default( yargs-factory.ts
566 key: string | string[] | Dictionary<any>,
567 value?: any,
592 return this;
593 }
594 > defaults( yargs-factory.ts
595 key: string | string[] | Dictionary<any>,
596 value?: any,
599 return this.default(key, value, defaultDescription);
600 }
601 > demandCommand( yargs-factory.ts
602 min = 1,
603 max?: number | string,
627 return this;
628 }
629 > demand( yargs-factory.ts
630 keys: string | string[] | Dictionary<string | undefined> | number,
631 max?: number | string[] | string | true,
664 return this;
665 }
666 > demandOption( yargs-factory.ts
667 keys: string | string[] | Dictionary<string | undefined>,
668 msg?: string
677 return this;
678 }
679 > deprecateOption(option: string, message: string | boolean): YargsInstance { yargs-factory.ts
680 argsert('<string> [string|boolean]', [option, message], arguments.length);
681 this.#options.deprecatedOptions[option] = message;
682 return this;
683 }
684 > describe( yargs-factory.ts
685 > keys: string | string[] | Dictionary<string>, yargs-factory.ts
686 > description?: string
687 > ): YargsInstance {
688 > argsert(
689 > '<object|string|array> [string]',
690 > [keys, description],
691 > arguments.length
692 > );
693 > this[kSetKey](keys, true);
694 > this.#usage.describe(keys, description);
695 > return this;
696 > }
697 > detectLocale(detect: boolean): YargsInstance { yargs-factory.ts
698 argsert('<boolean>', [detect], arguments.length);
699 this.#detectLocale = detect;
700 return this;
701 }
702 > // as long as options.envPrefix is not undefined, yargs-factory.ts
703 > // parser will apply env vars matching prefix to argv
704 > env(prefix?: string | false): YargsInstance {
705 argsert('[string|boolean]', [prefix], arguments.length);
706 if (prefix === false) delete this.#options.envPrefix;
708 return this;
709 }
710 > epilogue(msg: string): YargsInstance { yargs-factory.ts
711 argsert('<string>', [msg], arguments.length);
712 this.#usage.epilog(msg);
713 return this;
714 }
715 > epilog(msg: string): YargsInstance { yargs-factory.ts
716 return this.epilogue(msg);
717 }
718 > example( yargs-factory.ts
719 cmd: string | [string, string?][],
720 description?: string
730 return this;
731 }
732 > // maybe exit, always capture context about why we wanted to exit: yargs-factory.ts
733 > exit(code: number, err?: YError | string): void {
734 > this.#hasOutput = true; yargs-factory.ts
735 > this.#exitError = err;
736 > if (this.#exitProcess) this.#shim.process.exit(code);
737 > }
738 > exitProcess(enabled = true): YargsInstance { yargs-factory.ts
739 argsert('[boolean]', [enabled], arguments.length);
740 this.#exitProcess = enabled;
741 return this;
742 }
743 > fail(f: FailureFunction | boolean): YargsInstance { yargs-factory.ts
744 argsert('<function|boolean>', [f], arguments.length);
745 if (typeof f === 'boolean' && f !== false) {
751 return this;
752 }
753 > getAliases(): Dictionary<string[]> { yargs-factory.ts
754 > return this.parsed ? this.parsed.aliases : {}; yargs-factory.ts
755 > }
756 > async getCompletion( yargs-factory.ts
757 args: string[],
758 done?: (err: Error | null, completions: string[] | undefined) => void
770 }
771 }
772 > getDemandedOptions() { yargs-factory.ts
773 argsert([], 0);
774 return this.#options.demandedOptions;
775 }
776 > getDemandedCommands() { yargs-factory.ts
777 argsert([], 0);
778 return this.#options.demandedCommands;
779 }
780 > getDeprecatedOptions() { yargs-factory.ts
781 argsert([], 0);
782 return this.#options.deprecatedOptions;
783 }
784 > getDetectLocale(): boolean { yargs-factory.ts
785 return this.#detectLocale;
786 }
787 > getExitProcess(): boolean { yargs-factory.ts
788 return this.#exitProcess;
789 }
790 > // combine explicit and preserved groups. explicit groups should be first yargs-factory.ts
791 > getGroups(): Dictionary<string[]> {
792 > return Object.assign({}, this.#groups, this.#preservedGroups); yargs-factory.ts
793 > }
794 > getHelp(): Promise<string> { yargs-factory.ts
795 this.#hasOutput = true;
796 if (!this.#usage.hasCachedHelpMessage()) {
821 return Promise.resolve(this.#usage.help());
822 }
823 > getOptions(): Options { yargs-factory.ts
824 > return this.#options; yargs-factory.ts
825 > }
826 > getStrict(): boolean { yargs-factory.ts
827 return this.#strict;
828 }
829 > getStrictCommands(): boolean { yargs-factory.ts
830 return this.#strictCommands;
831 }
832 > getStrictOptions(): boolean { yargs-factory.ts
833 return this.#strictOptions;
834 }
835 > global(globals: string | string[], global?: boolean): YargsInstance { yargs-factory.ts
836 argsert('<string|array> [boolean]', [globals, global], arguments.length);
837 globals = ([] as string[]).concat(globals);
847 return this;
848 }
849 > group(opts: string | string[], groupName: string): YargsInstance { yargs-factory.ts
850 argsert('<string|array> <string>', [opts, groupName], arguments.length);
851 const existing =
862 return this;
863 }
864 > hide(key: string): YargsInstance { yargs-factory.ts
865 argsert('<string>', [key], arguments.length);
866 this.#options.hiddenOptions.push(key);
867 return this;
868 }
869 > implies( yargs-factory.ts
870 key: string | Dictionary<KeyOrPos | KeyOrPos[]>,
871 value?: KeyOrPos | KeyOrPos[]
879 return this;
880 }
881 > locale(locale?: string): YargsInstance | string { yargs-factory.ts
882 > argsert('[string]', [locale], arguments.length); yargs-factory.ts
883 > if (locale === undefined) {
884 this[kGuessLocale]();
885 return this.#shim.y18n.getLocale();
886 }
887 > this.#detectLocale = false; yargs-factory.ts
888 > this.#shim.y18n.setLocale(locale);
889 > return this;
890 > }
891 > middleware( yargs-factory.ts
892 callback: MiddlewareCallback | MiddlewareCallback[],
893 applyBeforeValidation?: boolean,
900 );
901 }
902 > nargs( yargs-factory.ts
903 key: string | string[] | Dictionary<number>,
904 value?: number
913 return this;
914 }
915 > normalize(keys: string | string[]): YargsInstance { yargs-factory.ts
916 argsert('<array|string>', [keys], arguments.length);
917 this[kPopulateParserHintArray]('normalize', keys);
918 return this;
919 }
920 > number(keys: string | string[]): YargsInstance { yargs-factory.ts
921 > argsert('<array|string>', [keys], arguments.length); yargs-factory.ts
922 > this[kPopulateParserHintArray]('number', keys);
923 > this[kTrackManuallySetKeys](keys);
924 > return this;
925 > }
926 > option( yargs-factory.ts
927 > key: string | Dictionary<OptionDefinition>, yargs-factory.ts
928 > opt?: OptionDefinition
929 > ): YargsInstance {
930 > argsert('<string|object> [object]', [key, opt], arguments.length);
931 > if (typeof key === 'object') {
932 > Object.keys(key).forEach(k => { yargs-factory.ts
933 > this.options(k, key[k]);
934 > });
935 > } else { yargs-factory.ts
936 > if (typeof opt !== 'object') {
937 opt = {};
938 }
940 > this[kTrackManuallySetKeys](key);
941 >
942 > // Warn about version name collision
943 > // Addresses: https://github.com/yargs/yargs/issues/1979
944 > if (this.#versionOpt && (key === 'version' || opt?.alias === 'version')) {
945 this[kEmitWarning](
946 [
956 );
957 }
959 > this.#options.key[key] = true; // track manually set keys.
960 >
961 > if (opt.alias) this.alias(key, opt.alias);
962 >
963 > const deprecate = opt.deprecate || opt.deprecated;
964 >
965 > if (deprecate) {
966 this.deprecateOption(key, deprecate);
967 }
969 > const demand = opt.demand || opt.required || opt.require;
970 >
971 > // A required option can be specified via "demand: true".
972 > if (demand) {
973 this.demand(key, demand);
974 }
976 > if (opt.demandOption) {
977 this.demandOption(
978 key,
980 );
981 }
983 > if (opt.conflicts) {
984 this.conflicts(key, opt.conflicts);
985 }
987 > if ('default' in opt) {
988 this.default(key, opt.default);
989 }
991 > if (opt.implies !== undefined) {
992 this.implies(key, opt.implies);
993 }
995 > if (opt.nargs !== undefined) {
996 this.nargs(key, opt.nargs);
997 }
999 > if (opt.config) {
1000 this.config(key, opt.configParser);
1001 }
1003 > if (opt.normalize) {
1004 this.normalize(key);
1005 }
1007 > if (opt.choices) {
1008 > this.choices(key, opt.choices); yargs-factory.ts
1009 > }
1011 > if (opt.coerce) {
1012 this.coerce(key, opt.coerce);
1013 }
1015 > if (opt.group) {
1016 this.group(key, opt.group);
1017 }
1019 > if (opt.boolean || opt.type === 'boolean') {
1020 this.boolean(key);
1021 if (opt.alias) this.boolean(opt.alias);
1022 }
1024 > if (opt.array || opt.type === 'array') {
1025 this.array(key);
1026 if (opt.alias) this.array(opt.alias);
1027 }
1029 > if (opt.number || opt.type === 'number') {
1030 > this.number(key); yargs-factory.ts
1031 > if (opt.alias) this.number(opt.alias);
1032 > }
1034 > if (opt.string || opt.type === 'string') {
1035 this.string(key);
1036 if (opt.alias) this.string(opt.alias);
1037 }
1039 > if (opt.count || opt.type === 'count') {
1040 this.count(key);
1041 }
1043 > if (typeof opt.global === 'boolean') {
1044 this.global(key, opt.global);
1045 }
1047 > if (opt.defaultDescription) {
1048 this.#options.defaultDescription[key] = opt.defaultDescription;
1049 }
1051 > if (opt.skipValidation) {
1052 this.skipValidation(key);
1053 }
1055 > const desc = opt.describe || opt.description || opt.desc;
1056 > const descriptions = this.#usage.getDescriptions();
1057 > if (
1058 > !Object.prototype.hasOwnProperty.call(descriptions, key) ||
1059 typeof desc === 'string'
1060 > ) { yargs-factory.ts
1061 > this.describe(key, desc); yargs-factory.ts
1062 > }
1064 > if (opt.hidden) {
1065 this.hide(key);
1066 }
1068 > if (opt.requiresArg) {
1069 this.requiresArg(key);
1070 }
1071 > } yargs-factory.ts
1072 >
1073 > return this;
1074 > }
1075 > options( yargs-factory.ts
1076 > key: string | Dictionary<OptionDefinition>, yargs-factory.ts
1077 > opt?: OptionDefinition
1078 > ): YargsInstance {
1079 > return this.option(key, opt);
1080 > }
1081 > parse( yargs-factory.ts
1082 > args?: string | string[], yargs-factory.ts
1083 > shortCircuit?: object | ParseCallback | boolean,
1084 > _parseFn?: ParseCallback
1085 > ): Arguments | Promise<Arguments> {
1086 > argsert(
1087 > '[string|array] [function|boolean|object] [function]',
1088 > [args, shortCircuit, _parseFn],
1089 > arguments.length
1090 > );
1091 > this[kFreeze](); // Push current state of parser onto stack.
1092 > if (typeof args === 'undefined') {
1093 > args = this.#processArgs; yargs-factory.ts
1094 > }
1096 > // a context object can optionally be provided, this allows
1097 > // additional information to be passed to a command handler.
1098 > if (typeof shortCircuit === 'object') {
1099 this.#parseContext = shortCircuit;
1100 shortCircuit = _parseFn;
1101 }
1103 > // by providing a function as a second argument to
1104 > // parse you can capture output that would otherwise
1105 > // default to printing to stdout/stderr.
1106 > if (typeof shortCircuit === 'function') {
1107 this.#parseFn = shortCircuit as ParseCallback;
1108 shortCircuit = false;
1109 }
1110 > // completion short-circuits the parsing process, yargs-factory.ts
1111 > // skipping validation, etc.
1112 > if (!shortCircuit) this.#processArgs = args;
1113 >
1114 > if (this.#parseFn) this.#exitProcess = false;
1115 >
1116 > const parsed = this[kRunYargsParserAndExecuteCommands](
1117 > args,
1118 > !!shortCircuit
1119 > );
1120 > const tmpParsed = this.parsed;
1121 > this.#completion!.setParsed(this.parsed as DetailedArguments);
1122 > if (isPromise(parsed)) {
1123 return parsed
1124 .then(argv => {
1140 this.parsed = tmpParsed;
1141 });
1142 > } else { yargs-factory.ts
1143 > if (this.#parseFn) this.#parseFn(this.#exitError, parsed, this.#output); yargs-factory.ts
1144 > this[kUnfreeze](); // Pop the stack.
1145 > this.parsed = tmpParsed;
1146 > }
1147 > return parsed;
1148 > }
1149 > parseAsync( yargs-factory.ts
1150 args?: string | string[],
1151 shortCircuit?: object | ParseCallback | boolean,
1157 : maybePromise;
1158 }
1159 > parseSync( yargs-factory.ts
1160 args?: string | string[],
1161 shortCircuit?: object | ParseCallback | boolean,
1170 return maybePromise;
1171 }
1172 > parserConfiguration(config: Configuration) { yargs-factory.ts
1173 argsert('<object>', [config], arguments.length);
1174 this.#parserConfig = config;
1175 return this;
1176 }
1177 > pkgConf(key: string, rootPath?: string): YargsInstance { yargs-factory.ts
1178 argsert('<string> [string]', [key, rootPath], arguments.length);
1179 let conf = null;
1197 return this;
1198 }
1199 > positional(key: string, opts: PositionalDefinition): YargsInstance { yargs-factory.ts
1200 argsert('<string> <object>', [key, opts], arguments.length);
1201 // .positional() only supports a subset of the configuration
1244 return this.option(key, opts);
1245 }
1246 > recommendCommands(recommend = true): YargsInstance { yargs-factory.ts
1247 argsert('[boolean]', [recommend], arguments.length);
1248 this.#recommendCommands = recommend;
1249 return this;
1250 }
1251 > required( yargs-factory.ts
1252 keys: string | string[] | Dictionary<string | undefined> | number,
1253 max?: number | string[] | string | true,
1256 return this.demand(keys, max, msg);
1257 }
1258 > require( yargs-factory.ts
1259 keys: string | string[] | Dictionary<string | undefined> | number,
1260 max?: number | string[] | string | true,
1263 return this.demand(keys, max, msg);
1264 }
1265 > requiresArg(keys: string | string[] | Dictionary): YargsInstance { yargs-factory.ts
1266 // the 2nd parameter [number] in the argsert the assertion is mandatory
1267 // as populateParserHintSingleValueDictionary recursively calls requiresArg
1285 return this;
1286 }
1287 > showCompletionScript($0?: string, cmd?: string): YargsInstance { yargs-factory.ts
1288 argsert('[string] [string]', [$0, cmd], arguments.length);
1289 $0 = $0 || this.$0;
1296 return this;
1297 }
1298 > showHelp( yargs-factory.ts
1299 level: 'error' | 'log' | ((message: string) => void)
1300 ): YargsInstance {
1331 return this;
1332 }
1333 > scriptName(scriptName: string): YargsInstance { yargs-factory.ts
1334 this.customScriptName = true;
1335 this.$0 = scriptName;
1336 return this;
1337 }
1338 > showHelpOnFail(enabled?: string | boolean, message?: string): YargsInstance { yargs-factory.ts
1339 argsert('[boolean|string] [string]', [enabled, message], arguments.length);
1340 this.#usage.showHelpOnFail(enabled, message);
1341 return this;
1342 }
1343 > showVersion( yargs-factory.ts
1344 level: 'error' | 'log' | ((message: string) => void)
1345 ): YargsInstance {
1348 return this;
1349 }
1350 > skipValidation(keys: string | string[]): YargsInstance { yargs-factory.ts
1351 argsert('<array|string>', [keys], arguments.length);
1352 this[kPopulateParserHintArray]('skipValidation', keys);
1353 return this;
1354 }
1355 > strict(enabled?: boolean): YargsInstance { yargs-factory.ts
1356 argsert('[boolean]', [enabled], arguments.length);
1357 this.#strict = enabled !== false;
1358 return this;
1359 }
1360 > strictCommands(enabled?: boolean): YargsInstance { yargs-factory.ts
1361 argsert('[boolean]', [enabled], arguments.length);
1362 this.#strictCommands = enabled !== false;
1363 return this;
1364 }
1365 > strictOptions(enabled?: boolean): YargsInstance { yargs-factory.ts
1366 argsert('[boolean]', [enabled], arguments.length);
1367 this.#strictOptions = enabled !== false;
1368 return this;
1369 }
1370 > string(keys: string | string[]): YargsInstance { yargs-factory.ts
1371 argsert('<array|string>', [keys], arguments.length);
1372 this[kPopulateParserHintArray]('string', keys);
1374 return this;
1375 }
1376 > terminalWidth(): number | null { yargs-factory.ts
1377 argsert([], 0);
1378 return this.#shim.process.stdColumns;
1379 }
1380 > updateLocale(obj: Dictionary<string>): YargsInstance { yargs-factory.ts
1381 return this.updateStrings(obj);
1382 }
1383 > updateStrings(obj: Dictionary<string>): YargsInstance { yargs-factory.ts
1384 argsert('<object>', [obj], arguments.length);
1385 this.#detectLocale = false;
1387 return this;
1388 }
1389 > usage( yargs-factory.ts
1390 msg: string | null,
1391 description?: CommandHandler['description'],
1415 }
1416 }
1417 > usageConfiguration(config: UsageConfiguration) { yargs-factory.ts
1418 argsert('<object>', [config], arguments.length);
1419 this.#usageConfig = config;
1420 return this;
1421 }
1422 > version(opt?: string | false, msg?: string, ver?: string): YargsInstance { yargs-factory.ts
1423 > const defaultVersionOpt = 'version'; yargs-factory.ts
1424 > argsert(
1425 > '[boolean|string] [string] [string]',
1426 > [opt, msg, ver],
1427 > arguments.length
1428 > );
1429 >
1430 > // nuke the key previously configured
1431 > // to return version #.
1432 > if (this.#versionOpt) {
1433 this[kDeleteFromParserHintObject](this.#versionOpt);
1434 this.#usage.version(undefined);
1435 this.#versionOpt = null;
1436 }
1438 > if (arguments.length === 0) {
1439 > ver = this[kGuessVersion]();
1440 > opt = defaultVersionOpt;
1441 > } else if (arguments.length === 1) {
1442 if (opt === false) {
1443 // disable default 'version' key.
1450 msg = undefined;
1451 }
1453 > this.#versionOpt = typeof opt === 'string' ? opt : defaultVersionOpt;
1454 > msg = msg || this.#usage.deferY18nLookup('Show version number');
1455 >
1456 > this.#usage.version(ver || undefined);
1457 > this.boolean(this.#versionOpt);
1458 > this.describe(this.#versionOpt, msg);
1459 > return this;
1460 > }
1461 > wrap(cols: number | nil): YargsInstance { yargs-factory.ts
1462 argsert('<number|null|undefined>', [cols], arguments.length);
1463 this.#usage.wrap(cols);
1464 return this;
1465 }
1467 > // to simplify the parsing of positionals in commands,
1468 > // we temporarily populate '--' rather than _, with arguments
1469 > // after the '--' directive. After the parse, we copy these back.
1470 > [kCopyDoubleDash](argv: Arguments): any {
1471 > if (!argv._ || !argv['--']) return argv; yargs-factory.ts
1472 // eslint-disable-next-line prefer-spread
1473 argv._.push.apply(argv._, argv['--']);
1482 return argv;
1483 }
1484 > [kCreateLogger](): LoggerInstance { yargs-factory.ts
1485 > return { yargs-factory.ts
1486 > log: (...args: any[]) => {
1487 > if (!this[kHasParseCallback]()) console.log(...args); yargs-factory.ts
1488 > this.#hasOutput = true;
1489 > if (this.#output.length) this.#output += '\n';
1490 > this.#output += args.join(' ');
1491 > }, yargs-factory.ts
1492 > error: (...args: any[]) => {
1493 if (!this[kHasParseCallback]()) console.error(...args);
1494 this.#hasOutput = true;
1495 if (this.#output.length) this.#output += '\n';
1496 this.#output += args.join(' ');
1497 > }, yargs-factory.ts
1498 > };
1499 > }
1500 > [kDeleteFromParserHintObject](optionKey: string) { yargs-factory.ts
1501 // delete from all parsing hints:
1502 // boolean, array, key, alias, etc.
1515 delete this.#usage.getDescriptions()[optionKey];
1516 }
1517 > [kEmitWarning]( yargs-factory.ts
1518 warning: string,
1519 type: string | undefined,
1526 }
1527 }
1528 > [kFreeze]() { yargs-factory.ts
1529 > this.#frozens.push({ yargs-factory.ts
1530 > options: this.#options,
1531 > configObjects: this.#options.configObjects.slice(0),
1532 > exitProcess: this.#exitProcess,
1533 > groups: this.#groups,
1534 > strict: this.#strict,
1535 > strictCommands: this.#strictCommands,
1536 > strictOptions: this.#strictOptions,
1537 > completionCommand: this.#completionCommand,
1538 > output: this.#output,
1539 > exitError: this.#exitError!,
1540 > hasOutput: this.#hasOutput,
1541 > parsed: this.parsed,
1542 > parseFn: this.#parseFn!,
1543 > parseContext: this.#parseContext,
1544 > });
1545 > this.#usage.freeze();
1546 > this.#validation.freeze();
1547 > this.#command.freeze();
1548 > this.#globalMiddleware.freeze();
1549 > }
1550 > [kGetDollarZero](): string { yargs-factory.ts
1551 > let $0 = ''; yargs-factory.ts
1552 > // ignore the node bin, specify this in your
1553 > // bin file with #!/usr/bin/env node
1554 > let default$0: string[];
1555 > if (
1556 > /\b(node|iojs|electron|bun)(\.exe)?$/.test(this.#shim.process.argv()[0])
1557 > ) {
1558 default$0 = this.#shim.process.argv().slice(1, 2);
1559 > } else { yargs-factory.ts
1560 > default$0 = this.#shim.process.argv().slice(0, 1); yargs-factory.ts
1561 > }
1563 > $0 = default$0
1564 > .map(x => {
1565 > const b = this[kRebase](this.#cwd, x);
1566 > return x.match(/^(\/|([a-zA-Z]:)?\\)/) && b.length < x.length ? b : x;
1567 > })
1568 > .join(' ')
1569 > .trim();
1570 >
1571 > if (
1572 > this.#shim.getEnv('_') &&
1573 > this.#shim.getProcessArgvBin() === this.#shim.getEnv('_')
1574 > ) {
1575 $0 = this.#shim
1576 .getEnv('_')!
1580 );
1581 }
1582 > return $0; yargs-factory.ts
1583 > }
1584 > [kGetParserConfiguration](): Configuration { yargs-factory.ts
1585 > return this.#parserConfig; yargs-factory.ts
1586 > }
1587 > [kGetUsageConfiguration](): UsageConfiguration { yargs-factory.ts
1588 return this.#usageConfig;
1589 }
1590 > [kGuessLocale]() { yargs-factory.ts
1591 > if (!this.#detectLocale) return; yargs-factory.ts
1592 > const locale = yargs-factory.ts
1593 > this.#shim.getEnv('LC_ALL') ||
1594 > this.#shim.getEnv('LC_MESSAGES') || yargs-factory.ts
1595 > this.#shim.getEnv('LANG') ||
1596 > this.#shim.getEnv('LANGUAGE') ||
1597 > 'en_US';
1598 > this.locale(locale.replace(/[.:].*/, ''));
1599 > }
1600 > [kGuessVersion](): string { yargs-factory.ts
1601 > const obj = this[kPkgUp](); yargs-factory.ts
1602 > return (obj.version as string) || 'unknown';
1603 > }
1604 > // We wait to coerce numbers for positionals until after the initial parse. yargs-factory.ts
1605 > // This allows commands to configure number parsing on a positional by
1606 > // positional basis:
1607 > [kParsePositionalNumbers](argv: Arguments): any {
1608 > const args: (string | number)[] = argv['--'] ? argv['--'] : argv._; yargs-factory.ts
1609 >
1610 > for (let i = 0, arg; (arg = args[i]) !== undefined; i++) {
1611 > if ( yargs-factory.ts
1612 > this.#shim.Parser.looksLikeNumber(arg) &&
1613 Number.isSafeInteger(Math.floor(parseFloat(`${arg}`)))
1614 > ) { yargs-factory.ts
1615 args[i] = Number(arg);
1616 }
1617 > } yargs-factory.ts
1618 > return argv; yargs-factory.ts
1619 > }
1620 > [kPkgUp](rootPath?: string) { yargs-factory.ts
1621 > const npath = rootPath || '*'; yargs-factory.ts
1622 > if (this.#pkgs[npath]) return this.#pkgs[npath];
1623 >
1624 > let obj = {};
1625 > try {
1626 > let startDir = rootPath || this.#shim.mainFilename;
1627 > // If a file path is provided for root, remove the file and keep path.
1628 > if (this.#shim.path.extname(startDir)) {
1629 startDir = this.#shim.path.dirname(startDir);
1630 }
1632 > const pkgJsonPath = this.#shim.findUp(
1633 > startDir,
1634 > (dir: string[], names: string[]) => {
1635 > if (names.includes('package.json')) {
1636 > return 'package.json';
1637 > } else {
1638 return undefined;
1639 }
1640 > } yargs-factory.ts
1641 > );
1642 > assertNotStrictEqual(pkgJsonPath, undefined, this.#shim);
1643 > obj = JSON.parse(this.#shim.readFileSync(pkgJsonPath, 'utf8'));
1644 > // eslint-disable-next-line no-empty
1645 > } catch (_noop) {}
1646 >
1647 > this.#pkgs[npath] = obj || {};
1648 > return this.#pkgs[npath];
1649 > }
1650 > [kPopulateParserHintArray]<T extends KeyOf<Options, string[]>>( yargs-factory.ts
1651 > type: T, yargs-factory.ts
1652 > keys: string | string[]
1653 > ) {
1654 > keys = ([] as string[]).concat(keys);
1655 > keys.forEach(key => {
1656 > key = this[kSanitizeKey](key);
1657 > this.#options[type].push(key);
1658 > });
1659 > }
1660 > [kPopulateParserHintSingleValueDictionary]< yargs-factory.ts
1661 > T extends yargs-factory.ts
1662 > | Exclude<DictionaryKeyof<Options>, DictionaryKeyof<Options, any[]>>
1663 > | 'default',
1664 > K extends keyof Options[T] & string = keyof Options[T] & string,
1665 > V extends ValueOf<Options[T]> = ValueOf<Options[T]>,
1666 > >(
1667 > builder: (key: K, value: V, ...otherArgs: any[]) => YargsInstance,
1668 > type: T,
1669 > key: K | K[] | {[key in K]: V | undefined},
1670 > value?: V
1671 > ) {
1672 > this[kPopulateParserHintDictionary]<T, K, V>(
1673 > builder,
1674 > type,
1675 > key,
1676 > value,
1677 > (type, key, value) => {
1678 > this.#options[type][key] = value as ValueOf<Options[T]>;
1679 > }
1680 > );
1681 > }
1682 > [kPopulateParserHintArrayDictionary]< yargs-factory.ts
1683 > T extends DictionaryKeyof<Options, any[]>, yargs-factory.ts
1684 > K extends keyof Options[T] & string = keyof Options[T] & string,
1685 > V extends ValueOf<ValueOf<Options[T]>> | ValueOf<ValueOf<Options[T]>>[] =
1686 > ValueOf<ValueOf<Options[T]>> | ValueOf<ValueOf<Options[T]>>[],
1687 > >(
1688 > builder: (key: K, value: V, ...otherArgs: any[]) => YargsInstance,
1689 > type: T,
1690 > key: K | K[] | {[key in K]: V},
1691 > value?: V
1692 > ) {
1693 > this[kPopulateParserHintDictionary]<T, K, V>(
1694 > builder,
1695 > type,
1696 > key,
1697 > value,
1698 > (type, key, value) => {
1699 > this.#options[type][key] = (
1700 > this.#options[type][key] || ([] as Options[T][keyof Options[T]])
1701 > ).concat(value);
1702 > }
1703 > );
1704 > }
1705 > [kPopulateParserHintDictionary]< yargs-factory.ts
1706 > T extends keyof Options, yargs-factory.ts
1707 > K extends keyof Options[T],
1708 > V,
1709 > >(
1710 > builder: (key: K, value: V, ...otherArgs: any[]) => YargsInstance,
1711 > type: T,
1712 > key: K | K[] | {[key in K]: V | undefined},
1713 > value: V | undefined,
1714 > singleKeyHandler: (type: T, key: K, value?: V) => void
1715 > ) {
1716 > if (Array.isArray(key)) {
1717 // an array of keys with one value ['x', 'y', 'z'], function parse () {}
1718 key.forEach(k => {
1719 builder(k, value!);
1720 });
1721 > } else if ( yargs-factory.ts
1722 > ((key): key is {[key in K]: V} => typeof key === 'object')(key)
1723 > ) {
1724 // an object of key value pairs: {'x': parse () {}, 'y': parse() {}}
1725 for (const k of objectKeys(key)) {
1726 builder(k, key[k]);
1727 }
1728 > } else { yargs-factory.ts
1729 > singleKeyHandler(type, this[kSanitizeKey](key), value);
1730 > }
1731 > }
1732 > [kSanitizeKey](key: any) { yargs-factory.ts
1733 > if (key === '__proto__') return '___proto___'; yargs-factory.ts
1734 > return key;
1735 > }
1736 > [kSetKey]( yargs-factory.ts
1737 > key: string | string[] | Dictionary<string | boolean>, yargs-factory.ts
1738 > set?: boolean | string
1739 > ) {
1740 > this[kPopulateParserHintSingleValueDictionary](
1741 > this[kSetKey].bind(this),
1742 > 'key',
1743 > key,
1744 > set
1745 > );
1746 > return this;
1747 > }
1748 > [kUnfreeze]() { yargs-factory.ts
1749 > const frozen = this.#frozens.pop(); yargs-factory.ts
1750 > assertNotStrictEqual(frozen, undefined, this.#shim);
1751 > let configObjects: Dictionary[];
1752 > ({
1753 > options: this.#options,
1754 > configObjects,
1755 > exitProcess: this.#exitProcess,
1756 > groups: this.#groups,
1757 > output: this.#output,
1758 > exitError: this.#exitError,
1759 > hasOutput: this.#hasOutput,
1760 > parsed: this.parsed,
1761 > strict: this.#strict,
1762 > strictCommands: this.#strictCommands,
1763 > strictOptions: this.#strictOptions,
1764 > completionCommand: this.#completionCommand,
1765 > parseFn: this.#parseFn,
1766 > parseContext: this.#parseContext,
1767 > } = frozen);
1768 > this.#options.configObjects = configObjects;
1769 > this.#usage.unfreeze();
1770 > this.#validation.unfreeze();
1771 > this.#command.unfreeze();
1772 > this.#globalMiddleware.unfreeze();
1773 > }
1774 > // If argv is a promise (which is possible if async middleware is used) yargs-factory.ts
1775 > // delay applying validation until the promise has resolved:
1776 > [kValidateAsync](
1777 validation: (argv: Arguments) => void,
1778 argv: Arguments | Promise<Arguments>
1783 });
1784 }
1786 > // Note: these method names could change at any time, and should not be
1787 > // depended upon externally:
1788 > getInternalMethods(): YargsInternalMethods {
1789 > return { yargs-factory.ts
1790 > getCommandInstance: this[kGetCommandInstance].bind(this),
1791 > getContext: this[kGetContext].bind(this),
1792 > getHasOutput: this[kGetHasOutput].bind(this),
1793 > getLoggerInstance: this[kGetLoggerInstance].bind(this),
1794 > getParseContext: this[kGetParseContext].bind(this),
1795 > getParserConfiguration: this[kGetParserConfiguration].bind(this),
1796 > getUsageConfiguration: this[kGetUsageConfiguration].bind(this),
1797 > getUsageInstance: this[kGetUsageInstance].bind(this),
1798 > getValidationInstance: this[kGetValidationInstance].bind(this),
1799 > hasParseCallback: this[kHasParseCallback].bind(this),
1800 > isGlobalContext: this[kIsGlobalContext].bind(this),
1801 > postProcess: this[kPostProcess].bind(this),
1802 > reset: this[kReset].bind(this),
1803 > runValidation: this[kRunValidation].bind(this),
1804 > runYargsParserAndExecuteCommands:
1805 > this[kRunYargsParserAndExecuteCommands].bind(this),
1806 > setHasOutput: this[kSetHasOutput].bind(this),
1807 > };
1808 > }
1809 > [kGetCommandInstance](): CommandInstance { yargs-factory.ts
1810 return this.#command;
1811 }
1812 > [kGetContext](): Context { yargs-factory.ts
1813 > return this.#context; yargs-factory.ts
1814 > }
1815 > [kGetHasOutput](): boolean { yargs-factory.ts
1816 return this.#hasOutput;
1817 }
1818 > [kGetLoggerInstance](): LoggerInstance { yargs-factory.ts
1819 return this.#logger;
1820 }
1821 > [kGetParseContext](): object { yargs-factory.ts
1822 return this.#parseContext || {};
1823 }
1824 > [kGetUsageInstance](): UsageInstance { yargs-factory.ts
1825 return this.#usage;
1826 }
1827 > [kGetValidationInstance](): ValidationInstance { yargs-factory.ts
1828 return this.#validation;
1829 }
1830 > [kHasParseCallback](): boolean { yargs-factory.ts
1831 > return !!this.#parseFn; yargs-factory.ts
1832 > }
1833 > [kIsGlobalContext](): boolean { yargs-factory.ts
1834 return this.#isGlobalContext;
1835 }
1836 > [kPostProcess]<T extends Arguments | Promise<Arguments>>( yargs-factory.ts
1837 > argv: Arguments | Promise<Arguments>, yargs-factory.ts
1838 > populateDoubleDash: boolean,
1839 > calledFromCommand: boolean,
1840 > runGlobalMiddleware: boolean
1841 > ): any {
1842 > if (calledFromCommand) return argv;
1843 > if (isPromise(argv)) return argv; yargs-factory.ts
1844 > if (!populateDoubleDash) { yargs-factory.ts
1845 > argv = this[kCopyDoubleDash](argv); yargs-factory.ts
1846 > }
1847 > const parsePositionalNumbers = yargs-factory.ts
1848 > this[kGetParserConfiguration]()['parse-positional-numbers'] ||
1849 > this[kGetParserConfiguration]()['parse-positional-numbers'] === undefined; yargs-factory.ts
1850 > if (parsePositionalNumbers) {
1851 > argv = this[kParsePositionalNumbers](argv as Arguments); yargs-factory.ts
1852 > }
1853 > if (runGlobalMiddleware) {
1854 argv = applyMiddleware(
1855 argv,
1859 );
1860 }
1861 > return argv; yargs-factory.ts
1862 > }
1863 > // put yargs back into an initial state; this is used mainly for running yargs-factory.ts
1864 > // commands in a breadth first manner:
1865 > [kReset](aliases: Aliases = {}): YargsInstance {
1866 > this.#options = this.#options || ({} as Options); yargs-factory.ts
1867 > const tmpOptions = {} as Options;
1868 > tmpOptions.local = this.#options.local || [];
1869 > tmpOptions.configObjects = this.#options.configObjects || [];
1870 >
1871 > // if a key has been explicitly set as local,
1872 > // we should reset it before passing options to command.
1873 > const localLookup: Dictionary<boolean> = {};
1874 > tmpOptions.local.forEach(l => {
1875 localLookup[l] = true;
1876 (aliases[l] || []).forEach(a => {
1877 localLookup[a] = true;
1878 });
1879 > }); yargs-factory.ts
1880 >
1881 > // add all groups not set to local to preserved groups
1882 > Object.assign(
1883 > this.#preservedGroups,
1884 > Object.keys(this.#groups).reduce(
1885 > (acc, groupName) => {
1886 const keys = this.#groups[groupName].filter(
1887 key => !(key in localLookup)
1891 }
1892 return acc;
1893 > }, yargs-factory.ts
1894 > {} as Dictionary<string[]>
1895 > )
1896 > );
1897 > // groups can now be reset
1898 > this.#groups = {};
1899 >
1900 > const arrayOptions: KeyOf<Options, string[]>[] = [
1901 > 'array',
1902 > 'boolean',
1903 > 'string',
1904 > 'skipValidation',
1905 > 'count',
1906 > 'normalize',
1907 > 'number',
1908 > 'hiddenOptions',
1909 > ];
1910 >
1911 > const objectOptions: DictionaryKeyof<Options>[] = [
1912 > 'narg',
1913 > 'key',
1914 > 'alias',
1915 > 'default',
1916 > 'defaultDescription',
1917 > 'config',
1918 > 'choices',
1919 > 'demandedOptions',
1920 > 'demandedCommands',
1921 > 'deprecatedOptions',
1922 > ];
1923 >
1924 > arrayOptions.forEach(k => {
1925 > tmpOptions[k] = (this.#options[k] || []).filter(
1926 > (k: string) => !localLookup[k]
1927 > );
1928 > });
1929 >
1930 > objectOptions.forEach(<K extends DictionaryKeyof<Options>>(k: K) => {
1931 > tmpOptions[k] = objFilter(
1932 > this.#options[k],
1933 > k => !localLookup[k as string]
1934 > );
1935 > });
1936 >
1937 > tmpOptions.envPrefix = this.#options.envPrefix;
1938 > this.#options = tmpOptions;
1939 >
1940 > // if this is the first time being executed, create
1941 > // instances of all our helpers -- otherwise just reset.
1942 > this.#usage = this.#usage
1943 > ? this.#usage.reset(localLookup)
1944 > : Usage(this, this.#shim);
1945 > this.#validation = this.#validation
1946 > ? this.#validation.reset(localLookup)
1947 > : Validation(this, this.#usage, this.#shim);
1948 > this.#command = this.#command
1949 > ? this.#command.reset()
1950 > : Command(
1951 > this.#usage,
1952 > this.#validation,
1953 > this.#globalMiddleware,
1954 > this.#shim
1955 > );
1956 > if (!this.#completion)
1957 > this.#completion = Completion(
1958 > this,
1959 > this.#usage,
1960 > this.#command,
1961 > this.#shim
1962 > );
1963 > this.#globalMiddleware.reset();
1964 >
1965 > this.#completionCommand = null;
1966 > this.#output = '';
1967 > this.#exitError = null;
1968 > this.#hasOutput = false;
1969 > this.parsed = false;
1970 >
1971 > return this;
1972 > }
1973 > [kRebase](base: string, dir: string): string { yargs-factory.ts
1974 > return this.#shim.path.relative(base, dir); yargs-factory.ts
1975 > }
1976 > [kRunYargsParserAndExecuteCommands]( yargs-factory.ts
1977 > args: string | string[] | null, yargs-factory.ts
1978 > shortCircuit?: boolean | null,
1979 > calledFromCommand?: boolean,
1980 > commandIndex = 0,
1981 > helpOnly = false
1982 > ): Arguments | Promise<Arguments> {
1983 > let skipValidation = !!calledFromCommand || helpOnly;
1984 > args = args || this.#processArgs;
1985 >
1986 > this.#options.__ = this.#shim.y18n.__;
1987 > this.#options.configuration = this[kGetParserConfiguration]();
1988 >
1989 > const populateDoubleDash = !!this.#options.configuration['populate--'];
1990 > const config = Object.assign({}, this.#options.configuration, {
1991 > 'populate--': true,
1992 > });
1993 > const parsed = this.#shim.Parser.detailed(
1994 > args,
1995 > Object.assign({}, this.#options, {
1996 > configuration: {'parse-positional-numbers': false, ...config},
1997 > })
1998 > ) as DetailedArguments;
1999 >
2000 > const argv: Arguments = Object.assign(
2001 > parsed.argv,
2002 > this.#parseContext
2003 > ) as Arguments;
2004 > let argvPromise: Arguments | Promise<Arguments> | undefined = undefined;
2005 > const aliases = parsed.aliases;
2006 >
2007 > let helpOptSet = false;
2008 > let versionOptSet = false;
2009 > Object.keys(argv).forEach(key => {
2010 > if (key === this.#helpOpt && argv[key]) {
2011 helpOptSet = true;
2012 > } else if (key === this.#versionOpt && argv[key]) { yargs-factory.ts
2013 versionOptSet = true;
2014 }
2015 > }); yargs-factory.ts
2016 >
2017 > argv.$0 = this.$0;
2018 > this.parsed = parsed;
2019 >
2020 > // A single yargs instance may be used multiple times, e.g.
2021 > // const y = yargs(); y.parse('foo --bar'); yargs.parse('bar --foo').
2022 > // When a prior parse has completed and a new parse is beginning, we
2023 > // need to clear the cached help message from the previous parse:
2024 > if (commandIndex === 0) {
2025 > this.#usage.clearCachedHelpMessage();
2026 > }
2027 >
2028 > try {
2029 > this[kGuessLocale](); // guess locale lazily, so that it can be turned off in chain.
2030 >
2031 > // while building up the argv object, there
2032 > // are two passes through the parser. If completion
2033 > // is being performed short-circuit on the first pass.
2034 > if (shortCircuit) {
2035 > return this[kPostProcess]( yargs-factory.ts
2036 > argv,
2037 > populateDoubleDash,
2038 > !!calledFromCommand,
2039 > false // Don't run middleware when figuring out completion.
2040 > );
2041 > }
2043 > // if there's a handler associated with a
2044 > // command defer processing to it.
2045 > if (this.#helpOpt) {
2046 > // consider any multi-char helpOpt alias as a valid help command yargs-factory.ts
2047 > // unless all helpOpt aliases are single-char
2048 > // note that parsed.aliases is a normalized bidirectional map :)
2049 > const helpCmds = [this.#helpOpt]
2050 > .concat(aliases[this.#helpOpt] || [])
2051 > .filter(k => k.length > 1);
2052 > // check if help should trigger and strip it from _.
2053 > if (helpCmds.includes('' + argv._[argv._.length - 1])) {
2054 argv._.pop();
2055 helpOptSet = true;
2056 }
2057 > } yargs-factory.ts
2059 > this.#isGlobalContext = false;
2060 >
2061 > const handlerKeys = this.#command.getCommands();
2062 >
2063 > const requestCompletions = this.#completion?.completionKey yargs-factory.ts
2064 > ? [
2065 > this.#completion?.completionKey, yargs-factory.ts
2066 > ...(this.getAliases()[this.#completion?.completionKey] ?? []),
2067 > ].some((key: string) =>
2068 > Object.prototype.hasOwnProperty.call(argv, key)
2069 > ) yargs-factory.ts
2070 > : false;
2071 >
2072 > const skipRecommendation = helpOptSet || requestCompletions || helpOnly;
2073 > if (argv._.length) {
2074 > if (handlerKeys.length) { yargs-factory.ts
2075 > let firstUnknownCommand; yargs-factory.ts
2076 > for (let i = commandIndex || 0, cmd; argv._[i] !== undefined; i++) {
2077 > cmd = String(argv._[i]);
2078 > if (handlerKeys.includes(cmd) && cmd !== this.#completionCommand) {
2079 // commands are executed using a recursive algorithm that executes
2080 // the deepest command first; we keep track of the position in the
2096 false
2097 );
2098 > } else if ( yargs-factory.ts
2099 > !firstUnknownCommand && yargs-factory.ts
2100 > cmd !== this.#completionCommand
2101 > ) {
2102 > firstUnknownCommand = cmd; yargs-factory.ts
2103 > break;
2104 > }
2105 > } yargs-factory.ts
2106 > // recommend a command if recommendCommands() has yargs-factory.ts
2107 > // been enabled, and no commands were found to execute
2108 > if (
2109 > !this.#command.hasDefaultCommand() &&
2110 > this.#recommendCommands && yargs-factory.ts
2111 > firstUnknownCommand &&
2112 !skipRecommendation
2113 > ) { yargs-factory.ts
2114 this.#validation.recommendCommands(
2115 firstUnknownCommand,
2117 );
2118 }
2119 > } yargs-factory.ts
2121 > // generate a completion script for adding to ~/.bashrc.
2122 > if (
2123 > this.#completionCommand &&
2124 > argv._.includes(this.#completionCommand) &&
2125 !requestCompletions
2126 > ) { yargs-factory.ts
2127 if (this.#exitProcess) setBlocking(true);
2128 this.showCompletionScript();
2129 this.exit(0);
2130 }
2131 > } yargs-factory.ts
2133 > if (this.#command.hasDefaultCommand() && !skipRecommendation) { yargs-factory.ts
2134 const innerArgv = this.#command.runCommand(
2135 null,
2147 );
2148 }
2150 > // we must run completions first, a user might
2151 > // want to complete the --help or --version option.
2152 > if (requestCompletions) {
2153 > if (this.#exitProcess) setBlocking(true); yargs-factory.ts
2154 >
2155 > // we allow for asynchronous completions,
2156 > // e.g., loading in a list of commands from an API.
2157 > args = ([] as string[]).concat(args);
2158 > const completionArgs = args.slice(
2159 > args.indexOf(`--${this.#completion!.completionKey}`) + 1
2160 > );
2161 > this.#completion!.getCompletion(completionArgs, (err, completions) => {
2162 > if (err) throw new YError(err.message);
2163 > (completions || []).forEach(completion => {
2164 > this.#logger.log(completion); yargs-factory.ts
2165 > }); yargs-factory.ts
2166 > this.exit(0);
2167 > });
2168 > return this[kPostProcess](
2169 > argv,
2170 > !populateDoubleDash,
2171 > !!calledFromCommand,
2172 > false // Don't run middleware when figuring out completion.
2173 > );
2174 > }
2175
2176 // Handle 'help' and 'version' options
2193
2194 // Check if any of the options to skip validation were provided
2195 > if (!skipValidation && this.#options.skipValidation.length > 0) { yargs-factory.ts
2196 skipValidation = Object.keys(argv).some(
2197 key =>
2230 }
2231 }
2232 > } catch (err) { yargs-factory.ts
2233 if (err instanceof YError) this.#usage.fail(err.message, err);
2234 else throw err;
2236
2237 return this[kPostProcess](
2238 > argvPromise ?? argv, yargs-factory.ts
2239 > populateDoubleDash,
2240 > !!calledFromCommand,
2241 > true
2242 > );
2243 > }
2244 > [kRunValidation]( yargs-factory.ts
2245 aliases: Dictionary<string[]>,
2246 positionalMap: Dictionary<string[]>,
2272 };
2273 }
2274 > [kSetHasOutput]() { yargs-factory.ts
2275 this.#hasOutput = true;
2276 }
2277 > [kTrackManuallySetKeys](keys: string | string[]) { yargs-factory.ts
2278 > if (typeof keys === 'string') { yargs-factory.ts
2279 > this.#options.key[keys] = true;
2280 > } else {
2281 for (const k of keys) {
2282 this.#options.key[k] = true;
2283 }
2284 }
2285 > } yargs-factory.ts
2286 > } yargs-factory.ts
2287 >
2288 > export function isYargsInstance(y: YargsInstance | void): y is YargsInstance {
2289 return !!y && typeof y.getInternalMethods === 'function';
2290 }
2292 > /** Yargs' context. */
2293 > export interface Context {
2294 > commands: string[];
2295 > fullCommands: string[];
2296 > }
2297 >
2298 > interface LoggerInstance {
2299 > error: Function;
2300 > log: Function;
2301 > }
2302 >
2303 > export interface Options extends ParserOptions {
2304 > __: (format: any, ...param: any[]) => string;
2305 > alias: Dictionary<string[]>;
2306 > array: string[];
2307 > boolean: string[];
2308 > choices: Dictionary<string[]>;
2309 > config: Dictionary<ConfigCallback | boolean>;
2310 > configObjects: Dictionary[];
2311 > configuration: Configuration;
2312 > count: string[];
2313 > defaultDescription: Dictionary<string | undefined>;
2314 > demandedCommands: Dictionary<{
2315 > min: number;
2316 > max: number;
2317 > minMsg?: string | null;
2318 > maxMsg?: string | null;
2319 > }>;
2320 > demandedOptions: Dictionary<string | undefined>;
2321 > deprecatedOptions: Dictionary<string | boolean | undefined>;
2322 > hiddenOptions: string[];
2323 > /** Manually set keys */
2324 > key: Dictionary<boolean | string>;
2325 > local: string[];
2326 > normalize: string[];
2327 > number: string[];
2328 > showHiddenOpt: string;
2329 > skipValidation: string[];
2330 > string: string[];
2331 > }
2332 >
2333 > export interface Configuration extends Partial<ParserConfiguration> {
2334 > /** Should a config object be deep-merged with the object config it extends? */
2335 > 'deep-merge-config'?: boolean;
2336 > /** Should commands be sorted in help? */
2337 > 'sort-commands'?: boolean;
2338 > }
2339 >
2340 > export interface UsageConfiguration {
2341 > /** Should types be hidden when usage is displayed */
2342 > 'hide-types'?: boolean;
2343 > }
2344 >
2345 > export interface OptionDefinition {
2346 > alias?: string | string[];
2347 > array?: boolean;
2348 > boolean?: boolean;
2349 > choices?: string | string[];
2350 > coerce?: CoerceCallback;
2351 > config?: boolean;
2352 > configParser?: ConfigCallback;
2353 > conflicts?: string | string[];
2354 > count?: boolean;
2355 > default?: any;
2356 > defaultDescription?: string;
2357 > deprecate?: string | boolean;
2358 > deprecated?: OptionDefinition['deprecate'];
2359 > desc?: string;
2360 > describe?: OptionDefinition['desc'];
2361 > description?: OptionDefinition['desc'];
2362 > demand?: string | true;
2363 > demandOption?: OptionDefinition['demand'];
2364 > global?: boolean;
2365 > group?: string;
2366 > hidden?: boolean;
2367 > implies?: string | number | KeyOrPos[];
2368 > nargs?: number;
2369 > normalize?: boolean;
2370 > number?: boolean;
2371 > require?: OptionDefinition['demand'];
2372 > required?: OptionDefinition['demand'];
2373 > requiresArg?: boolean;
2374 > skipValidation?: boolean;
2375 > string?: boolean;
2376 > type?: 'array' | 'boolean' | 'count' | 'number' | 'string';
2377 > }
2378 >
2379 > interface PositionalDefinition extends Pick<
2380 > OptionDefinition,
2381 > | 'alias'
2382 > | 'array'
2383 > | 'coerce'
2384 > | 'choices'
2385 > | 'conflicts'
2386 > | 'default'
2387 > | 'defaultDescription'
2388 > | 'demand'
2389 > | 'desc'
2390 > | 'describe'
2391 > | 'description'
2392 > | 'implies'
2393 > | 'normalize'
2394 > > {
2395 > type?: 'boolean' | 'number' | 'string';
2396 > }
2397 >
2398 > interface FrozenYargsInstance {
2399 > options: Options;
2400 > configObjects: Dictionary[];
2401 > exitProcess: boolean;
2402 > groups: Dictionary<string[]>;
2403 > strict: boolean;
2404 > strictCommands: boolean;
2405 > strictOptions: boolean;
2406 > completionCommand: string | null;
2407 > output: string;
2408 > exitError: YError | string | nil;
2409 > hasOutput: boolean;
2410 > parsed: DetailedArguments | false;
2411 > parseFn: ParseCallback | null;
2412 > parseContext: object | null;
2413 > }
2414 >
2415 > interface ParseCallback {
2416 > (err: YError | string | nil, argv: Arguments, output: string): void;
2417 > }
2418 >
2419 > interface Aliases {
2420 > [key: string]: Array<string>;
2421 > }
2422 >
2423 > export interface Arguments {
2424 > /** The script name or node command */
2425 > $0: string;
2426 > /** Non-option arguments */
2427 > _: ArgsOutput;
2428 > /** Arguments after the end-of-options flag `--` */
2429 > '--'?: ArgsOutput;
2430 > /** All remaining options */
2431 > [argName: string]: any;
2432 > }
2433 >
2434 > export interface DetailedArguments extends ParserDetailedArguments {
2435 > argv: Arguments;
2436 > aliases: Dictionary<string[]>;
2437 > }
lib/command.ts 251 covered LOC · 51 ranges

Open complete file

1 > import { command.ts
2 > Dictionary,
3 > assertNotStrictEqual,
4 > RequireDirectoryOptions,
5 > PlatformShim,
6 > } from './typings/common-types.js';
7 > import {isPromise} from './utils/is-promise.js';
8 > import {
9 > applyMiddleware,
10 > commandMiddlewareFactory,
11 > GlobalMiddleware,
12 > Middleware,
13 > } from './middleware.js';
14 > import {parseCommand, Positional} from './parse-command.js';
15 > import {UsageInstance} from './usage.js';
16 > import {ValidationInstance} from './validation.js';
17 > import {
18 > YargsInstance,
19 > isYargsInstance,
20 > Options,
21 > OptionDefinition,
22 > Context,
23 > Configuration,
24 > Arguments,
25 > DetailedArguments,
26 > } from './yargs-factory.js';
27 > import {maybeAsyncResult} from './utils/maybe-async-result.js';
28 >
29 > const DEFAULT_MARKER = /(^\*)|(^\$0)/;
30 > export type DefinitionOrCommandName = string | CommandHandlerDefinition;
31 >
32 > export class CommandInstance {
33 > shim: PlatformShim;
34 > requireCache: Set<string> = new Set();
35 > handlers: Dictionary<CommandHandler> = {};
36 > aliasMap: Dictionary<string> = {};
37 > defaultCommand?: CommandHandler;
38 > usage: UsageInstance;
39 > globalMiddleware: GlobalMiddleware;
40 > validation: ValidationInstance;
41 > // Used to cache state from prior invocations of commands.
42 > // This allows the parser to push and pop state when running
43 > // a nested command:
44 > frozens: FrozenCommandInstance[] = [];
45 > constructor(
46 > usage: UsageInstance, command.ts
47 > validation: ValidationInstance,
48 > globalMiddleware: GlobalMiddleware,
49 > shim: PlatformShim
50 > ) {
51 > this.shim = shim;
52 > this.usage = usage;
53 > this.globalMiddleware = globalMiddleware;
54 > this.validation = validation;
55 > }
56 > addDirectory( command.ts
57 dir: string,
58 req: Function,
123 }
124 }
125 > addHandler( command.ts
126 > cmd: string | CommandHandlerDefinition | DefinitionOrCommandName[], command.ts
127 > description?: CommandHandler['description'],
128 > builder?: CommandBuilderDefinition | CommandBuilder,
129 > handler?: CommandHandlerCallback,
130 > commandMiddleware?: Middleware[],
131 > deprecated?: boolean
132 > ): void {
133 > let aliases: string[] = [];
134 > const middlewares = commandMiddlewareFactory(commandMiddleware);
135 > handler = handler || (() => {});
136 >
137 > // If an array is provided that is all CommandHandlerDefinitions, add
138 > // each handler individually:
139 > if (Array.isArray(cmd)) {
140 if (isCommandAndAliases(cmd)) {
141 [cmd, ...aliases] = cmd;
145 }
146 }
147 > } else if (isCommandHandlerDefinition(cmd)) { command.ts
148 let command =
149 Array.isArray(cmd.command) || typeof cmd.command === 'string'
166 );
167 return;
168 > } else if (isCommandBuilderDefinition(builder)) { command.ts
169 // Allow a module to be provided as builder, rather than function:
170 this.addHandler(
178 return;
179 }
180 > command.ts
181 > // The 'cmd' provided was a string, we apply the command DSL:
182 > // https://github.com/yargs/yargs/blob/main/docs/advanced.md#advanced-topics
183 > if (typeof cmd === 'string') {
184 > // parse positionals out of cmd string
185 > const parsedCommand = parseCommand(cmd);
186 >
187 > // remove positional args from aliases only
188 > aliases = aliases.map(alias => parseCommand(alias).cmd);
189 >
190 > // check for default and filter out '*'
191 > let isDefault = false;
192 > const parsedAliases = [parsedCommand.cmd].concat(aliases).filter(c => {
193 > if (DEFAULT_MARKER.test(c)) {
194 isDefault = true;
195 return false;
196 }
197 > return true; command.ts
198 > }); command.ts
199 >
200 > // standardize on $0 for default command.
201 > if (parsedAliases.length === 0 && isDefault) parsedAliases.push('$0');
202 >
203 > // shift cmd and aliases after filtering out '*'
204 > if (isDefault) {
205 parsedCommand.cmd = parsedAliases[0];
206 aliases = parsedAliases.slice(1);
207 cmd = cmd.replace(DEFAULT_MARKER, parsedCommand.cmd);
208 }
209 > command.ts
210 > // populate aliasMap
211 > aliases.forEach(alias => {
212 this.aliasMap[alias] = parsedCommand.cmd;
213 > }); command.ts
214 >
215 > if (description !== false) {
216 this.usage.command(cmd, description, isDefault, aliases, deprecated);
217 }
218 > command.ts
219 > this.handlers[parsedCommand.cmd] = {
220 > original: cmd,
221 > description,
222 > handler,
223 > builder: (builder as CommandBuilder) || {},
224 > middlewares,
225 > deprecated,
226 > demanded: parsedCommand.demanded,
227 > optional: parsedCommand.optional,
228 > };
229 >
230 > if (isDefault) this.defaultCommand = this.handlers[parsedCommand.cmd];
231 > }
232 > } command.ts
233 > getCommandHandlers(): Dictionary<CommandHandler> { command.ts
234 > return this.handlers; command.ts
235 > }
236 > getCommands(): string[] { command.ts
237 > return Object.keys(this.handlers).concat(Object.keys(this.aliasMap)); command.ts
238 > }
239 > hasDefaultCommand(): boolean { command.ts
240 > return !!this.defaultCommand; command.ts
241 > }
242 > runCommand( command.ts
243 command: string | null,
244 yargs: YargsInstance,
291 );
292 }
293 > private applyBuilderUpdateUsageAndParse( command.ts
294 isDefaultCommand: boolean,
295 commandHandler: CommandHandler,
345 );
346 }
347 > private parseAndUpdateUsage( command.ts
348 isDefaultCommand: boolean,
349 commandHandler: CommandHandler,
392 };
393 }
394 > private shouldUpdateUsage(yargs: YargsInstance) { command.ts
395 return (
396 !yargs.getInternalMethods().getUsageInstance().getUsageDisabled() &&
398 );
399 }
400 > private usageFromParentCommandsCommandHandler( command.ts
401 parentCommands: string[],
402 commandHandler: CommandHandler
411 return `$0 ${pc.join(' ')}`;
412 }
413 > private handleValidationAndGetResult( command.ts
414 isDefaultCommand: boolean,
415 commandHandler: CommandHandler,
482 return innerArgv;
483 }
484 > private applyMiddlewareAndGetResult( command.ts
485 isDefaultCommand: boolean,
486 commandHandler: CommandHandler,
540 );
541 }
542 > // transcribe all positional arguments "command <foo> <bar> [apple]" command.ts
543 > // onto argv.
544 > private populatePositionals(
545 commandHandler: CommandHandler,
546 argv: Arguments,
576 return positionalMap;
577 }
578 > command.ts
579 > private populatePositional(
580 positional: Positional,
581 argv: Arguments,
589 }
590 }
591 > command.ts
592 > // Based on parsing variadic markers '...', demand syntax '<foo>', etc.,
593 > // populate parser hints:
594 > public cmdToParseOptions(cmdString: string): Positionals {
595 const parseOptions: Positionals = {
596 array: [],
622 return parseOptions;
623 }
624 > command.ts
625 > // we run yargs-parser against the positional arguments
626 > // applying the same parsing logic used for flags.
627 > private postProcessPositionals(
628 argv: Arguments,
629 positionalMap: Dictionary<string[]>,
704 }
705 }
706 > // Check defaults for key (and camel case version of key) command.ts
707 > isDefaulted(yargs: YargsInstance, key: string): boolean {
708 const {default: defaults} = yargs.getOptions();
709 return (
715 );
716 }
717 > // Check each config for key (and camel case version of key) command.ts
718 > isInConfigs(yargs: YargsInstance, key: string): boolean {
719 const {configObjects} = yargs.getOptions();
720 return (
725 );
726 }
727 > runDefaultBuilderOn(yargs: YargsInstance): unknown | Promise<unknown> { command.ts
728 if (!this.defaultCommand) return;
729 if (this.shouldUpdateUsage(yargs)) {
747 return undefined;
748 }
749 > command.ts
750 > private extractDesc({describe, description, desc}: CommandHandlerDefinition) {
751 for (const test of [describe, description, desc]) {
752 if (typeof test === 'string' || test === false) return test;
755 return false;
756 }
757 > // Push/pop the current command configuration: command.ts
758 > freeze() {
759 > this.frozens.push({ command.ts
760 > handlers: this.handlers,
761 > aliasMap: this.aliasMap,
762 > defaultCommand: this.defaultCommand,
763 > });
764 > }
765 > unfreeze() { command.ts
766 > const frozen = this.frozens.pop(); command.ts
767 > assertNotStrictEqual(frozen, undefined, this.shim);
768 > ({
769 > handlers: this.handlers,
770 > aliasMap: this.aliasMap,
771 > defaultCommand: this.defaultCommand,
772 > } = frozen);
773 > }
774 > // Revert to initial state: command.ts
775 > reset(): CommandInstance {
776 this.handlers = {};
777 this.aliasMap = {};
780 return this;
781 }
782 > } command.ts
783 >
784 > // Adds support to yargs for lazy loading a hierarchy of commands:
785 > export function command(
786 > usage: UsageInstance, command.ts
787 > validation: ValidationInstance,
788 > globalMiddleware: GlobalMiddleware,
789 > shim: PlatformShim
790 > ) {
791 > return new CommandInstance(usage, validation, globalMiddleware, shim);
792 > }
793 > command.ts
794 > export interface CommandHandlerDefinition extends Partial<
795 > Pick<CommandHandler, 'deprecated' | 'description' | 'handler' | 'middlewares'>
796 > > {
797 > aliases?: string[];
798 > builder?: CommandBuilder | CommandBuilderDefinition;
799 > command?: string | string[];
800 > desc?: CommandHandler['description'];
801 > describe?: CommandHandler['description'];
802 > }
803 >
804 > export interface CommandBuilderDefinition {
805 > builder?: CommandBuilder;
806 > deprecated?: boolean;
807 > handler: CommandHandlerCallback;
808 > middlewares?: Middleware[];
809 > }
810 >
811 > export function isCommandBuilderDefinition(
812 > builder?: CommandBuilder | CommandBuilderDefinition command.ts
813 > ): builder is CommandBuilderDefinition {
814 > return (
815 > typeof builder === 'object' &&
816 > !!(builder as CommandBuilderDefinition).builder &&
817 typeof (builder as CommandBuilderDefinition).handler === 'function'
818 > ); command.ts
819 > }
820 > command.ts
821 > export interface CommandHandlerCallback {
822 > (argv: Arguments): any;
823 > }
824 >
825 > export interface CommandHandler {
826 > builder: CommandBuilder;
827 > demanded: Positional[];
828 > deprecated?: boolean;
829 > description?: string | false;
830 > handler: CommandHandlerCallback;
831 > middlewares: Middleware[];
832 > optional: Positional[];
833 > original: string;
834 > }
835 >
836 > // To be completed later with other CommandBuilder flavours
837 > export type CommandBuilder =
838 > CommandBuilderCallback | Dictionary<OptionDefinition>;
839 >
840 > interface CommandBuilderCallback {
841 > (y: YargsInstance, helpOrVersionSet: boolean): YargsInstance | void;
842 > }
843 >
844 function isCommandAndAliases(
845 cmd: DefinitionOrCommandName[]
847 return cmd.every(c => typeof c === 'string');
848 }
849 > command.ts
850 > export function isCommandBuilderCallback(
851 builder: CommandBuilder
852 ): builder is CommandBuilderCallback {
853 return typeof builder === 'function';
854 }
855 > command.ts
856 function isCommandBuilderOptionDefinitions(
857 builder: CommandBuilder
859 return typeof builder === 'object';
860 }
861 > command.ts
862 > export function isCommandHandlerDefinition(
863 > cmd: DefinitionOrCommandName | [DefinitionOrCommandName, ...string[]] command.ts
864 > ): cmd is CommandHandlerDefinition {
865 > return typeof cmd === 'object' && !Array.isArray(cmd);
866 > }
867 > command.ts
868 > interface Positionals extends Pick<Options, 'alias' | 'array' | 'default'> {
869 > demand: Dictionary<boolean>;
870 > }
871 >
872 > type FrozenCommandInstance = {
873 > handlers: Dictionary<CommandHandler>;
874 > aliasMap: Dictionary<string>;
875 > defaultCommand: CommandHandler | undefined;
876 > };
lib/usage.ts 245 covered LOC · 45 ranges

Open complete file

1 > // this file handles outputting usage instructions, usage.ts
2 > // failures, etc. keeps logging in one place.
3 > import {Dictionary, PlatformShim, nil} from './typings/common-types.js';
4 > import {objFilter} from './utils/obj-filter.js';
5 > import {YargsInstance} from './yargs-factory.js';
6 > import {YError} from './yerror.js';
7 > import {DetailedArguments} from './typings/yargs-parser-types.js';
8 > import setBlocking from './utils/set-blocking.js';
9 >
10 function isBoolean(fail: FailureFunction | boolean): fail is boolean {
11 return typeof fail === 'boolean';
12 }
13 > usage.ts
14 > export function usage(yargs: YargsInstance, shim: PlatformShim) {
15 > const __ = shim.y18n.__; usage.ts
16 > const self = {} as UsageInstance;
17 >
18 > // methods for outputting/building failure message.
19 > const fails: (FailureFunction | boolean)[] = [];
20 > self.failFn = function failFn(f) {
21 fails.push(f);
22 > }; usage.ts
23 > let failMessage: string | nil = null;
24 > let globalFailMessage: string | nil = null;
25 > let showHelpOnFail = true;
26 > self.showHelpOnFail = function showHelpOnFailFn(
27 arg1: boolean | string = true,
28 arg2?: string
40 showHelpOnFail = enabled;
41 return self;
42 > }; usage.ts
43 >
44 > let failureOutput = false;
45 > self.fail = function fail(msg, err) {
46 const logger = yargs.getInternalMethods().getLoggerInstance();
47
83 }
84 }
85 > }; usage.ts
86 >
87 > // methods for outputting/building help (usage) message.
88 > let usages: [string, string][] = [];
89 > let usageDisabled = false;
90 > self.usage = (msg, description) => {
91 if (msg === null) {
92 usageDisabled = true;
97 usages.push([msg, description || '']);
98 return self;
99 > }; usage.ts
100 > self.getUsage = () => {
101 return usages;
102 > }; usage.ts
103 > self.getUsageDisabled = () => {
104 return usageDisabled;
105 > }; usage.ts
106 >
107 > self.getPositionalGroupName = () => {
108 > return __('Positionals:'); usage.ts
109 > }; usage.ts
110 >
111 > let examples: [string, string][] = [];
112 > self.example = (cmd, description) => {
113 examples.push([cmd, description || '']);
114 > }; usage.ts
115 >
116 > let commands: [string, string, boolean, string[], boolean][] = [];
117 > self.command = function command(
118 cmd,
119 description,
130 }
131 commands.push([cmd, description || '', isDefault, aliases, deprecated]);
132 > }; usage.ts
133 > self.getCommands = () => commands;
134 >
135 > let descriptions: Dictionary<string | undefined> = {};
136 > self.describe = function describe(
137 > keyOrKeys: string | string[] | Dictionary<string>,
138 > desc?: string
139 > ) {
140 > if (Array.isArray(keyOrKeys)) {
141 keyOrKeys.forEach(k => {
142 self.describe(k, desc);
143 });
144 > } else if (typeof keyOrKeys === 'object') { usage.ts
145 Object.keys(keyOrKeys).forEach(k => {
146 self.describe(k, keyOrKeys[k]);
147 });
148 > } else { usage.ts
149 > descriptions[keyOrKeys] = desc;
150 > }
151 > };
152 > self.getDescriptions = () => descriptions;
153 >
154 > let epilogs: string[] = [];
155 > self.epilog = msg => {
156 epilogs.push(msg);
157 > }; usage.ts
158 >
159 > let wrapSet = false;
160 > let wrap: number | nil;
161 > self.wrap = cols => {
162 wrapSet = true;
163 wrap = cols;
164 > }; usage.ts
165 >
166 > self.getWrap = () => {
167 if (shim.getEnv('YARGS_DISABLE_WRAP')) {
168 return null;
174
175 return wrap;
176 > }; usage.ts
177 >
178 > const deferY18nLookupPrefix = '__yargsString__:';
179 > self.deferY18nLookup = str => deferY18nLookupPrefix + str;
180 >
181 > self.help = function help() {
182 if (cachedHelpMessage) return cachedHelpMessage;
183 normalizeAliases();
507 // Remove the trailing white spaces
508 return ui.toString().replace(/\s*$/, '');
509 > }; usage.ts
510 >
511 > // return the maximum width of a string
512 > // in the left-hand column of a table.
513 > function maxWidth(
514 table:
515 [string | IndentedText, ...any[]][] | Dictionary<string | IndentedText>,
543 return width;
544 }
545 > usage.ts
546 > // make sure any options set for aliases,
547 > // are copied to the keys being aliased.
548 > function normalizeAliases() {
549 // handle old demanded API
550 const demandedOptions = yargs.getDemandedOptions();
568 });
569 }
570 > usage.ts
571 > // if yargs is executing an async handler, we take a snapshot of the
572 > // help message to display on failure:
573 > let cachedHelpMessage: string | undefined;
574 > self.cacheHelpMessage = function () {
575 cachedHelpMessage = this.help();
576 > }; usage.ts
577 >
578 > // however this snapshot must be cleared afterwards
579 > // not to be be used by next calls to parse
580 > self.clearCachedHelpMessage = function () {
581 > cachedHelpMessage = undefined; usage.ts
582 > }; usage.ts
583 >
584 > self.hasCachedHelpMessage = function () {
585 return !!cachedHelpMessage;
586 > }; usage.ts
587 >
588 > // given a set of keys, place any keys that are
589 > // ungrouped under the 'Options:' grouping.
590 > function addUngroupedKeys(
591 keys: string[],
592 aliases: Dictionary<string[]>,
608 return groupedKeys;
609 }
610 > usage.ts
611 > function filterHiddenOptions(key: string) {
612 return (
613 yargs.getOptions().hiddenOptions.indexOf(key) < 0 ||
615 );
616 }
617 > usage.ts
618 > self.showHelp = (level: 'error' | 'log' | ((message: string) => void)) => {
619 const logger = yargs.getInternalMethods().getLoggerInstance();
620 if (!level) level = 'error';
621 const emit = typeof level === 'function' ? level : logger[level];
622 emit(self.help());
623 > }; usage.ts
624 >
625 > self.functionDescription = fn => {
626 const description = fn.name
627 ? shim.Parser.decamelize(fn.name, '-')
628 : __('generated-value');
629 return ['(', description, ')'].join('');
630 > }; usage.ts
631 >
632 > self.stringifiedValues = function stringifiedValues(values, separator) {
633 let string = '';
634 const sep = separator || ', ';
643
644 return string;
645 > }; usage.ts
646 >
647 > // format the default-value-string displayed in
648 > // the right-hand column.
649 > function defaultString(value: any, defaultDescription?: string) {
650 let string = `[${__('default:')} `;
651
669 return `${string}]`;
670 }
671 > usage.ts
672 > // guess the width of the console window, max-width 80.
673 > function windowWidth() {
674 const maxWidth = 80;
675 // CI is not a TTY
676 > /* c8 ignore next 2 */ usage.ts
677 > if (shim.process.stdColumns) {
678 > return Math.min(maxWidth, shim.process.stdColumns);
679 } else {
680 return maxWidth;
681 }
682 }
683 > usage.ts
684 > // logic for displaying application version.
685 > let version: any = null;
686 > self.version = ver => {
687 > version = ver;
688 > };
689 >
690 > self.showVersion = level => {
691 const logger = yargs.getInternalMethods().getLoggerInstance();
692 if (!level) level = 'error';
693 const emit = typeof level === 'function' ? level : logger[level];
694 emit(version);
695 > }; usage.ts
696 >
697 > self.reset = function reset(localLookup) {
698 // do not reset wrap here
699 // do not reset fails here
707 descriptions = objFilter(descriptions, k => !localLookup[k]);
708 return self;
709 > }; usage.ts
710 >
711 > const frozens = [] as FrozenUsageInstance[];
712 > self.freeze = function freeze() {
713 > frozens.push({ usage.ts
714 > failMessage,
715 > failureOutput,
716 > usages,
717 > usageDisabled,
718 > epilogs,
719 > examples,
720 > commands,
721 > descriptions,
722 > });
723 > }; usage.ts
724 > self.unfreeze = function unfreeze(defaultCommand = false) {
725 > const frozen = frozens.pop(); usage.ts
726 > // In the case of running a defaultCommand, we reset
727 > // usage early to ensure we receive the top level instructions.
728 > // unfreezing again should just be a noop:
729 > if (!frozen) return;
730 > // Addresses: https://github.com/yargs/yargs/issues/2030
731 > if (defaultCommand) {
732 descriptions = {...frozen.descriptions, ...descriptions};
733 commands = [...frozen.commands, ...commands];
735 examples = [...frozen.examples, ...examples];
736 epilogs = [...frozen.epilogs, ...epilogs];
737 > } else { usage.ts
738 > ({ usage.ts
739 > failMessage,
740 > failureOutput,
741 > usages,
742 > usageDisabled,
743 > epilogs,
744 > examples,
745 > commands,
746 > descriptions,
747 > } = frozen);
748 > }
749 > }; usage.ts
750 >
751 > return self;
752 > }
753 > usage.ts
754 > /** Instance of the usage module. */
755 > export interface UsageInstance {
756 > cacheHelpMessage(): void;
757 > clearCachedHelpMessage(): void;
758 > hasCachedHelpMessage(): boolean;
759 > command(
760 > cmd: string,
761 > description: string | undefined,
762 > isDefault: boolean,
763 > aliases: string[],
764 > deprecated?: boolean
765 > ): void;
766 > deferY18nLookup(str: string): string;
767 > describe(keys: string | string[] | Dictionary<string>, desc?: string): void;
768 > epilog(msg: string): void;
769 > example(cmd: string, description?: string): void;
770 > fail(msg?: string | null, err?: YError | string): void;
771 > failFn(f: FailureFunction | boolean): void;
772 > freeze(): void;
773 > functionDescription(fn: {name?: string}): string;
774 > getCommands(): [string, string, boolean, string[], boolean][];
775 > getDescriptions(): Dictionary<string | undefined>;
776 > getPositionalGroupName(): string;
777 > getUsage(): [string, string][];
778 > getUsageDisabled(): boolean;
779 > getWrap(): number | nil;
780 > help(): string;
781 > reset(localLookup: Dictionary<boolean>): UsageInstance;
782 > showHelp(level?: 'error' | 'log' | ((message: string) => void)): void;
783 > showHelpOnFail(enabled?: boolean | string, message?: string): UsageInstance;
784 > showVersion(level?: 'error' | 'log' | ((message: string) => void)): void;
785 > stringifiedValues(values?: any[], separator?: string): string;
786 > unfreeze(defaultCommand?: boolean): void;
787 > usage(msg: string | null, description?: string | false): UsageInstance;
788 > version(ver: any): void;
789 > wrap(cols: number | nil): void;
790 > }
791 >
792 > export interface FailureFunction {
793 > (
794 > msg: string | nil,
795 > err: YError | string | undefined,
796 > usage: UsageInstance
797 > ): void;
798 > }
799 >
800 > export interface FrozenUsageInstance {
801 > failMessage: string | nil;
802 > failureOutput: boolean;
803 > usages: [string, string][];
804 > usageDisabled: boolean;
805 > epilogs: string[];
806 > examples: [string, string][];
807 > commands: [string, string, boolean, string[], boolean][];
808 > descriptions: Dictionary<string | undefined>;
809 > }
810 >
811 > interface IndentedText {
812 > text: string;
813 > indentation: number;
814 > }
815 >
816 function isIndentedText(text: string | IndentedText): text is IndentedText {
817 return typeof text === 'object';
818 }
819 > usage.ts
820 function addIndentation(
821 text: string | IndentedText,
826 : {text, indentation: indent};
827 }
828 > usage.ts
829 function getIndentation(text: string | IndentedText): number {
830 return isIndentedText(text) ? text.indentation : 0;
831 }
832 > usage.ts
833 function getText(text: string | IndentedText): string {
834 return isIndentedText(text) ? text.text : text;
lib/completion.ts 242 covered LOC · 56 ranges

Open complete file

1 > import {CommandInstance, isCommandBuilderCallback} from './command.js'; completion.ts
2 > import {PlatformShim, assertNotStrictEqual} from './typings/common-types.js';
3 > import * as templates from './completion-templates.js';
4 > import {isPromise} from './utils/is-promise.js';
5 > import {parseCommand} from './parse-command.js';
6 > import {UsageInstance} from './usage.js';
7 > import {YargsInstance} from './yargs-factory.js';
8 > import {Arguments, DetailedArguments} from './typings/yargs-parser-types.js';
9 >
10 > // add bash completions to your
11 > // yargs-powered applications.
12 >
13 > type CompletionCallback = (
14 > err: Error | null,
15 > completions: string[] | undefined
16 > ) => void;
17 >
18 > /** Instance of the completion module. */
19 > export interface CompletionInstance {
20 > completionKey: string;
21 > generateCompletionScript($0: string, cmd: string): string;
22 > getCompletion(
23 > args: string[],
24 > done: (err: Error | null, completions: string[] | undefined) => void
25 > ): any;
26 > registerFunction(fn: CompletionFunction): void;
27 > setParsed(parsed: DetailedArguments): void;
28 > }
29 >
30 > export class Completion implements CompletionInstance {
31 > completionKey = 'get-yargs-completions';
32 >
33 > private aliases: DetailedArguments['aliases'] | null = null;
34 > private customCompletionFunction: CompletionFunction | null = null;
35 > private indexAfterLastReset = 0;
36 > private readonly zshShell: boolean;
37 >
38 > constructor(
39 > private readonly yargs: YargsInstance, completion.ts
40 > private readonly usage: UsageInstance,
41 > private readonly command: CommandInstance,
42 > private readonly shim: PlatformShim
43 > ) {
44 > this.zshShell =
45 > (this.shim.getEnv('SHELL')?.includes('zsh') ||
46 > this.shim.getEnv('ZSH_NAME')?.includes('zsh')) ??
47 > false;
48 > }
50 > private defaultCompletion(
51 > args: string[], completion.ts
52 > argv: Arguments,
53 > current: string,
54 > done: CompletionCallback
55 > ): Arguments | void {
56 > const handlers = this.command.getCommandHandlers();
57 > for (let i = 0, ii = args.length; i < ii; ++i) {
58 > if (handlers[args[i]] && handlers[args[i]].builder) { completion.ts
59 const builder = handlers[args[i]].builder;
60 if (isCommandBuilderCallback(builder)) {
65 }
66 }
67 > } completion.ts
69 > const completions: string[] = [];
70 >
71 > this.commandCompletions(completions, args, current);
72 > this.optionCompletions(completions, args, argv, current);
73 > this.choicesFromOptionsCompletions(completions, args, argv, current);
74 > this.choicesFromPositionalsCompletions(completions, args, argv, current);
75 > done(null, completions);
76 > }
78 > // Default completions for commands
79 > private commandCompletions(
80 > completions: string[], completion.ts
81 > args: string[],
82 > current: string
83 > ) {
84 > const parentCommands = this.yargs
85 > .getInternalMethods()
86 > .getContext().commands;
87 > if (
88 > !current.match(/^-/) &&
89 > parentCommands[parentCommands.length - 1] !== current &&
90 !this.previousArgHasChoices(args)
91 > ) { completion.ts
92 this.usage.getCommands().forEach(usageCommand => {
93 const commandName = parseCommand(usageCommand[0]).cmd;
102 });
103 }
104 > } completion.ts
106 > // Default completions for - and -- options
107 > private optionCompletions(
108 > completions: string[], completion.ts
109 > args: string[],
110 > argv: Arguments,
111 > current: string
112 > ) {
113 > if (
114 > (current.match(/^-/) || (current === '' && completions.length === 0)) &&
115 > !this.previousArgHasChoices(args) completion.ts
116 > ) { completion.ts
117 const options = this.yargs.getOptions();
118 const positionalKeys =
140 });
141 }
142 > } completion.ts
144 > private choicesFromOptionsCompletions(
145 > completions: string[], completion.ts
146 > args: string[],
147 > argv: Arguments,
148 > current: string
149 > ) {
150 > if (this.previousArgHasChoices(args)) {
151 > const choices = this.getPreviousArgChoices(args); completion.ts
152 > if (choices && choices.length > 0) {
153 > completions.push(...choices.map(c => c.replace(/:/g, '\\:')));
154 > }
155 > }
156 > } completion.ts
158 > private choicesFromPositionalsCompletions(
159 > completions: string[], completion.ts
160 > args: string[],
161 > argv: Arguments,
162 > current: string
163 > ) {
164 > if (
165 > current === '' &&
166 > completions.length > 0 &&
167 this.previousArgHasChoices(args)
168 > ) { completion.ts
169 return;
170 }
172 > const positionalKeys =
173 > this.yargs.getGroups()[this.usage.getPositionalGroupName()] || []; completion.ts
174 > const offset = Math.max(
175 > this.indexAfterLastReset,
176 > this.yargs.getInternalMethods().getContext().commands.length +
177 > /* name of the script is first param */ 1
178 > );
179 >
180 > const positionalKey = positionalKeys[argv._.length - offset - 1];
181 > if (!positionalKey) {
182 > return; completion.ts
183 > }
184
185 > const choices = this.yargs.getOptions().choices[positionalKey] || []; completion.ts
186 > for (const choice of choices) {
187 if (choice.startsWith(current)) {
188 completions.push(choice.replace(/:/g, '\\:'));
190 }
191 }
193 > private getPreviousArgChoices(args: string[]): string[] | void {
194 > if (args.length < 1) return; // no args completion.ts
195 > let previousArg = args[args.length - 1]; completion.ts
196 > let filter = '';
197 > // use second to last argument if the last one is not an option starting with --
198 > if (!previousArg.startsWith('-') && args.length > 1) { completion.ts
199 filter = previousArg; // use last arg as filter for choices
200 previousArg = args[args.length - 2];
201 }
202 > if (!previousArg.startsWith('-')) return; // still no valid arg, abort completion.ts
203 > const previousArgKey = previousArg.replace(/^-+/, ''); completion.ts
204 >
205 > const options = this.yargs.getOptions();
206 >
207 > const possibleAliases = [
208 > previousArgKey,
209 > ...(this.yargs.getAliases()[previousArgKey] || []), completion.ts
210 > ];
211 > let choices: string[] | undefined;
212 > // Find choices across all possible aliases
213 > for (const possibleAlias of possibleAliases) {
214 > if ( completion.ts
215 > Object.prototype.hasOwnProperty.call(options.key, possibleAlias) &&
216 > Array.isArray(options.choices[possibleAlias]) completion.ts
217 > ) { completion.ts
218 > choices = options.choices[possibleAlias]; completion.ts
219 > break;
220 > }
221 > } completion.ts
222 >
223 > if (choices) {
224 > return choices.filter(choice => !filter || choice.startsWith(filter)); completion.ts
225 > }
226 > } completion.ts
228 > private previousArgHasChoices(args: string[]): boolean {
229 > const choices = this.getPreviousArgChoices(args); completion.ts
230 > return choices !== undefined && choices.length > 0;
231 > }
233 > private argsContainKey(
234 args: string[],
235 key: string,
247 return false;
248 }
250 > // Add completion for a single - or -- option
251 > private completeOptionKey(
252 key: string,
253 completions: string[],
279 }
280 }
282 > // a custom completion function can be provided
283 > // to completion().
284 > private customCompletion(
285 args: string[],
286 argv: Arguments,
329 }
330 }
332 > // get a list of completion commands.
333 > // 'args' is the array of strings from the line to be completed
334 > getCompletion(args: string[], done: CompletionCallback): any {
335 > const current = args.length ? args[args.length - 1] : ''; completion.ts
336 > const argv = this.yargs.parse(args, true);
337 >
338 > const completionFunction = this.customCompletionFunction
339 > ? (argv: Arguments) => this.customCompletion(args, argv, current, done)
340 > : (argv: Arguments) => this.defaultCompletion(args, argv, current, done);
341 >
342 > return isPromise(argv)
343 > ? argv.then(completionFunction)
344 > : completionFunction(argv);
345 > }
347 > // generate the completion script to add to your .bashrc.
348 > generateCompletionScript($0: string, cmd: string): string {
349 let script = this.zshShell
350 ? templates.completionZshTemplate
359 return script.replace(/{{app_path}}/g, $0);
360 }
362 > // register a function to perform your own custom
363 > // completions. this function can be either
364 > // synchronous or asynchronous.
365 > registerFunction(fn: CompletionFunction) {
366 this.customCompletionFunction = fn;
367 }
369 > setParsed(parsed: DetailedArguments) {
370 > this.aliases = parsed.aliases; completion.ts
371 > }
372 > } completion.ts
373 >
374 > // For backwards compatibility
375 > export function completion(
376 > yargs: YargsInstance, completion.ts
377 > usage: UsageInstance,
378 > command: CommandInstance,
379 > shim: PlatformShim
380 > ): CompletionInstance {
381 > return new Completion(yargs, usage, command, shim);
382 > }
384 > export type CompletionFunction =
385 > SyncCompletionFunction | AsyncCompletionFunction | FallbackCompletionFunction;
386 >
387 > interface SyncCompletionFunction {
388 > (current: string, argv: Arguments): string[] | Promise<string[]>;
389 > }
390 >
391 > interface AsyncCompletionFunction {
392 > (current: string, argv: Arguments, done: (completions: string[]) => any): any;
393 > }
394 >
395 > interface FallbackCompletionFunction {
396 > (
397 > current: string,
398 > argv: Arguments,
399 > completionFilter: (onCompleted?: CompletionCallback) => any,
400 > done: (completions: string[]) => any
401 > ): any;
402 > }
403 >
404 function isSyncCompletionFunction(
405 completionFunction: CompletionFunction
407 return completionFunction.length < 3;
408 }
410 function isFallbackCompletionFunction(
411 completionFunction: CompletionFunction
lib/validation.ts 142 covered LOC · 22 ranges

Open complete file

1 > import {argsert} from './argsert.js'; validation.ts
2 > import {
3 > Dictionary,
4 > assertNotStrictEqual,
5 > PlatformShim,
6 > } from './typings/common-types.js';
7 > import {levenshtein as distance} from './utils/levenshtein.js';
8 > import {objFilter} from './utils/obj-filter.js';
9 > import {UsageInstance} from './usage.js';
10 > import {YargsInstance, Arguments} from './yargs-factory.js';
11 > import {DetailedArguments} from './typings/yargs-parser-types.js';
12 >
13 > const specialKeys = ['$0', '--', '_'];
14 >
15 > // validation-type-stuff, missing params,
16 > // bad implications:
17 > export function validation(
18 > yargs: YargsInstance, validation.ts
19 > usage: UsageInstance,
20 > shim: PlatformShim
21 > ) {
22 > const __ = shim.y18n.__;
23 > const __n = shim.y18n.__n;
24 > const self = {} as ValidationInstance;
25 >
26 > // validate appropriate # of non-option
27 > // arguments were provided, i.e., '_'.
28 > self.nonOptionCount = function nonOptionCount(argv) {
29 const demandedCommands = yargs.getDemandedCommands();
30 // don't count currently executing commands
82 }
83 }
84 > }; validation.ts
85 >
86 > // validate the appropriate # of <required>
87 > // positional arguments were provided:
88 > self.positionalCount = function positionalCount(required, observed) {
89 if (observed < required) {
90 usage.fail(
98 );
99 }
100 > }; validation.ts
101 >
102 > // make sure all the required arguments are present.
103 > self.requiredArguments = function requiredArguments(
104 argv,
105 demandedOptions: Dictionary<string | undefined>
136 );
137 }
138 > }; validation.ts
139 >
140 > // check for unknown arguments (strict-mode).
141 > self.unknownArguments = function unknownArguments(
142 argv,
143 aliases,
210 );
211 }
212 > }; validation.ts
213 >
214 > self.unknownCommands = function unknownCommands(argv) {
215 const commandKeys = yargs
216 .getInternalMethods()
241 return false;
242 }
243 > }; validation.ts
244 >
245 > // check for a key that is not an alias, or for which every alias is new,
246 > // implying that it was invented by the parser, e.g., during camelization
247 > self.isValidAndSomeAliasIsNotNew = function isValidAndSomeAliasIsNotNew(
248 key,
249 aliases
257 !Object.prototype.hasOwnProperty.call(newAliases, a) || !newAliases[key]
258 );
259 > }; validation.ts
260 >
261 > // validate arguments limited to enumerated choices
262 > self.limitedChoices = function limitedChoices(argv) {
263 const options = yargs.getOptions();
264 const invalid: Dictionary<any[]> = {};
297 });
298 usage.fail(msg);
299 > }; validation.ts
300 >
301 > // check implications, argument foo implies => argument bar.
302 > let implied: Dictionary<KeyOrPos[]> = {};
303 > self.implies = function implies(key, value) {
304 argsert(
305 '<string|object> [array|number|string]',
324 }
325 }
326 > }; validation.ts
327 > self.getImplied = function getImplied() {
328 return implied;
329 > }; validation.ts
330 >
331 > function keyExists(argv: Arguments, val: any): any {
332 // convert string '1' to number 1
333 const num = Number(val);
347 return val;
348 }
350 > self.implications = function implications(argv) {
351 const implyFail: string[] = [];
352
374 usage.fail(msg);
375 }
376 > }; validation.ts
377 >
378 > let conflicting: Dictionary<(string | undefined)[]> = {};
379 > self.conflicts = function conflicts(key, value) {
380 argsert('<string|object> [array|string]', [key, value], arguments.length);
381
395 }
396 }
397 > }; validation.ts
398 > self.getConflicting = () => conflicting;
399 >
400 > self.conflicting = function conflictingFn(argv) {
401 Object.keys(argv).forEach(key => {
402 if (conflicting[key]) {
430 });
431 }
432 > }; validation.ts
433 >
434 > self.recommendCommands = function recommendCommands(cmd, potentialCommands) {
435 const threshold = 3; // if it takes more than three edits, let's move on.
436 potentialCommands = potentialCommands.sort((a, b) => b.length - a.length);
450 }
451 if (recommended) usage.fail(__('Did you mean %s?', recommended));
452 > }; validation.ts
453 >
454 > self.reset = function reset(localLookup) {
455 implied = objFilter(implied, k => !localLookup[k]);
456 conflicting = objFilter(conflicting, k => !localLookup[k]);
457 return self;
458 > }; validation.ts
459 >
460 > const frozens: FrozenValidationInstance[] = [];
461 > self.freeze = function freeze() {
462 > frozens.push({ validation.ts
463 > implied,
464 > conflicting,
465 > });
466 > }; validation.ts
467 > self.unfreeze = function unfreeze() {
468 > const frozen = frozens.pop(); validation.ts
469 > assertNotStrictEqual(frozen, undefined, shim);
470 > ({implied, conflicting} = frozen);
471 > }; validation.ts
472 >
473 > return self;
474 > }
476 > /** Instance of the validation module. */
477 > export interface ValidationInstance {
478 > conflicting(argv: Arguments): void;
479 > conflicts(
480 > key: string | Dictionary<string | string[]>,
481 > value?: string | string[]
482 > ): void;
483 > freeze(): void;
484 > getConflicting(): Dictionary<(string | undefined)[]>;
485 > getImplied(): Dictionary<KeyOrPos[]>;
486 > implications(argv: Arguments): void;
487 > implies(
488 > key: string | Dictionary<KeyOrPos | KeyOrPos[]>,
489 > value?: KeyOrPos | KeyOrPos[]
490 > ): void;
491 > isValidAndSomeAliasIsNotNew(
492 > key: string,
493 > aliases: DetailedArguments['aliases']
494 > ): boolean;
495 > limitedChoices(argv: Arguments): void;
496 > nonOptionCount(argv: Arguments): void;
497 > positionalCount(required: number, observed: number): void;
498 > recommendCommands(cmd: string, potentialCommands: string[]): void;
499 > requiredArguments(
500 > argv: Arguments,
501 > demandedOptions: Dictionary<string | undefined>
502 > ): void;
503 > reset(localLookup: Dictionary): ValidationInstance;
504 > unfreeze(): void;
505 > unknownArguments(
506 > argv: Arguments,
507 > aliases: DetailedArguments['aliases'],
508 > positionalMap: Dictionary,
509 > isDefaultCommand: boolean,
510 > checkPositionals?: boolean
511 > ): void;
512 > unknownCommands(argv: Arguments): boolean;
513 > }
514 >
515 > interface FrozenValidationInstance {
516 > implied: Dictionary<KeyOrPos[]>;
517 > conflicting: Dictionary<(string | undefined)[]>;
518 > }
519 >
520 > export type KeyOrPos = string | number;
lib/typings/common-types.ts 140 covered LOC · 6 ranges

Open complete file

1 > import {Parser} from './yargs-parser-types.js'; common-types.ts
2 >
3 > /**
4 > * A type that represents undefined or null
5 > */
6 > export type nil = undefined | null;
7 >
8 > /**
9 > * An object whose all properties have the same type.
10 > */
11 > export type Dictionary<T = any> = {[key: string]: T};
12 >
13 > /**
14 > * Returns the keys of T that match Dictionary<U> and are not arrays.
15 > */
16 > export type DictionaryKeyof<T, U = any> = Exclude<
17 > KeyOf<T, Dictionary<U>>,
18 > KeyOf<T, any[]>
19 > >;
20 >
21 > /**
22 > * Returns the keys of T that match U.
23 > */
24 > export type KeyOf<T, U> = Exclude<
25 > {[K in keyof T]: T[K] extends U ? K : never}[keyof T],
26 > undefined
27 > >;
28 >
29 > /**
30 > * An array whose first element is not undefined.
31 > */
32 > export type NotEmptyArray<T = any> = [T, ...T[]];
33 >
34 > /**
35 > * Returns the type of a Dictionary or array values.
36 > */
37 > export type ValueOf<T> = T extends (infer U)[] ? U : T[keyof T];
38 >
39 > /**
40 > * Typing wrapper around assert.notStrictEqual()
41 > */
42 > export function assertNotStrictEqual<N, T>(
43 > actual: T | N, common-types.ts
44 > expected: N,
45 > shim: PlatformShim,
46 > message?: string | Error
47 > ): asserts actual is Exclude<T, N> {
48 > shim.assert.notStrictEqual(actual, expected, message);
49 > }
51 > /**
52 > * Asserts actual is a single key, not a key array or a key map.
53 > */
54 > export function assertSingleKey(
55 actual: string | string[] | Dictionary,
56 shim: PlatformShim
58 shim.assert.strictEqual(typeof actual, 'string');
59 }
61 > /**
62 > * Typing wrapper around Object.keys()
63 > */
64 > export function objectKeys<T extends {}>(object: T) {
65 > return Object.keys(object) as (keyof T)[]; common-types.ts
66 > }
68 > export interface RequireDirectoryOptions {
69 > extensions?: ReadonlyArray<string>;
70 > visit?: (commandObject: any, pathToFile: string, filename?: string) => any;
71 > recurse?: boolean;
72 > include?: RegExp | ((fileName: string) => boolean);
73 > exclude?: RegExp | ((fileName: string) => boolean);
74 > }
75 >
76 > // Dependencies that might vary between CJS, ESM, and Deno are isolated:
77 > export interface PlatformShim {
78 > assert: {
79 > notStrictEqual: (
80 > expected: any,
81 > observed: any,
82 > message?: string | Error
83 > ) => void;
84 > strictEqual: (
85 > expected: any,
86 > observed: any,
87 > message?: string | Error
88 > ) => void;
89 > };
90 > findUp: (
91 > startDir: string,
92 > fn: (dir: string[], names: string[]) => string | undefined
93 > ) => string;
94 > getCallerFile: () => string;
95 > getEnv: (key: string) => string | undefined;
96 > getProcessArgvBin: () => string;
97 > inspect: (obj: object) => string;
98 > mainFilename: string;
99 > requireDirectory: Function;
100 > stringWidth: (str: string) => number;
101 > cliui: Function;
102 > Parser: Parser;
103 > path: {
104 > basename: (p1: string, p2?: string) => string;
105 > extname: (path: string) => string;
106 > dirname: (path: string) => string;
107 > relative: (p1: string, p2: string) => string;
108 > resolve: (p1: string, p2: string) => string;
109 > join: (p1: string, p2: string) => string;
110 > };
111 > process: {
112 > argv: () => string[];
113 > cwd: () => string;
114 > emitWarning: (warning: string | Error, type?: string) => void;
115 > execPath: () => string;
116 > exit: (code: number) => void;
117 > nextTick: (cb: Function) => void;
118 > stdColumns: number | null;
119 > };
120 > readFileSync: (path: string, encoding: string) => string;
121 > readdirSync: (
122 > path: string,
123 > opts: object
124 > ) => Array<string | Buffer<ArrayBufferLike>>[];
125 > require: RequireType;
126 > y18n: Y18N;
127 > }
128 >
129 > export interface RequireType {
130 > (path: string): Function;
131 > main: MainType;
132 > }
133 >
134 > export interface MainType {
135 > filename: string;
136 > children: MainType[];
137 > }
138 >
139 > export interface Y18N {
140 > __(str: string, ...args: string[]): string;
141 > __n(str: string, ...args: (string | number)[]): string;
142 > getLocale(): string;
143 > setLocale(locale: string): void;
144 > updateLocale(obj: {[key: string]: string}): void;
145 > }
lib/argsert.ts 76 covered LOC · 21 ranges

Open complete file

1 > import {YError} from './yerror.js'; argsert.ts
2 > import {parseCommand, ParsedCommand} from './parse-command.js';
3 >
4 > const positionName = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth'];
5 > export function argsert(callerArguments: any[], length?: number): void;
6 > export function argsert(
7 > expected: string,
8 > callerArguments: any[],
9 > length?: number
10 > ): void;
11 > export function argsert(
12 > arg1: string | any[], argsert.ts
13 > arg2?: any[] | number,
14 > arg3?: number
15 > ): void {
16 > function parseArgs(): [
17 > Pick<ParsedCommand, 'demanded' | 'optional'>,
18 > any[],
19 > number?,
20 > ] {
21 > return typeof arg1 === 'object'
22 > ? [{demanded: [], optional: []}, arg1, arg2 as number | undefined]
23 > : [
24 > parseCommand(`cmd ${arg1}`), argsert.ts
25 > arg2 as any[],
26 > arg3 as number | undefined,
27 > ];
28 > } argsert.ts
29 > // TODO: should this eventually raise an exception.
30 > try {
31 > // preface the argument description with "cmd", so
32 > // that we can run it through yargs' command parser.
33 > let position = 0;
34 > const [parsed, callerArguments, _length] = parseArgs();
35 > const args = [].slice.call(callerArguments);
36 >
37 > while (args.length && args[args.length - 1] === undefined) args.pop();
38 > const length = _length || args.length;
39 >
40 > if (length < parsed.demanded.length) {
41 throw new YError(
42 `Not enough arguments provided. Expected ${parsed.demanded.length} but received ${args.length}.`
43 );
44 }
45 > argsert.ts
46 > const totalCommands = parsed.demanded.length + parsed.optional.length;
47 > if (length > totalCommands) {
48 throw new YError(
49 `Too many arguments provided. Expected max ${totalCommands} but received ${length}.`
50 );
51 }
52 > argsert.ts
53 > parsed.demanded.forEach(demanded => {
54 > const arg = args.shift(); argsert.ts
55 > const observedType = guessType(arg);
56 > const matchingTypes = demanded.cmd.filter(
57 > type => type === observedType || type === '*'
58 > );
59 > if (matchingTypes.length === 0)
60 > argumentTypeError(observedType, demanded.cmd, position);
61 > position += 1; argsert.ts
62 > }); argsert.ts
63 >
64 > parsed.optional.forEach(optional => {
65 > if (args.length === 0) return; argsert.ts
66 > const arg = args.shift(); argsert.ts
67 > const observedType = guessType(arg);
68 > const matchingTypes = optional.cmd.filter(
69 > type => type === observedType || type === '*'
70 > );
71 > if (matchingTypes.length === 0)
72 > argumentTypeError(observedType, optional.cmd, position);
73 > position += 1; argsert.ts
74 > }); argsert.ts
75 > } catch (err) { argsert.ts
76 console.warn((err as Error).stack);
77 }
78 > } argsert.ts
79 > argsert.ts
80 > function guessType(arg: any) { argsert.ts
81 > if (Array.isArray(arg)) {
82 > return 'array'; argsert.ts
83 > } else if (arg === null) { argsert.ts
84 return 'null';
85 }
86 > return typeof arg; argsert.ts
87 > }
88 > argsert.ts
89 function argumentTypeError(
90 observedType: string,
lib/completion-templates.ts 58 covered LOC · 1 range

Open complete file

1 > export const completionShTemplate = `###-begin-{{app_name}}-completions-### completion-templates.ts
2 > #
3 > # yargs command completion script
4 > #
5 > # Installation: {{app_path}} {{completion_command}} >> ~/.bashrc
6 > # or {{app_path}} {{completion_command}} >> ~/.bash_profile on OSX.
7 > #
8 > _{{app_name}}_yargs_completions()
9 > {
10 > local cur_word args type_list
11 >
12 > cur_word="\${COMP_WORDS[COMP_CWORD]}"
13 > args=("\${COMP_WORDS[@]}")
14 >
15 > # ask yargs to generate completions.
16 > # see https://stackoverflow.com/a/40944195/7080036 for the spaces-handling awk
17 > mapfile -t type_list < <({{app_path}} --get-yargs-completions "\${args[@]}")
18 > mapfile -t COMPREPLY < <(compgen -W "$( printf '%q ' "\${type_list[@]}" )" -- "\${cur_word}" |
19 > awk '/ / { print "\\""$0"\\"" } /^[^ ]+$/ { print $0 }')
20 >
21 > # if no match was found, fall back to filename completion
22 > if [ \${#COMPREPLY[@]} -eq 0 ]; then
23 > COMPREPLY=()
24 > fi
25 >
26 > return 0
27 > }
28 > complete -o bashdefault -o default -F _{{app_name}}_yargs_completions {{app_name}}
29 > ###-end-{{app_name}}-completions-###
30 > `;
31 >
32 > export const completionZshTemplate = `#compdef {{app_name}}
33 > ###-begin-{{app_name}}-completions-###
34 > #
35 > # yargs command completion script
36 > #
37 > # Installation: {{app_path}} {{completion_command}} >> ~/.zshrc
38 > # or {{app_path}} {{completion_command}} >> ~/.zprofile on OSX.
39 > #
40 > _{{app_name}}_yargs_completions()
41 > {
42 > local reply
43 > local si=$IFS
44 > IFS=$'\n' reply=($(COMP_CWORD="$((CURRENT-1))" COMP_LINE="$BUFFER" COMP_POINT="$CURSOR" {{app_path}} --get-yargs-completions "\${words[@]}"))
45 > IFS=$si
46 > if [[ \${#reply} -gt 0 ]]; then
47 > _describe 'values' reply
48 > else
49 > _default
50 > fi
51 > }
52 > if [[ "'\${zsh_eval_context[-1]}" == "loadautofunc" ]]; then
53 > _{{app_name}}_yargs_completions "$@"
54 > else
55 > compdef _{{app_name}}_yargs_completions {{app_name}}
56 > fi
57 > ###-end-{{app_name}}-completions-###
58 > `;
lib/middleware.ts 49 covered LOC · 15 ranges

Open complete file

1 > import {argsert} from './argsert.js'; middleware.ts
2 > import {isPromise} from './utils/is-promise.js';
3 > import {YargsInstance, Arguments} from './yargs-factory.js';
4 >
5 > export class GlobalMiddleware {
6 > globalMiddleware: Middleware[] = [];
7 > yargs: YargsInstance;
8 > frozens: Array<Middleware[]> = [];
9 > constructor(yargs: YargsInstance) {
10 > this.yargs = yargs; middleware.ts
11 > }
12 > addMiddleware( middleware.ts
13 callback: MiddlewareCallback | MiddlewareCallback[],
14 applyBeforeValidation: boolean,
43 return this.yargs;
44 }
45 > // For "coerce" middleware, only one middleware instance can be registered middleware.ts
46 > // per option:
47 > addCoerceMiddleware(
48 callback: MiddlewareCallback,
49 option: string
58 return this.addMiddleware(callback, true, true, true);
59 }
60 > getMiddleware() { middleware.ts
61 return this.globalMiddleware;
62 }
63 > freeze() { middleware.ts
64 > this.frozens.push([...this.globalMiddleware]); middleware.ts
65 > }
66 > unfreeze() { middleware.ts
67 > const frozen = this.frozens.pop(); middleware.ts
68 > if (frozen !== undefined) this.globalMiddleware = frozen;
69 > }
70 > reset() { middleware.ts
71 > this.globalMiddleware = this.globalMiddleware.filter(m => m.global); middleware.ts
72 > }
73 > } middleware.ts
74 >
75 > export function commandMiddlewareFactory(
76 > commandMiddleware?: MiddlewareCallback[] middleware.ts
77 > ): Middleware[] {
78 > if (!commandMiddleware) return [];
79 return commandMiddleware.map(middleware => {
80 (middleware as Middleware).applyBeforeValidation = false;
82 }) as Middleware[];
83 }
85 > export function applyMiddleware(
86 argv: Arguments | Promise<Arguments>,
87 yargs: YargsInstance,
118 );
119 }
121 > export interface MiddlewareCallback {
122 > (
123 > argv: Arguments,
124 > yargs: YargsInstance
125 > ): Partial<Arguments> | Promise<Partial<Arguments>>;
126 > }
127 >
128 > export interface Middleware extends MiddlewareCallback {
129 > applyBeforeValidation: boolean;
130 > global: boolean;
131 > option?: string;
132 > mutates?: boolean;
133 > applied?: boolean;
134 > }
lib/parse-command.ts 44 covered LOC · 8 ranges

Open complete file

1 > import {NotEmptyArray} from './typings/common-types.js'; parse-command.ts
2 >
3 > export function parseCommand(cmd: string) {
4 > const extraSpacesStrippedCommand = cmd.replace(/\s{2,}/g, ' '); parse-command.ts
5 > const splitCommand = extraSpacesStrippedCommand.split(/\s+(?![^[]*]|[^<]*>)/);
6 > const bregex = /\.*[\][<>]/g;
7 >
8 > const firstCommand = splitCommand.shift();
9 > if (!firstCommand) throw new Error(`No command found in: ${cmd}`);
11 > const parsedCommand: ParsedCommand = {
12 > cmd: firstCommand.replace(bregex, ''),
13 > demanded: [],
14 > optional: [],
15 > };
16 > splitCommand.forEach((cmd, i) => {
17 > let variadic = false;
18 > cmd = cmd.replace(/\s/g, '');
19 > if (/\.+[\]>]/.test(cmd) && i === splitCommand.length - 1) variadic = true;
20 > if (/^\[/.test(cmd)) {
21 > parsedCommand.optional.push({ parse-command.ts
22 > cmd: cmd.replace(bregex, '').split('|') as NotEmptyArray<string>,
23 > variadic,
24 > });
25 > } else { parse-command.ts
26 > parsedCommand.demanded.push({ parse-command.ts
27 > cmd: cmd.replace(bregex, '').split('|') as NotEmptyArray<string>,
28 > variadic,
29 > });
30 > }
31 > }); parse-command.ts
32 > return parsedCommand;
33 > }
35 > export interface ParsedCommand {
36 > cmd: string;
37 > demanded: Positional[];
38 > optional: Positional[];
39 > }
40 >
41 > export interface Positional {
42 > cmd: NotEmptyArray<string>;
43 > variadic: boolean;
44 > }
lib/utils/process-argv.ts 34 covered LOC · 10 ranges

Open complete file

1 > function getProcessArgvBinIndex() { process-argv.ts
2 > // The binary name is the first command line argument for:
3 > // - bundled Electron apps: bin argv1 argv2 ... argvn
4 > if (isBundledElectronApp()) return 0;
5 > // or the second one (default) for: process-argv.ts
6 > // - standard node apps: node bin.js argv1 argv2 ... argvn
7 > // - unbundled Electron apps: electron bin.js argv1 arg2 ... argvn
8 > return 1;
9 > }
11 > function isBundledElectronApp() { process-argv.ts
12 > // process.defaultApp is either set by electron in an electron unbundled app, or undefined
13 > // see https://github.com/electron/electron/blob/main/docs/api/process.md#processdefaultapp-readonly
14 > return isElectronApp() && !(process as ElectronProcess).defaultApp;
15 > }
17 > function isElectronApp() { process-argv.ts
18 > // process.versions.electron is either set by electron, or undefined
19 > // see https://github.com/electron/electron/blob/main/docs/api/process.md#processversionselectron-readonly
20 > return !!(process as ElectronProcess).versions.electron;
21 > }
23 > export function hideBin(argv: string[]) {
24 return argv.slice(getProcessArgvBinIndex() + 1);
25 }
27 > export function getProcessArgvBin() {
28 > return process.argv[getProcessArgvBinIndex()]; process-argv.ts
29 > }
31 > interface ElectronProcess extends NodeJS.Process {
32 > defaultApp?: boolean;
33 > versions: NodeJS.ProcessVersions & {
34 > electron: string;
35 > };
36 > }
lib/utils/levenshtein.ts 27 covered LOC · 1 range

Open complete file

2 > Copyright (c) 2011 Andrei Mackenzie
3 >
4 > Permission is hereby granted, free of charge, to any person obtaining a copy of
5 > this software and associated documentation files (the "Software"), to deal in
6 > the Software without restriction, including without limitation the rights to
7 > use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 > the Software, and to permit persons to whom the Software is furnished to do so,
9 > subject to the following conditions:
10 >
11 > The above copyright notice and this permission notice shall be included in all
12 > copies or substantial portions of the Software.
13 >
14 > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16 > FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17 > COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 > IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 > CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 > */
21 >
22 > // levenshtein distance algorithm, pulled from Andrei Mackenzie's MIT licensed.
23 > // gist, which can be found here: https://gist.github.com/andrei-m/982927
24 > // extended to compute damerau-levenshtein distance
25 >
26 > // Compute the edit distance between the two given strings
27 > export function levenshtein(a: string, b: string) {
28 if (a.length === 0) return b.length;
29 if (b.length === 0) return a.length;
lib/utils/set-blocking.ts 18 covered LOC · 4 ranges

Open complete file

1 > interface WriteStreamWithHandle { set-blocking.ts
2 > _handle: {
3 > setBlocking: Function;
4 > };
5 > isTTY: boolean;
6 > }
7 >
8 > export default function setBlocking(blocking: boolean) {
9 > // Deno and browser have no process object: set-blocking.ts
10 > if (typeof process === 'undefined') return;
11 > [process.stdout, process.stderr].forEach(_stream => {
12 > const stream = _stream as any as WriteStreamWithHandle;
13 > if (
14 > stream._handle &&
15 > stream.isTTY &&
16 typeof stream._handle.setBlocking === 'function'
17 > ) { set-blocking.ts
18 stream._handle.setBlocking(blocking);
19 }
20 > }); set-blocking.ts
21 > }
lib/utils/obj-filter.ts 11 covered LOC · 3 ranges

Open complete file

1 > import {objectKeys} from '../typings/common-types.js'; obj-filter.ts
2 >
3 > export function objFilter<T extends object>(
4 > original = {} as T, obj-filter.ts
5 > filter: (k: keyof T, v: T[keyof T]) => boolean = () => true
6 > ) {
7 > const obj = {} as T;
8 > objectKeys(original).forEach(key => {
9 if (filter(key, original[key])) {
10 obj[key] = original[key];
11 }
12 > }); obj-filter.ts
13 > return obj;
14 > }
lib/utils/maybe-async-result.ts 10 covered LOC · 2 ranges

Open complete file

1 > // maybeAsyncResult() allows the same error/completion handler to be maybe-async-result.ts
2 > // applied to a value regardless of whether it is a concrete value or an
3 > // eventual value.
4 > //
5 > // As of yargs@v17, if no asynchronous steps are run, .e.g, a
6 > // check() script that resolves a promise, yargs will return a concrete
7 > // value. If any asynchronous steps are introduced, yargs resolves a promise.
8 > import {isPromise} from './is-promise.js';
9 > export function maybeAsyncResult<T>(
10 getResult: (() => T | Promise<T>) | T | Promise<T>,
11 resultHandler: (result: T) => T | Promise<T>,
23 }
24 }
26 function isFunction(arg: (() => any) | any): arg is () => any {
27 return typeof arg === 'function';
lib/utils/apply-extends.ts 9 covered LOC · 4 ranges

Open complete file

1 > import {Dictionary, PlatformShim} from '../typings/common-types.js'; apply-extends.ts
2 > import {YError} from '../yerror.js';
3 >
4 > let previouslyVisitedConfigs: string[] = [];
5 > let shim: PlatformShim;
6 > export function applyExtends(
7 config: Dictionary,
8 cwd: string,
51 : Object.assign({}, defaultConfig, config);
52 }
54 function checkForCircularExtends(cfgPath: string) {
55 if (previouslyVisitedConfigs.indexOf(cfgPath) > -1) {
57 }
58 }
60 function getPathToDefaultConfig(cwd: string, pathToExtend: string) {
61 return shim.path.resolve(cwd, pathToExtend);
62 }
64 function mergeDeep(config1: Dictionary, config2: Dictionary) {
65 const target: Dictionary = {};
lib/utils/is-promise.ts 8 covered LOC · 3 ranges

Open complete file

1 > export function isPromise<T>( is-promise.ts
2 > maybePromise: T | Promise<T> is-promise.ts
3 > ): maybePromise is Promise<T> {
4 > return (
5 > !!maybePromise &&
6 > !!(maybePromise as Promise<T>).then &&
7 typeof (maybePromise as Promise<T>).then === 'function'
8 > ); is-promise.ts
9 > }
lib/yerror.ts 4 covered LOC · 2 ranges

Open complete file

1 > export class YError extends Error { yerror.ts
2 > name = 'YError';
3 > constructor(msg?: string | null) {
4 super(msg || 'yargs error');
5 if (Error.captureStackTrace) {