command-line-interface
Advanced tools
Comparing version 3.2.2 to 3.3.0
import { Command } from './elements/Command'; | ||
declare const runCli: ({ rootCommand, argv }: { | ||
import { Handlers } from './Handlers'; | ||
declare const runCli: ({ rootCommand, argv, handlers }: { | ||
rootCommand: Command<any>; | ||
argv: string[]; | ||
handlers?: Partial<Handlers> | undefined; | ||
}) => Promise<void>; | ||
export { runCli }; |
@@ -7,3 +7,26 @@ "use strict"; | ||
const runCliRecursive_1 = require("./runCliRecursive"); | ||
const runCli = async function ({ rootCommand, argv }) { | ||
const runCli = async function ({ rootCommand, argv, handlers = {} }) { | ||
const handlersWithDefaults = { | ||
commandFailed({ ex }) { | ||
// eslint-disable-next-line no-console | ||
console.error(ex); | ||
}, | ||
commandUnknown({ unknownCommandName, recommendedCommandName }) { | ||
// eslint-disable-next-line no-console | ||
console.error(`Unknown command '${unknownCommandName}'. Did you mean '${recommendedCommandName}'?`); | ||
}, | ||
optionInvalid({ optionDefinition }) { | ||
// eslint-disable-next-line no-console | ||
console.error(`Option '${optionDefinition.name}' must be a ${optionDefinition.type}.`); | ||
}, | ||
optionMissing({ optionDefinition }) { | ||
// eslint-disable-next-line no-console | ||
console.error(`Option '${optionDefinition.name}' is missing.`); | ||
}, | ||
optionUnknown({ optionName }) { | ||
// eslint-disable-next-line no-console | ||
console.error(`Unknown option '${optionName}'.`); | ||
}, | ||
...handlers | ||
}; | ||
const extendedRootCommand = addHelpCommandToCli_1.addHelpCommandToCli({ rootCommand }); | ||
@@ -15,2 +38,3 @@ const recommendCommand = getRecommendCommand_1.getRecommendCommand({ rootCommand: extendedRootCommand }); | ||
argv, | ||
handlers: handlersWithDefaults, | ||
getUsage, | ||
@@ -17,0 +41,0 @@ recommendCommand, |
import { Command } from './elements/Command'; | ||
import { CommandPath } from './elements/CommandPath'; | ||
import { GetUsageFn } from './elements/GetUsageFn'; | ||
import { Handlers } from './Handlers'; | ||
import { RecommendCommandFn } from './elements/RecommendCommandFn'; | ||
declare const runCliRecursive: ({ command, argv, getUsage, recommendCommand, level, ancestorOptions, ancestorNames }: { | ||
declare const runCliRecursive: ({ command, argv, handlers, getUsage, recommendCommand, level, ancestorOptions, ancestorNames }: { | ||
command: Command<any>; | ||
argv: string[]; | ||
handlers: Handlers; | ||
getUsage: GetUsageFn; | ||
@@ -9,0 +11,0 @@ recommendCommand: RecommendCommandFn; |
@@ -11,3 +11,3 @@ "use strict"; | ||
const command_line_args_1 = __importDefault(require("command-line-args")); | ||
const runCliRecursive = async function ({ command, argv, getUsage, recommendCommand, level, ancestorOptions, ancestorNames }) { | ||
const runCliRecursive = async function ({ command, argv, handlers, getUsage, recommendCommand, level, ancestorOptions, ancestorNames }) { | ||
const commandPath = [...ancestorNames, command.name]; | ||
@@ -22,5 +22,4 @@ const optionDefinitions = command.optionDefinitions. | ||
if (options.help) { | ||
/* eslint-disable no-console */ | ||
// eslint-disable-next-line no-console | ||
console.log(getUsage({ commandPath })); | ||
/* eslint-enable no-console */ | ||
return; | ||
@@ -34,9 +33,9 @@ } | ||
case 'EOPTIONMISSING': | ||
handlers.optionMissing({ optionDefinition: ex.data.optionDefinition }); | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
return process.exit(1); | ||
case 'EOPTIONINVALID': { | ||
/* eslint-disable no-console */ | ||
console.error(ex.message); | ||
/* eslint-enable no-console */ | ||
/* eslint-disable unicorn/no-process-exit */ | ||
handlers.optionInvalid({ optionDefinition: ex.data.optionDefinition }); | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
return process.exit(1); | ||
/* eslint-enable unicorn/no-process-exit */ | ||
} | ||
@@ -62,8 +61,5 @@ default: { | ||
catch (ex) { | ||
/* eslint-disable no-console */ | ||
console.error(ex); | ||
/* eslint-enable no-console */ | ||
/* eslint-disable unicorn/no-process-exit */ | ||
handlers.commandFailed({ ex }); | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
return process.exit(1); | ||
/* eslint-enable unicorn/no-process-exit */ | ||
} | ||
@@ -73,8 +69,5 @@ } | ||
const unknowOption = _unknown[0]; | ||
/* eslint-disable no-console */ | ||
console.error(`Unknown option '${unknowOption}'.`); | ||
/* eslint-enable no-console */ | ||
/* eslint-disable unicorn/no-process-exit */ | ||
handlers.optionUnknown({ optionName: unknowOption }); | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
return process.exit(1); | ||
/* eslint-enable unicorn/no-process-exit */ | ||
} | ||
@@ -91,2 +84,3 @@ try { | ||
argv: subArgv, | ||
handlers, | ||
getUsage, | ||
@@ -102,10 +96,11 @@ recommendCommand, | ||
const recommendedCommand = recommendCommand({ commandPath: [...commandPath, unknownCommand] }); | ||
/* eslint-disable no-console */ | ||
console.error(`Unknown command '${unknownCommand}'. Did you mean '${recommendedCommand}'?`); | ||
/* eslint-enable no-console */ | ||
/* eslint-disable unicorn/no-process-exit */ | ||
handlers.commandUnknown({ | ||
unknownCommandName: unknownCommand, | ||
recommendedCommandName: recommendedCommand, | ||
ancestors: ancestorNames | ||
}); | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
process.exit(1); | ||
/* eslint-enable unicorn/no-process-exit */ | ||
} | ||
}; | ||
exports.runCliRecursive = runCliRecursive; |
@@ -13,3 +13,5 @@ "use strict"; | ||
if (optionRequired && value === undefined) { | ||
throw new errors_1.errors.OptionMissing(`Option '${optionDefinition.name}' is missing.`); | ||
throw new errors_1.errors.OptionMissing(`Option '${optionDefinition.name}' is missing.`, { | ||
data: { optionDefinition } | ||
}); | ||
} | ||
@@ -25,3 +27,5 @@ switch (optionDefinition.type) { | ||
if (typeof value !== 'number' || Number.isNaN(value)) { | ||
throw new errors_1.errors.OptionInvalid(`Option '${optionDefinition.name}' must be a number.`); | ||
throw new errors_1.errors.OptionInvalid(`Option '${optionDefinition.name}' must be a number.`, { | ||
data: { optionDefinition } | ||
}); | ||
} | ||
@@ -28,0 +32,0 @@ break; |
@@ -0,1 +1,8 @@ | ||
# [3.3.0](https://github.com/thenativeweb/command-line-interface/compare/3.2.2...3.3.0) (2020-02-10) | ||
### Features | ||
* Add custom error handlers. ([#30](https://github.com/thenativeweb/command-line-interface/issues/30)) ([1b3e5e7](https://github.com/thenativeweb/command-line-interface/commit/1b3e5e7bf26134643c7a94b1bf9cc33a1fc2d4e4)) | ||
## [3.2.2](https://github.com/thenativeweb/command-line-interface/compare/3.2.1...3.2.2) (2020-02-07) | ||
@@ -2,0 +9,0 @@ |
@@ -5,8 +5,34 @@ import { addHelpCommandToCli } from './addHelpCommandToCli'; | ||
import { getRecommendCommand } from './recommend/getRecommendCommand'; | ||
import { Handlers } from './Handlers'; | ||
import { runCliRecursive } from './runCliRecursive'; | ||
const runCli = async function ({ rootCommand, argv }: { | ||
const runCli = async function ({ rootCommand, argv, handlers = {}}: { | ||
rootCommand: Command<any>; | ||
argv: string[]; | ||
handlers?: Partial<Handlers>; | ||
}): Promise<void> { | ||
const handlersWithDefaults: Handlers = { | ||
commandFailed ({ ex }): void { | ||
// eslint-disable-next-line no-console | ||
console.error(ex); | ||
}, | ||
commandUnknown ({ unknownCommandName, recommendedCommandName }): void { | ||
// eslint-disable-next-line no-console | ||
console.error(`Unknown command '${unknownCommandName}'. Did you mean '${recommendedCommandName}'?`); | ||
}, | ||
optionInvalid ({ optionDefinition }): void { | ||
// eslint-disable-next-line no-console | ||
console.error(`Option '${optionDefinition.name}' must be a ${optionDefinition.type}.`); | ||
}, | ||
optionMissing ({ optionDefinition }): void { | ||
// eslint-disable-next-line no-console | ||
console.error(`Option '${optionDefinition.name}' is missing.`); | ||
}, | ||
optionUnknown ({ optionName }): void { | ||
// eslint-disable-next-line no-console | ||
console.error(`Unknown option '${optionName}'.`); | ||
}, | ||
...handlers | ||
}; | ||
const extendedRootCommand = addHelpCommandToCli({ rootCommand }); | ||
@@ -20,2 +46,3 @@ | ||
argv, | ||
handlers: handlersWithDefaults, | ||
getUsage, | ||
@@ -22,0 +49,0 @@ recommendCommand, |
@@ -6,2 +6,3 @@ import { Command } from './elements/Command'; | ||
import { GetUsageFn } from './elements/GetUsageFn'; | ||
import { Handlers } from './Handlers'; | ||
import { helpOption } from './commands/helpOption'; | ||
@@ -15,2 +16,3 @@ import { RecommendCommandFn } from './elements/RecommendCommandFn'; | ||
argv, | ||
handlers, | ||
getUsage, | ||
@@ -24,2 +26,3 @@ recommendCommand, | ||
argv: string[]; | ||
handlers: Handlers; | ||
getUsage: GetUsageFn; | ||
@@ -43,5 +46,4 @@ recommendCommand: RecommendCommandFn; | ||
if (options.help) { | ||
/* eslint-disable no-console */ | ||
// eslint-disable-next-line no-console | ||
console.log(getUsage({ commandPath })); | ||
/* eslint-enable no-console */ | ||
@@ -56,10 +58,11 @@ return; | ||
case 'EOPTIONMISSING': | ||
handlers.optionMissing({ optionDefinition: ex.data.optionDefinition }); | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
return process.exit(1); | ||
case 'EOPTIONINVALID': { | ||
/* eslint-disable no-console */ | ||
console.error(ex.message); | ||
/* eslint-enable no-console */ | ||
handlers.optionInvalid({ optionDefinition: ex.data.optionDefinition }); | ||
/* eslint-disable unicorn/no-process-exit */ | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
return process.exit(1); | ||
/* eslint-enable unicorn/no-process-exit */ | ||
} | ||
@@ -86,9 +89,6 @@ default: { | ||
} catch (ex) { | ||
/* eslint-disable no-console */ | ||
console.error(ex); | ||
/* eslint-enable no-console */ | ||
handlers.commandFailed({ ex }); | ||
/* eslint-disable unicorn/no-process-exit */ | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
return process.exit(1); | ||
/* eslint-enable unicorn/no-process-exit */ | ||
} | ||
@@ -100,9 +100,6 @@ } | ||
/* eslint-disable no-console */ | ||
console.error(`Unknown option '${unknowOption}'.`); | ||
/* eslint-enable no-console */ | ||
handlers.optionUnknown({ optionName: unknowOption }); | ||
/* eslint-disable unicorn/no-process-exit */ | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
return process.exit(1); | ||
/* eslint-enable unicorn/no-process-exit */ | ||
} | ||
@@ -125,2 +122,3 @@ | ||
argv: subArgv, | ||
handlers, | ||
getUsage, | ||
@@ -136,9 +134,10 @@ recommendCommand, | ||
/* eslint-disable no-console */ | ||
console.error(`Unknown command '${unknownCommand}'. Did you mean '${recommendedCommand}'?`); | ||
/* eslint-enable no-console */ | ||
handlers.commandUnknown({ | ||
unknownCommandName: unknownCommand, | ||
recommendedCommandName: recommendedCommand, | ||
ancestors: ancestorNames | ||
}); | ||
/* eslint-disable unicorn/no-process-exit */ | ||
// eslint-disable-next-line unicorn/no-process-exit | ||
process.exit(1); | ||
/* eslint-enable unicorn/no-process-exit */ | ||
} | ||
@@ -145,0 +144,0 @@ }; |
@@ -16,3 +16,5 @@ import { errors } from './errors'; | ||
if (optionRequired && value === undefined) { | ||
throw new errors.OptionMissing(`Option '${optionDefinition.name}' is missing.`); | ||
throw new errors.OptionMissing(`Option '${optionDefinition.name}' is missing.`, { | ||
data: { optionDefinition } | ||
}); | ||
} | ||
@@ -29,3 +31,5 @@ | ||
if (typeof value !== 'number' || Number.isNaN(value)) { | ||
throw new errors.OptionInvalid(`Option '${optionDefinition.name}' must be a number.`); | ||
throw new errors.OptionInvalid(`Option '${optionDefinition.name}' must be a number.`, { | ||
data: { optionDefinition } | ||
}); | ||
} | ||
@@ -32,0 +36,0 @@ break; |
{ | ||
"name": "command-line-interface", | ||
"version": "3.2.2", | ||
"version": "3.3.0", | ||
"description": "command-line-interface is a foundation for CLI applications.", | ||
@@ -5,0 +5,0 @@ "contributors": [ |
@@ -193,2 +193,36 @@ # command-line-interface | ||
### Customizing handling errors | ||
By default, command-line-interface takes care of handling any errors that occur. However, sometimes you may want to customize handling errors, e.g. to format them before displaying them. For that, hand over the optional `handlers` parameter to the `runCli` function, and provide functions for the error types you want to customize: | ||
```javascript | ||
await runCli({ | ||
rootCommand: hello, | ||
argv: process.argv, | ||
handlers: { | ||
commandFailed ({ ex }) { | ||
// ... | ||
}, | ||
commandUnknown ({ unknownCommandName, recommendedCommandName, ancestors }) { | ||
// ... | ||
}, | ||
optionInvalid ({ optionDefinition }) { | ||
// ... | ||
}, | ||
optionMissing ({ optionDefinition }) { | ||
// ... | ||
}, | ||
optionUnknown ({ optionName }) { | ||
// ... | ||
} | ||
} | ||
}); | ||
``` | ||
*Please note that if you do not provide all handlers, the remaining ones stick to the default behavior.* | ||
## Running the build | ||
@@ -195,0 +229,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
62357
85
1248
234