Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: do not print errors returned from yargs #300

Merged
merged 1 commit into from
Sep 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ intuitive to work with.
- [Getting started](#getting-started)
- [Installation](#installation)
- [Simple example](#simple-example)
- [Error handling](#error-handling)
- [REPL example](#repl-example)
- [Prompt](#prompt)
- [TypeScript](#typescript)
Expand Down Expand Up @@ -124,6 +125,58 @@ Options:
_ℹ You see `bin.js` here instead of `foo.ts` because we're running the program
with `ts-node`._

### Error handling

We first create a new program called `cat.ts` which is a simple version of the
`cat` program we all know:

```ts
import { readFileSync } from 'fs'
import { program, command } from 'bandersnatch'

const cat = command('cat')
.description('Concatenate files')
.argument('files', { variadic: true })
.action(({ files }) =>
console.log(
files.reduce((str, file) => str + readFileSync(file, 'utf8'), '')
)
)

program().default(cat).run()
```

Now try your program by running it:

```
$ ts-node cat.ts somefile
contents of somefile
```

However, when `somefile` doesn't exist, we get are faced with an ugly unhandled
promise rejection warning/error (depending on the Node.js version you're using).

Let's fix that:

```diff
-program().default(cat).run()
+program()
+ .default(cat)
+ .run()
+ .catch((err) => {
+ console.error(`There was a problem running this command:\n${String(err)}`)
+ process.exit(1)
+ })
```

Which will yield:

```
$ ts-node cat.ts somefile
There was a problem running this command:
Error: ENOENT: no such file or directory, open 'somefile'
```

### REPL example

A program can also show an interactive
Expand Down
19 changes: 19 additions & 0 deletions examples/cat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { readFileSync } from 'fs'
import { command, program } from '../src'

const cat = command('cat')
.description('Concatenate files')
.argument('files', { variadic: true })
.action(({ files }) =>
console.log(
files.reduce((str, file) => str + readFileSync(file, 'utf8'), '')
)
)

program()
.default(cat)
.run()
.catch((err) => {
console.error(`There was a problem running this command:\n${String(err)}`)
process.exit(1)
})
2 changes: 1 addition & 1 deletion examples/errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { program, command } from '../src'
import { command, program } from '../src'

const app = program()

Expand Down
14 changes: 10 additions & 4 deletions src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ type ProgramOptions = {

/**
* Specifies whether to add a default behaviour for an `exit` command.
*
*
* Takes a boolean or a function argument:
* - `false` installs no handler
* - `true` will install the default handler
* - a given function will be installed as the handler
*
*
* Defaults to `() => process.exit()`.
*/
exit?: boolean | (() => void)
Expand Down Expand Up @@ -99,7 +99,10 @@ export class Program extends (EventEmitter as new () => TypedEventEmitter<Events
}

// Set default exit handler
if (this.options.exit === true || typeof this.options.exit === 'undefined') {
if (
this.options.exit === true ||
typeof this.options.exit === 'undefined'
) {
this.options.exit = () => process.exit()
}

Expand Down Expand Up @@ -217,9 +220,12 @@ export class Program extends (EventEmitter as new () => TypedEventEmitter<Events
* From the yargs docs:
* > Populated if any validation errors raised while parsing.
* http://yargs.js.org/docs/#api-parseargs-context-parsecallback
* This seems to be incorrect though, and err is populated when any
* error is thrown inside the command handler.
*/
if (err) {
console.error(err)
// Ignore err value, which encourages users to deliberately handle
// error conditions in their programs.
}

if (isPromise(argv.__promise)) {
Expand Down