commander 12.0.0 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/error.js CHANGED
@@ -1,6 +1,5 @@
1
1
  /**
2
2
  * CommanderError class
3
- * @class
4
3
  */
5
4
  class CommanderError extends Error {
6
5
  /**
@@ -8,7 +7,6 @@ class CommanderError extends Error {
8
7
  * @param {number} exitCode suggested exit code which could be used with process.exit
9
8
  * @param {string} code an id string representing the error
10
9
  * @param {string} message human-readable description of the error
11
- * @constructor
12
10
  */
13
11
  constructor(exitCode, code, message) {
14
12
  super(message);
@@ -23,13 +21,11 @@ class CommanderError extends Error {
23
21
 
24
22
  /**
25
23
  * InvalidArgumentError class
26
- * @class
27
24
  */
28
25
  class InvalidArgumentError extends CommanderError {
29
26
  /**
30
27
  * Constructs the InvalidArgumentError class
31
28
  * @param {string} [message] explanation of why argument is invalid
32
- * @constructor
33
29
  */
34
30
  constructor(message) {
35
31
  super(1, 'commander.invalidArgument', message);
package/lib/help.js CHANGED
@@ -25,14 +25,14 @@ class Help {
25
25
  */
26
26
 
27
27
  visibleCommands(cmd) {
28
- const visibleCommands = cmd.commands.filter(cmd => !cmd._hidden);
28
+ const visibleCommands = cmd.commands.filter((cmd) => !cmd._hidden);
29
29
  const helpCommand = cmd._getHelpCommand();
30
30
  if (helpCommand && !helpCommand._hidden) {
31
31
  visibleCommands.push(helpCommand);
32
32
  }
33
33
  if (this.sortSubcommands) {
34
34
  visibleCommands.sort((a, b) => {
35
- // @ts-ignore: overloaded return type
35
+ // @ts-ignore: because overloaded return type
36
36
  return a.name().localeCompare(b.name());
37
37
  });
38
38
  }
@@ -44,12 +44,14 @@ class Help {
44
44
  *
45
45
  * @param {Option} a
46
46
  * @param {Option} b
47
- * @returns number
47
+ * @returns {number}
48
48
  */
49
49
  compareOptions(a, b) {
50
50
  const getSortKey = (option) => {
51
51
  // WYSIWYG for order displayed in help. Short used for comparison if present. No special handling for negated.
52
- return option.short ? option.short.replace(/^-/, '') : option.long.replace(/^--/, '');
52
+ return option.short
53
+ ? option.short.replace(/^-/, '')
54
+ : option.long.replace(/^--/, '');
53
55
  };
54
56
  return getSortKey(a).localeCompare(getSortKey(b));
55
57
  }
@@ -72,9 +74,13 @@ class Help {
72
74
  if (!removeShort && !removeLong) {
73
75
  visibleOptions.push(helpOption); // no changes needed
74
76
  } else if (helpOption.long && !removeLong) {
75
- visibleOptions.push(cmd.createOption(helpOption.long, helpOption.description));
77
+ visibleOptions.push(
78
+ cmd.createOption(helpOption.long, helpOption.description),
79
+ );
76
80
  } else if (helpOption.short && !removeShort) {
77
- visibleOptions.push(cmd.createOption(helpOption.short, helpOption.description));
81
+ visibleOptions.push(
82
+ cmd.createOption(helpOption.short, helpOption.description),
83
+ );
78
84
  }
79
85
  }
80
86
  if (this.sortOptions) {
@@ -94,8 +100,14 @@ class Help {
94
100
  if (!this.showGlobalOptions) return [];
95
101
 
96
102
  const globalOptions = [];
97
- for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
98
- const visibleOptions = ancestorCmd.options.filter((option) => !option.hidden);
103
+ for (
104
+ let ancestorCmd = cmd.parent;
105
+ ancestorCmd;
106
+ ancestorCmd = ancestorCmd.parent
107
+ ) {
108
+ const visibleOptions = ancestorCmd.options.filter(
109
+ (option) => !option.hidden,
110
+ );
99
111
  globalOptions.push(...visibleOptions);
100
112
  }
101
113
  if (this.sortOptions) {
@@ -114,13 +126,14 @@ class Help {
114
126
  visibleArguments(cmd) {
115
127
  // Side effect! Apply the legacy descriptions before the arguments are displayed.
116
128
  if (cmd._argsDescription) {
117
- cmd.registeredArguments.forEach(argument => {
118
- argument.description = argument.description || cmd._argsDescription[argument.name()] || '';
129
+ cmd.registeredArguments.forEach((argument) => {
130
+ argument.description =
131
+ argument.description || cmd._argsDescription[argument.name()] || '';
119
132
  });
120
133
  }
121
134
 
122
135
  // If there are any arguments with a description then return all the arguments.
123
- if (cmd.registeredArguments.find(argument => argument.description)) {
136
+ if (cmd.registeredArguments.find((argument) => argument.description)) {
124
137
  return cmd.registeredArguments;
125
138
  }
126
139
  return [];
@@ -135,11 +148,15 @@ class Help {
135
148
 
136
149
  subcommandTerm(cmd) {
137
150
  // Legacy. Ignores custom usage string, and nested commands.
138
- const args = cmd.registeredArguments.map(arg => humanReadableArgName(arg)).join(' ');
139
- return cmd._name +
151
+ const args = cmd.registeredArguments
152
+ .map((arg) => humanReadableArgName(arg))
153
+ .join(' ');
154
+ return (
155
+ cmd._name +
140
156
  (cmd._aliases[0] ? '|' + cmd._aliases[0] : '') +
141
157
  (cmd.options.length ? ' [options]' : '') + // simplistic check for non-help option
142
- (args ? ' ' + args : '');
158
+ (args ? ' ' + args : '')
159
+ );
143
160
  }
144
161
 
145
162
  /**
@@ -234,7 +251,11 @@ class Help {
234
251
  cmdName = cmdName + '|' + cmd._aliases[0];
235
252
  }
236
253
  let ancestorCmdNames = '';
237
- for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
254
+ for (
255
+ let ancestorCmd = cmd.parent;
256
+ ancestorCmd;
257
+ ancestorCmd = ancestorCmd.parent
258
+ ) {
238
259
  ancestorCmdNames = ancestorCmd.name() + ' ' + ancestorCmdNames;
239
260
  }
240
261
  return ancestorCmdNames + cmdName + ' ' + cmd.usage();
@@ -248,7 +269,7 @@ class Help {
248
269
  */
249
270
 
250
271
  commandDescription(cmd) {
251
- // @ts-ignore: overloaded return type
272
+ // @ts-ignore: because overloaded return type
252
273
  return cmd.description();
253
274
  }
254
275
 
@@ -261,7 +282,7 @@ class Help {
261
282
  */
262
283
 
263
284
  subcommandDescription(cmd) {
264
- // @ts-ignore: overloaded return type
285
+ // @ts-ignore: because overloaded return type
265
286
  return cmd.summary() || cmd.description();
266
287
  }
267
288
 
@@ -278,15 +299,20 @@ class Help {
278
299
  if (option.argChoices) {
279
300
  extraInfo.push(
280
301
  // use stringify to match the display of the default value
281
- `choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`);
302
+ `choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`,
303
+ );
282
304
  }
283
305
  if (option.defaultValue !== undefined) {
284
306
  // default for boolean and negated more for programmer than end user,
285
307
  // but show true/false for boolean option as may be for hand-rolled env or config processing.
286
- const showDefault = option.required || option.optional ||
308
+ const showDefault =
309
+ option.required ||
310
+ option.optional ||
287
311
  (option.isBoolean() && typeof option.defaultValue === 'boolean');
288
312
  if (showDefault) {
289
- extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`);
313
+ extraInfo.push(
314
+ `default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`,
315
+ );
290
316
  }
291
317
  }
292
318
  // preset for boolean and negated are more for programmer than end user
@@ -315,10 +341,13 @@ class Help {
315
341
  if (argument.argChoices) {
316
342
  extraInfo.push(
317
343
  // use stringify to match the display of the default value
318
- `choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`);
344
+ `choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`,
345
+ );
319
346
  }
320
347
  if (argument.defaultValue !== undefined) {
321
- extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`);
348
+ extraInfo.push(
349
+ `default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`,
350
+ );
322
351
  }
323
352
  if (extraInfo.length > 0) {
324
353
  const extraDescripton = `(${extraInfo.join(', ')})`;
@@ -346,7 +375,11 @@ class Help {
346
375
  function formatItem(term, description) {
347
376
  if (description) {
348
377
  const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
349
- return helper.wrap(fullText, helpWidth - itemIndentWidth, termWidth + itemSeparatorWidth);
378
+ return helper.wrap(
379
+ fullText,
380
+ helpWidth - itemIndentWidth,
381
+ termWidth + itemSeparatorWidth,
382
+ );
350
383
  }
351
384
  return term;
352
385
  }
@@ -360,12 +393,18 @@ class Help {
360
393
  // Description
361
394
  const commandDescription = helper.commandDescription(cmd);
362
395
  if (commandDescription.length > 0) {
363
- output = output.concat([helper.wrap(commandDescription, helpWidth, 0), '']);
396
+ output = output.concat([
397
+ helper.wrap(commandDescription, helpWidth, 0),
398
+ '',
399
+ ]);
364
400
  }
365
401
 
366
402
  // Arguments
367
403
  const argumentList = helper.visibleArguments(cmd).map((argument) => {
368
- return formatItem(helper.argumentTerm(argument), helper.argumentDescription(argument));
404
+ return formatItem(
405
+ helper.argumentTerm(argument),
406
+ helper.argumentDescription(argument),
407
+ );
369
408
  });
370
409
  if (argumentList.length > 0) {
371
410
  output = output.concat(['Arguments:', formatList(argumentList), '']);
@@ -373,24 +412,39 @@ class Help {
373
412
 
374
413
  // Options
375
414
  const optionList = helper.visibleOptions(cmd).map((option) => {
376
- return formatItem(helper.optionTerm(option), helper.optionDescription(option));
415
+ return formatItem(
416
+ helper.optionTerm(option),
417
+ helper.optionDescription(option),
418
+ );
377
419
  });
378
420
  if (optionList.length > 0) {
379
421
  output = output.concat(['Options:', formatList(optionList), '']);
380
422
  }
381
423
 
382
424
  if (this.showGlobalOptions) {
383
- const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
384
- return formatItem(helper.optionTerm(option), helper.optionDescription(option));
385
- });
425
+ const globalOptionList = helper
426
+ .visibleGlobalOptions(cmd)
427
+ .map((option) => {
428
+ return formatItem(
429
+ helper.optionTerm(option),
430
+ helper.optionDescription(option),
431
+ );
432
+ });
386
433
  if (globalOptionList.length > 0) {
387
- output = output.concat(['Global Options:', formatList(globalOptionList), '']);
434
+ output = output.concat([
435
+ 'Global Options:',
436
+ formatList(globalOptionList),
437
+ '',
438
+ ]);
388
439
  }
389
440
  }
390
441
 
391
442
  // Commands
392
443
  const commandList = helper.visibleCommands(cmd).map((cmd) => {
393
- return formatItem(helper.subcommandTerm(cmd), helper.subcommandDescription(cmd));
444
+ return formatItem(
445
+ helper.subcommandTerm(cmd),
446
+ helper.subcommandDescription(cmd),
447
+ );
394
448
  });
395
449
  if (commandList.length > 0) {
396
450
  output = output.concat(['Commands:', formatList(commandList), '']);
@@ -412,7 +466,7 @@ class Help {
412
466
  helper.longestOptionTermLength(cmd, helper),
413
467
  helper.longestGlobalOptionTermLength(cmd, helper),
414
468
  helper.longestSubcommandTermLength(cmd, helper),
415
- helper.longestArgumentTermLength(cmd, helper)
469
+ helper.longestArgumentTermLength(cmd, helper),
416
470
  );
417
471
  }
418
472
 
@@ -430,7 +484,8 @@ class Help {
430
484
 
431
485
  wrap(str, width, indent, minColumnWidth = 40) {
432
486
  // Full \s characters, minus the linefeeds.
433
- const indents = ' \\f\\t\\v\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff';
487
+ const indents =
488
+ ' \\f\\t\\v\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff';
434
489
  // Detect manually wrapped and indented strings by searching for line break followed by spaces.
435
490
  const manualIndent = new RegExp(`[\\n][${indents}]+`);
436
491
  if (str.match(manualIndent)) return str;
@@ -445,12 +500,20 @@ class Help {
445
500
  const breaks = `\\s${zeroWidthSpace}`;
446
501
  // Match line end (so empty lines don't collapse),
447
502
  // or as much text as will fit in column, or excess text up to first break.
448
- const regex = new RegExp(`\n|.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`, 'g');
503
+ const regex = new RegExp(
504
+ `\n|.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`,
505
+ 'g',
506
+ );
449
507
  const lines = columnText.match(regex) || [];
450
- return leadingStr + lines.map((line, i) => {
451
- if (line === '\n') return ''; // preserve empty lines
452
- return ((i > 0) ? indentString : '') + line.trimEnd();
453
- }).join('\n');
508
+ return (
509
+ leadingStr +
510
+ lines
511
+ .map((line, i) => {
512
+ if (line === '\n') return ''; // preserve empty lines
513
+ return (i > 0 ? indentString : '') + line.trimEnd();
514
+ })
515
+ .join('\n')
516
+ );
454
517
  }
455
518
  }
456
519
 
package/lib/option.js CHANGED
@@ -93,7 +93,7 @@ class Option {
93
93
  * .addOption(new Option('--log', 'write logging information to file'))
94
94
  * .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' }));
95
95
  *
96
- * @param {Object} impliedOptionValues
96
+ * @param {object} impliedOptionValues
97
97
  * @return {Option}
98
98
  */
99
99
  implies(impliedOptionValues) {
@@ -158,7 +158,7 @@ class Option {
158
158
  }
159
159
 
160
160
  /**
161
- * @package internal use only
161
+ * @package
162
162
  */
163
163
 
164
164
  _concatValue(value, previous) {
@@ -180,7 +180,9 @@ class Option {
180
180
  this.argChoices = values.slice();
181
181
  this.parseArg = (arg, previous) => {
182
182
  if (!this.argChoices.includes(arg)) {
183
- throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(', ')}.`);
183
+ throw new InvalidArgumentError(
184
+ `Allowed choices are ${this.argChoices.join(', ')}.`,
185
+ );
184
186
  }
185
187
  if (this.variadic) {
186
188
  return this._concatValue(arg, previous);
@@ -219,7 +221,7 @@ class Option {
219
221
  *
220
222
  * @param {string} arg
221
223
  * @return {boolean}
222
- * @package internal use only
224
+ * @package
223
225
  */
224
226
 
225
227
  is(arg) {
@@ -232,7 +234,7 @@ class Option {
232
234
  * Options are one of boolean, negated, required argument, or optional argument.
233
235
  *
234
236
  * @return {boolean}
235
- * @package internal use only
237
+ * @package
236
238
  */
237
239
 
238
240
  isBoolean() {
@@ -255,7 +257,7 @@ class DualOptions {
255
257
  this.positiveOptions = new Map();
256
258
  this.negativeOptions = new Map();
257
259
  this.dualOptions = new Set();
258
- options.forEach(option => {
260
+ options.forEach((option) => {
259
261
  if (option.negate) {
260
262
  this.negativeOptions.set(option.attributeName(), option);
261
263
  } else {
@@ -282,7 +284,7 @@ class DualOptions {
282
284
 
283
285
  // Use the value to deduce if (probably) came from the option.
284
286
  const preset = this.negativeOptions.get(optionKey).presetArg;
285
- const negativeValue = (preset !== undefined) ? preset : false;
287
+ const negativeValue = preset !== undefined ? preset : false;
286
288
  return option.negate === (negativeValue === value);
287
289
  }
288
290
  }
@@ -313,7 +315,8 @@ function splitOptionFlags(flags) {
313
315
  // Use original very loose parsing to maintain backwards compatibility for now,
314
316
  // which allowed for example unintended `-sw, --short-word` [sic].
315
317
  const flagParts = flags.split(/[ |,]+/);
316
- if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1])) shortFlag = flagParts.shift();
318
+ if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1]))
319
+ shortFlag = flagParts.shift();
317
320
  longFlag = flagParts.shift();
318
321
  // Add support for lone short flag without significantly changing parsing!
319
322
  if (!shortFlag && /^-[^-]$/.test(longFlag)) {
@@ -6,7 +6,8 @@ function editDistance(a, b) {
6
6
  // (Simple implementation.)
7
7
 
8
8
  // Quick early exit, return worst case.
9
- if (Math.abs(a.length - b.length) > maxDistance) return Math.max(a.length, b.length);
9
+ if (Math.abs(a.length - b.length) > maxDistance)
10
+ return Math.max(a.length, b.length);
10
11
 
11
12
  // distance between prefix substrings of a and b
12
13
  const d = [];
@@ -32,7 +33,7 @@ function editDistance(a, b) {
32
33
  d[i][j] = Math.min(
33
34
  d[i - 1][j] + 1, // deletion
34
35
  d[i][j - 1] + 1, // insertion
35
- d[i - 1][j - 1] + cost // substitution
36
+ d[i - 1][j - 1] + cost, // substitution
36
37
  );
37
38
  // transposition
38
39
  if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
@@ -60,7 +61,7 @@ function suggestSimilar(word, candidates) {
60
61
  const searchingOptions = word.startsWith('--');
61
62
  if (searchingOptions) {
62
63
  word = word.slice(2);
63
- candidates = candidates.map(candidate => candidate.slice(2));
64
+ candidates = candidates.map((candidate) => candidate.slice(2));
64
65
  }
65
66
 
66
67
  let similar = [];
@@ -85,7 +86,7 @@ function suggestSimilar(word, candidates) {
85
86
 
86
87
  similar.sort((a, b) => a.localeCompare(b));
87
88
  if (searchingOptions) {
88
- similar = similar.map(candidate => `--${candidate}`);
89
+ similar = similar.map((candidate) => `--${candidate}`);
89
90
  }
90
91
 
91
92
  if (similar.length > 1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commander",
3
- "version": "12.0.0",
3
+ "version": "12.1.0",
4
4
  "description": "the complete solution for node.js command-line programs",
5
5
  "keywords": [
6
6
  "commander",
@@ -19,14 +19,18 @@
19
19
  "url": "git+https://github.com/tj/commander.js.git"
20
20
  },
21
21
  "scripts": {
22
- "lint": "npm run lint:javascript && npm run lint:typescript",
23
- "lint:javascript": "eslint index.js esm.mjs \"lib/*.js\" \"tests/**/*.js\"",
24
- "lint:typescript": "eslint typings/*.ts tests/*.ts",
25
- "test": "jest && npm run typecheck-ts",
26
- "test-esm": "node ./tests/esm-imports-test.mjs",
27
- "typecheck-ts": "tsd && tsc -p tsconfig.ts.json",
28
- "typecheck-js": "tsc -p tsconfig.js.json",
29
- "test-all": "npm run test && npm run lint && npm run typecheck-js && npm run test-esm"
22
+ "check": "npm run check:type && npm run check:lint && npm run check:format",
23
+ "check:format": "prettier --check .",
24
+ "check:lint": "eslint .",
25
+ "check:type": "npm run check:type:js && npm run check:type:ts",
26
+ "check:type:ts": "tsd && tsc -p tsconfig.ts.json",
27
+ "check:type:js": "tsc -p tsconfig.js.json",
28
+ "fix": "npm run fix:lint && npm run fix:format",
29
+ "fix:format": "prettier --write .",
30
+ "fix:lint": "eslint --fix .",
31
+ "test": "jest && npm run check:type:ts",
32
+ "test-all": "jest && npm run test-esm && npm run check",
33
+ "test-esm": "node ./tests/esm-imports-test.mjs"
30
34
  },
31
35
  "files": [
32
36
  "index.js",
@@ -56,21 +60,21 @@
56
60
  }
57
61
  },
58
62
  "devDependencies": {
63
+ "@eslint/js": "^8.56.0",
59
64
  "@types/jest": "^29.2.4",
60
65
  "@types/node": "^20.2.5",
61
- "@typescript-eslint/eslint-plugin": "^6.7.5",
62
- "@typescript-eslint/parser": "^6.7.5",
63
66
  "eslint": "^8.30.0",
64
- "eslint-config-standard": "^17.0.0",
65
- "eslint-config-standard-with-typescript": "^40.0.0",
66
- "eslint-plugin-import": "^2.26.0",
67
- "eslint-plugin-jest": "^27.1.7",
68
- "eslint-plugin-n": "^16.2.0",
69
- "eslint-plugin-promise": "^6.1.1",
67
+ "eslint-config-prettier": "^9.1.0",
68
+ "eslint-plugin-jest": "^28.3.0",
69
+ "eslint-plugin-jsdoc": "^48.1.0",
70
+ "globals": "^13.24.0",
70
71
  "jest": "^29.3.1",
72
+ "prettier": "^3.2.5",
73
+ "prettier-plugin-jsdoc": "^1.3.0",
71
74
  "ts-jest": "^29.0.3",
72
- "tsd": "^0.30.4",
73
- "typescript": "^5.0.4"
75
+ "tsd": "^0.31.0",
76
+ "typescript": "^5.0.4",
77
+ "typescript-eslint": "^7.0.1"
74
78
  },
75
79
  "types": "typings/index.d.ts",
76
80
  "engines": {