lib/usage.ts

835 LOC · 835 covered · 0 uncovered · 195 ranges · 1119 concepts · 85 introducers · 788 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > // this file handles outputting usage instructions, yargs-factory.ts ×124
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 { usage.ts ×4
11 > return typeof fail === 'boolean';
12 > }
14 > export function usage(yargs: YargsInstance, shim: PlatformShim) {
15 > const __ = shim.y18n.__; yargs-factory.ts ×35
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); usage.ts ×1
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, usage.ts ×2
28 > arg2?: string
29 > ) {
30 > const [enabled, message] =
31 > typeof arg1 === 'string' ? [true, arg1] : [arg1, arg2];
32 >
33 > // If global context, set globalFailMessage
34 > // Addresses: https://github.com/yargs/yargs/issues/2085
35 > if (yargs.getInternalMethods().isGlobalContext()) {
36 > globalFailMessage = message; usage.ts ×1
37 > }
39 > failMessage = message;
40 > showHelpOnFail = enabled;
41 > return self;
43 >
44 > let failureOutput = false;
45 > self.fail = function fail(msg, err) {
46 > const logger = yargs.getInternalMethods().getLoggerInstance(); usage.ts ×1
47 >
48 > if (fails.length) {
49 > for (let i = fails.length - 1; i >= 0; --i) { usage.ts ×4
50 > const fail = fails[i];
51 > if (isBoolean(fail)) {
52 > if (err) throw err; usage.ts ×1
53 > else if (msg) throw Error(msg); usage.ts ×1
54 > } else { usage.ts ×4
55 > fail(msg, err, self); usage.ts ×1
56 > }
57 > } usage.ts ×4
58 > } else { usage.ts ×1
59 > if (yargs.getExitProcess()) setBlocking(true); usage.ts ×5
60 >
61 > // don't output failure message more than once
62 > if (!failureOutput) {
63 > failureOutput = true;
64 > if (showHelpOnFail) {
65 > yargs.showHelp('error'); usage.ts ×1
66 > logger.error();
67 > }
68 > if (msg || err) logger.error(msg || err); usage.ts ×5
69 > const globalOrCommandFailMessage = failMessage || globalFailMessage;
70 > if (globalOrCommandFailMessage) {
71 > if (msg || err) logger.error(''); usage.ts ×1
72 > logger.error(globalOrCommandFailMessage);
73 > }
74 > } usage.ts ×5
75 >
76 > err = err || new YError(msg);
77 > if (yargs.getExitProcess()) {
78 > return yargs.exit(1); usage.ts ×1
79 > } else if (yargs.getInternalMethods().hasParseCallback()) { usage.ts ×5
80 > return yargs.exit(1, err); usage.ts ×1
81 > } else { usage.ts ×1
82 > throw err; usage.ts ×1
83 > }
84 > } usage.ts ×5
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) { usage.ts ×2
92 > usageDisabled = true; usage.ts ×1
93 > usages = [];
94 > return self;
95 > }
96 > usageDisabled = false; usage.ts ×1
97 > usages.push([msg, description || '']); usage.ts ×2
98 > return self;
100 > self.getUsage = () => {
101 > return usages; command.ts ×1
103 > self.getUsageDisabled = () => {
104 > return usageDisabled; command.ts ×2
106 >
107 > self.getPositionalGroupName = () => {
108 > return __('Positionals:'); usage.ts ×1
110 >
111 > let examples: [string, string][] = [];
112 > self.example = (cmd, description) => {
113 > examples.push([cmd, description || '']); usage.ts ×4
115 >
116 > let commands: [string, string, boolean, string[], boolean][] = [];
117 > self.command = function command(
118 > cmd, usage.ts ×2
119 > description,
120 > isDefault,
121 > aliases,
122 > deprecated = false
123 > ) {
124 > // the last default wins, so cancel out any previously set default
125 > if (isDefault) {
126 > commands = commands.map(cmdArray => { command.ts ×2
127 > cmdArray[2] = false; usage.ts ×1
128 > return cmdArray;
129 > }); command.ts ×2
130 > }
131 > commands.push([cmd, description || '', isDefault, aliases, deprecated]); usage.ts ×2
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 => { usage.ts ×1
142 > self.describe(k, desc);
143 > });
144 > } else if (typeof keyOrKeys === 'object') { yargs-factory.ts ×35
145 > Object.keys(keyOrKeys).forEach(k => { usage.ts ×1
146 > self.describe(k, keyOrKeys[k]);
147 > });
148 > } else { yargs-factory.ts ×35
149 > descriptions[keyOrKeys] = desc;
150 > }
151 > };
152 > self.getDescriptions = () => descriptions;
153 >
154 > let epilogs: string[] = [];
155 > self.epilog = msg => {
156 > epilogs.push(msg); usage.ts ×2
158 >
159 > let wrapSet = false;
160 > let wrap: number | nil;
161 > self.wrap = cols => {
162 > wrapSet = true; usage.ts ×1
163 > wrap = cols;
165 >
166 > self.getWrap = () => {
167 > if (shim.getEnv('YARGS_DISABLE_WRAP')) { usage.ts ×1
168 > return null; usage.ts ×1
169 > }
170 > if (!wrapSet) { usage.ts ×19
171 > wrap = windowWidth(); usage.ts ×3
172 > wrapSet = true;
173 > }
175 > return wrap;
177 >
178 > const deferY18nLookupPrefix = '__yargsString__:';
179 > self.deferY18nLookup = str => deferY18nLookupPrefix + str;
180 >
181 > self.help = function help() {
182 > if (cachedHelpMessage) return cachedHelpMessage; usage.ts ×19
183 > normalizeAliases();
184 >
185 > // handle old demanded API
186 > const base$0 = yargs.customScriptName
187 > ? yargs.$0
188 > : shim.path.basename(yargs.$0);
189 > const demandedOptions = yargs.getDemandedOptions();
190 > const demandedCommands = yargs.getDemandedCommands();
191 > const deprecatedOptions = yargs.getDeprecatedOptions();
192 > const groups = yargs.getGroups();
193 > const options = yargs.getOptions();
194 >
195 > let keys: string[] = [];
196 > keys = keys.concat(Object.keys(descriptions));
197 > keys = keys.concat(Object.keys(demandedOptions));
198 > keys = keys.concat(Object.keys(demandedCommands));
199 > keys = keys.concat(Object.keys(options.default));
200 > keys = keys.filter(filterHiddenOptions);
201 > keys = Object.keys(
202 > keys.reduce((acc, key) => {
203 > if (key !== '_') acc[key] = true;
204 > return acc;
205 > }, {} as Dictionary<boolean>)
206 > );
207 >
208 > const theWrap = self.getWrap();
209 > const ui = shim.cliui({
210 > width: theWrap,
211 > wrap: !!theWrap,
212 > });
213 >
214 > // the usage string.
215 > if (!usageDisabled) {
216 > if (usages.length) { usage.ts ×3
217 > // user-defined usage. usage.ts ×2
218 > usages.forEach(usage => {
219 > ui.div({text: `${usage[0].replace(/\$0/g, base$0)}`});
220 > if (usage[1]) {
221 > ui.div({text: `${usage[1]}`, padding: [1, 0, 0, 0]}); usage.ts ×1
222 > }
223 > }); usage.ts ×2
224 > ui.div();
225 > } else if (commands.length) { usage.ts ×3
226 > let u = null; usage.ts ×3
227 > // demonstrate how commands are used.
228 > if (demandedCommands._) {
229 > u = `${base$0} <${__('command')}>\n`; usage.ts ×1
230 > } else { usage.ts ×3
231 > u = `${base$0} [${__('command')}]\n`; usage.ts ×1
232 > }
233 > ui.div(`${u}`); usage.ts ×3
234 > }
235 > } usage.ts ×3
237 > // your application's commands, i.e., non-option
238 > // arguments populated in '_'.
239 > //
240 > // If there's only a single command, and it's the default command
241 > // (represented by commands[0][2]) don't show command stanza:
242 > //
243 > // TODO(@bcoe): why isn't commands[0][2] an object with a named property?
244 > if (commands.length > 1 || (commands.length === 1 && !commands[0][2])) {
245 > ui.div(__('Commands:')); usage.ts ×6
246 >
247 > const context = yargs.getInternalMethods().getContext();
248 > const parentCommands = context.commands.length
249 > ? `${context.commands.join(' ')} `
250 > : '';
251 >
252 > if (
253 > yargs.getInternalMethods().getParserConfiguration()['sort-commands'] ===
254 > true
255 > ) {
256 > commands = commands.sort((a, b) => a[0].localeCompare(b[0])); usage.ts ×1
257 > }
258 > usage.ts ×6
259 > const prefix = base$0 ? `${base$0} ` : '';
260 >
261 > commands.forEach(command => {
262 > const commandString = `${prefix}${parentCommands}${command[0].replace(
263 > /^\$0 ?/,
264 > ''
265 > )}`; // drop $0 from default commands.
266 > ui.span(
267 > {
268 > text: commandString,
269 > padding: [0, 2, 0, 2],
270 > width:
271 > maxWidth(commands, theWrap, `${base$0}${parentCommands}`) + 4,
272 > },
273 > {text: command[1]}
274 > );
275 > const hints = [];
276 > if (command[2]) hints.push(`[${__('default')}]`);
277 > if (command[3] && command[3].length) {
278 > hints.push(`[${__('aliases:')} ${command[3].join(', ')}]`); usage.ts ×1
279 > }
280 > if (command[4]) { usage.ts ×6
281 > if (typeof command[4] === 'string') { usage.ts ×3
282 > hints.push(`[${__('deprecated: %s', command[4])}]`); usage.ts ×1
283 > } else { usage.ts ×3
284 > hints.push(`[${__('deprecated')}]`); usage.ts ×1
285 > }
286 > } usage.ts ×3
287 > if (hints.length) { usage.ts ×6
288 > ui.div({ usage.ts ×1
289 > text: hints.join(' '),
290 > padding: [0, 0, 0, 2],
291 > align: 'right',
292 > });
293 > } else { usage.ts ×6
294 > ui.div(); usage.ts ×1
295 > }
296 > }); usage.ts ×6
297 >
298 > ui.div();
299 > }
301 > // perform some cleanup on the keys array, making it
302 > // only include top-level keys not their aliases.
303 > const aliasKeys = (Object.keys(options.alias) || []).concat(
304 > Object.keys((yargs.parsed as DetailedArguments).newAliases) || []
305 > );
306 >
307 > keys = keys.filter(
308 > key =>
309 > !(yargs.parsed as DetailedArguments).newAliases[key] && usage.ts ×17
310 > aliasKeys.every(
311 > alias => (options.alias[alias] || []).indexOf(key) === -1
312 > ) usage.ts ×19
313 > );
314 >
315 > // populate 'Options:' group with any keys that have not
316 > // explicitly had a group set.
317 > const defaultGroup = __('Options:');
318 > if (!groups[defaultGroup]) groups[defaultGroup] = [];
319 > addUngroupedKeys(keys, options.alias, groups, defaultGroup);
320 >
321 > const isLongSwitch = (sw: string | IndentedText) => /^--/.test(getText(sw));
322 >
323 > // prepare 'Options:' tables display
324 > const displayedGroups = Object.keys(groups)
325 > .filter(groupName => groups[groupName].length > 0)
326 > .map(groupName => {
327 > // if we've grouped the key 'f', but 'f' aliases 'foobar', usage.ts ×17
328 > // normalizedKeys should contain only 'foobar'.
329 > const normalizedKeys: string[] = groups[groupName]
330 > .filter(filterHiddenOptions)
331 > .map(key => {
332 > if (aliasKeys.includes(key)) return key;
333 > for ( usage.ts ×2
334 > let i = 0, aliasKey;
335 > (aliasKey = aliasKeys[i]) !== undefined;
336 > i++
337 > ) {
338 > if ((options.alias[aliasKey] || []).includes(key)) usage.ts ×1
339 > return aliasKey;
340 > }
341 > return key; usage.ts ×2
342 > }); usage.ts ×17
343 >
344 > return {groupName, normalizedKeys};
345 > }) usage.ts ×19
346 > .filter(({normalizedKeys}) => normalizedKeys.length > 0)
347 > .map(({groupName, normalizedKeys}) => {
348 > // actually generate the switches string --foo, -f, --bar. usage.ts ×17
349 > const switches: Dictionary<string | IndentedText> =
350 > normalizedKeys.reduce((acc, key) => {
351 > acc[key] = [key]
352 > .concat(options.alias[key] || [])
353 > .map(sw => {
354 > // for the special positional group don't
355 > // add '--' or '-' prefix.
356 > if (groupName === self.getPositionalGroupName()) return sw;
357 > else {
358 > return (
359 > // matches yargs-parser logic in which single-digits
360 > // aliases declared with a boolean type are now valid
361 > (/^[0-9]$/.test(sw)
362 > ? options.boolean.includes(key)
363 > ? '-' usage.ts ×1
364 > : '--'
365 > : sw.length > 1 usage.ts ×17
366 > ? '--'
367 > : '-') + sw
368 > );
369 > }
370 > })
371 > // place short switches first (see #1403)
372 > .sort((sw1, sw2) =>
373 > isLongSwitch(sw1) === isLongSwitch(sw2) usage.ts ×1
374 > ? 0
375 > : isLongSwitch(sw1)
376 > ? 1 usage.ts ×1
377 > : -1
378 > ) usage.ts ×17
379 > .join(', ');
380 >
381 > return acc;
382 > }, {} as Dictionary<string>);
383 >
384 > return {groupName, normalizedKeys, switches};
385 > }); usage.ts ×19
386 >
387 > // if some options use short switches, indent long-switches only options (see #1403)
388 > const shortSwitchesUsed = displayedGroups
389 > .filter(({groupName}) => groupName !== self.getPositionalGroupName())
390 > .some(
391 > ({normalizedKeys, switches}) =>
392 > !normalizedKeys.every(key => isLongSwitch(switches[key])) usage.ts ×17
393 > ); usage.ts ×19
394 >
395 > if (shortSwitchesUsed) {
396 > displayedGroups usage.ts ×2
397 > .filter(({groupName}) => groupName !== self.getPositionalGroupName())
398 > .forEach(({normalizedKeys, switches}) => {
399 > normalizedKeys.forEach(key => {
400 > if (isLongSwitch(switches[key])) {
401 > switches[key] = addIndentation(switches[key], '-x, '.length); usage.ts ×2
402 > }
403 > }); usage.ts ×2
404 > });
405 > }
407 > // display 'Options:' table along with any custom tables:
408 > displayedGroups.forEach(({groupName, normalizedKeys, switches}) => {
409 > ui.div(groupName); usage.ts ×17
410 >
411 > normalizedKeys.forEach(key => {
412 > const kswitch = switches[key];
413 > let desc = descriptions[key] || '';
414 > let type = null;
415 >
416 > if (desc.includes(deferY18nLookupPrefix))
417 > desc = __(desc.substring(deferY18nLookupPrefix.length));
418 >
419 > if (options.boolean.includes(key)) type = `[${__('boolean')}]`;
420 > if (options.count.includes(key)) type = `[${__('count')}]`;
421 > if (options.string.includes(key)) type = `[${__('string')}]`;
422 > if (options.normalize.includes(key)) type = `[${__('string')}]`;
423 > if (options.array.includes(key)) type = `[${__('array')}]`;
424 > if (options.number.includes(key)) type = `[${__('number')}]`;
425 >
426 > const deprecatedExtra = (deprecated?: string | boolean) =>
427 > typeof deprecated === 'string' usage.ts ×1
428 > ? `[${__('deprecated: %s', deprecated)}]`
429 > : `[${__('deprecated')}]`; usage.ts ×17
430 >
431 > const extra = [
432 > key in deprecatedOptions
433 > ? deprecatedExtra(deprecatedOptions[key])
434 > : null,
435 > type,
436 > key in demandedOptions ? `[${__('required')}]` : null,
437 > options.choices && options.choices[key]
438 > ? `[${__('choices:')} ${self.stringifiedValues(
439 > options.choices[key] usage.ts ×1
440 > )}]`
441 > : null, usage.ts ×17
442 > defaultString(options.default[key], options.defaultDescription[key]),
443 > ]
444 > .filter(Boolean)
445 > .join(' ');
446 >
447 > ui.span(
448 > {
449 > text: getText(kswitch),
450 > padding: [0, 2, 0, 2 + getIndentation(kswitch)],
451 > width: maxWidth(switches, theWrap) + 4,
452 > },
453 > desc
454 > );
455 >
456 > const shouldHideOptionExtras =
457 > yargs.getInternalMethods().getUsageConfiguration()['hide-types'] ===
458 > true;
459 >
460 > if (extra && !shouldHideOptionExtras)
461 > ui.div({text: extra, padding: [0, 0, 0, 2], align: 'right'});
462 > else ui.div(); usage.ts ×1
463 > }); usage.ts ×17
464 >
465 > ui.div();
466 > }); usage.ts ×19
467 >
468 > // describe some common use-cases for your application.
469 > if (examples.length) {
470 > ui.div(__('Examples:')); usage.ts ×4
471 >
472 > examples.forEach(example => {
473 > example[0] = example[0].replace(/\$0/g, base$0);
474 > });
475 >
476 > examples.forEach(example => {
477 > if (example[1] === '') {
478 > ui.div({ usage.ts ×1
479 > text: example[0],
480 > padding: [0, 2, 0, 2],
481 > });
482 > } else { usage.ts ×4
483 > ui.div( usage.ts ×1
484 > {
485 > text: example[0],
486 > padding: [0, 2, 0, 2],
487 > width: maxWidth(examples, theWrap) + 4,
488 > },
489 > {
490 > text: example[1],
491 > }
492 > );
493 > }
494 > }); usage.ts ×4
495 >
496 > ui.div();
497 > }
499 > // the usage string.
500 > if (epilogs.length > 0) {
501 > const e = epilogs usage.ts ×2
502 > .map(epilog => epilog.replace(/\$0/g, base$0))
503 > .join('\n');
504 > ui.div(`${e}\n`);
505 > }
507 > // Remove the trailing white spaces
508 > return ui.toString().replace(/\s*$/, '');
510 >
511 > // return the maximum width of a string
512 > // in the left-hand column of a table.
513 > function maxWidth(
514 > table: usage.ts ×17
515 > [string | IndentedText, ...any[]][] | Dictionary<string | IndentedText>,
516 > theWrap?: number | null,
517 > modifier?: string
518 > ) {
519 > let width = 0;
520 >
521 > // table might be of the form [leftColumn],
522 > // or {key: leftColumn}
523 > if (!Array.isArray(table)) {
524 > table = Object.values(table).map<[string | IndentedText]>(v => [v]);
525 > }
526 >
527 > table.forEach(v => {
528 > // column might be of the form "text"
529 > // or { text: "text", indent: 4 }
530 > width = Math.max(
531 > shim.stringWidth(
532 > modifier ? `${modifier} ${getText(v[0])}` : getText(v[0])
533 > ) + getIndentation(v[0]),
534 > width
535 > );
536 > });
537 >
538 > // if we've enabled 'wrap' we should limit
539 > // the max-width of the left-column.
540 > if (theWrap)
541 > width = Math.min(width, parseInt((theWrap * 0.5).toString(), 10));
542 >
543 > return width;
544 > }
546 > // make sure any options set for aliases,
547 > // are copied to the keys being aliased.
548 > function normalizeAliases() {
549 > // handle old demanded API usage.ts ×19
550 > const demandedOptions = yargs.getDemandedOptions();
551 > const options = yargs.getOptions();
552 >
553 > (Object.keys(options.alias) || []).forEach(key => {
554 > options.alias[key].forEach(alias => { usage.ts ×2
555 > // copy descriptions. usage.ts ×1
556 > if (descriptions[alias]) self.describe(key, descriptions[alias]);
557 > // copy demanded.
558 > if (alias in demandedOptions)
559 > yargs.demandOption(key, demandedOptions[alias]);
560 > // type messages.
561 > if (options.boolean.includes(alias)) yargs.boolean(key);
562 > if (options.count.includes(alias)) yargs.count(key);
563 > if (options.string.includes(alias)) yargs.string(key);
564 > if (options.normalize.includes(alias)) yargs.normalize(key);
565 > if (options.array.includes(alias)) yargs.array(key);
566 > if (options.number.includes(alias)) yargs.number(key);
567 > }); usage.ts ×2
568 > }); usage.ts ×19
569 > }
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(); command.ts ×1
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; yargs-factory.ts ×9
583 >
584 > self.hasCachedHelpMessage = function () {
585 > return !!cachedHelpMessage; usage.ts ×1
587 >
588 > // given a set of keys, place any keys that are
589 > // ungrouped under the 'Options:' grouping.
590 > function addUngroupedKeys(
591 > keys: string[], usage.ts ×19
592 > aliases: Dictionary<string[]>,
593 > groups: Dictionary<string[]>,
594 > defaultGroup: string
595 > ) {
596 > let groupedKeys = [] as string[];
597 > let toCheck = null;
598 > Object.keys(groups).forEach(group => {
599 > groupedKeys = groupedKeys.concat(groups[group]);
600 > });
601 >
602 > keys.forEach(key => {
603 > toCheck = [key].concat(aliases[key]); usage.ts ×17
604 > if (!toCheck.some(k => groupedKeys.indexOf(k) !== -1)) {
605 > groups[defaultGroup].push(key); usage.ts ×1
606 > }
607 > }); usage.ts ×19
608 > return groupedKeys;
609 > }
611 > function filterHiddenOptions(key: string) {
612 > return ( usage.ts ×19
613 > yargs.getOptions().hiddenOptions.indexOf(key) < 0 ||
614 > (yargs.parsed as DetailedArguments).argv[yargs.getOptions().showHiddenOpt] usage.ts ×1
615 > ); usage.ts ×19
616 > }
618 > self.showHelp = (level: 'error' | 'log' | ((message: string) => void)) => {
619 > const logger = yargs.getInternalMethods().getLoggerInstance(); usage.ts ×1
620 > if (!level) level = 'error';
621 > const emit = typeof level === 'function' ? level : logger[level];
622 > emit(self.help());
624 >
625 > self.functionDescription = fn => {
626 > const description = fn.name usage.ts ×1
627 > ? shim.Parser.decamelize(fn.name, '-')
628 > : __('generated-value');
629 > return ['(', description, ')'].join('');
631 >
632 > self.stringifiedValues = function stringifiedValues(values, separator) {
633 > let string = ''; usage.ts ×1
634 > const sep = separator || ', ';
635 > const array = ([] as any[]).concat(values);
636 >
637 > if (!values || !array.length) return string;
638 >
639 > array.forEach(value => {
640 > if (string.length) string += sep;
641 > string += JSON.stringify(value);
642 > });
643 >
644 > return string;
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:')} `; usage.ts ×17
651 >
652 > if (value === undefined && !defaultDescription) return null;
653 > usage.ts ×3
654 > if (defaultDescription) {
655 > string += defaultDescription; usage.ts ×1
656 > } else { usage.ts ×3
657 > switch (typeof value) { usage.ts ×4
658 > case 'string':
659 > string += `"${value}"`; usage.ts ×1
660 > break;
661 > case 'object': usage.ts ×4
662 > string += JSON.stringify(value); usage.ts ×1
663 > break;
664 > default: usage.ts ×4
665 > string += value; usage.ts ×1
666 > } usage.ts ×4
667 > }
668 > usage.ts ×3
669 > return `${string}]`;
670 > }
672 > // guess the width of the console window, max-width 80.
673 > function windowWidth() {
674 > const maxWidth = 80; usage.ts ×3
675 > // CI is not a TTY
676 > /* c8 ignore next 2 */ yargs-factory.ts ×124
677 > if (shim.process.stdColumns) {
678 > return Math.min(maxWidth, shim.process.stdColumns);
679 > } else { usage.ts ×3
680 > return maxWidth;
681 > }
682 > }
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(); usage.ts ×1
692 > if (!level) level = 'error';
693 > const emit = typeof level === 'function' ? level : logger[level];
694 > emit(version);
696 >
697 > self.reset = function reset(localLookup) {
698 > // do not reset wrap here command.ts ×1
699 > // do not reset fails here
700 > failMessage = null;
701 > failureOutput = false;
702 > usages = [];
703 > usageDisabled = false;
704 > epilogs = [];
705 > examples = [];
706 > commands = [];
707 > descriptions = objFilter(descriptions, k => !localLookup[k]);
708 > return self;
710 >
711 > const frozens = [] as FrozenUsageInstance[];
712 > self.freeze = function freeze() {
713 > frozens.push({ usage.ts ×1
714 > failMessage,
715 > failureOutput,
716 > usages,
717 > usageDisabled,
718 > epilogs,
719 > examples,
720 > commands,
721 > descriptions,
722 > });
724 > self.unfreeze = function unfreeze(defaultCommand = false) {
725 > const frozen = frozens.pop(); usage.ts ×2
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}; usage.ts ×1
733 > commands = [...frozen.commands, ...commands];
734 > usages = [...frozen.usages, ...usages];
735 > examples = [...frozen.examples, ...examples];
736 > epilogs = [...frozen.epilogs, ...epilogs];
737 > } else { usage.ts ×2
739 > failMessage,
740 > failureOutput,
741 > usages,
742 > usageDisabled,
743 > epilogs,
744 > examples,
745 > commands,
746 > descriptions,
747 > } = frozen);
748 > }
750 >
751 > return self;
752 > }
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 { usage.ts ×17
817 > return typeof text === 'object';
818 > }
820 > function addIndentation( usage.ts ×2
821 > text: string | IndentedText,
822 > indent: number
823 > ): IndentedText {
824 > return isIndentedText(text)
825 > ? {text: text.text, indentation: text.indentation + indent}
826 > : {text, indentation: indent};
827 > }
829 > function getIndentation(text: string | IndentedText): number { usage.ts ×17
830 > return isIndentedText(text) ? text.indentation : 0;
831 > }
833 > function getText(text: string | IndentedText): string { usage.ts ×17
834 > return isIndentedText(text) ? text.text : text;
835 > }