Skip to content

Commit

Permalink
feat!: add name prop
Browse files Browse the repository at this point in the history
BREAKING CHANGE: log renamed to logAndExit
  • Loading branch information
uetchy committed Mar 26, 2021
1 parent e24ca90 commit 5ed18a9
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 37 deletions.
66 changes: 39 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ yarn add epicfail
## Use

```js
import epicfail from 'epicfail'
import epicfail from 'epicfail';

epicfail()
epicfail();

// your CLI app code goes here
fs.readFileSync('foo') // => will cause "ENOENT: no such file or directory, open 'foo'"
fs.readFileSync('foo'); // => will cause "ENOENT: no such file or directory, open 'foo'"
```

![With stacktrace](https://raw.githubusercontent.com/uetchy/epicfail/master/docs/full.png)
Expand All @@ -70,11 +70,11 @@ fs.readFileSync('foo') // => will cause "ENOENT: no such file or directory, open
Show stack trace.

```js
import epicfail from 'epicfail'
import epicfail from 'epicfail';

epicfail({
stacktrace: false,
})
});
```

![Without stacktrace](https://raw.githubusercontent.com/uetchy/epicfail/master/docs/without-stacktrace.png)
Expand All @@ -84,11 +84,11 @@ epicfail({
Search and show related issues in GitHub Issues.

```js
import epicfail from 'epicfail'
import epicfail from 'epicfail';

epicfail({
issues: true,
})
});
```

![With issues](https://raw.githubusercontent.com/uetchy/epicfail/master/docs/with-issues.png)
Expand All @@ -98,15 +98,15 @@ epicfail({
Show environment information. You can find all possible options [here](https://github.com/tabrindle/envinfo#cli-usage). Set to `false` to disable it.

```js
import epicfail from 'epicfail'
import epicfail from 'epicfail';

epicfail({
env: {
System: ['OS', 'CPU'],
Binaries: ['Node', 'Yarn', 'npm'],
Utilities: ['Git'],
},
})
});
```

Default values:
Expand All @@ -125,75 +125,87 @@ Default values:
Show bug tracker URL and ask users to report the error.

```js
import epicfail from 'epicfail'
import epicfail from 'epicfail';

epicfail({ message: false })
epicfail({ message: false });
```

### assertExpected (default: `() => false`)

While processing an error, if `assertExpected(error)` returns `true`, epicfail just prints the error message without any extra information; which is the same behaviour as the `log()` function described below.
While processing an error, if `assertExpected(error)` returns `true`, epicfail just prints the error message without any extra information; which is the same behaviour as the `logAndExit()` function described below.

```js
import epicfail from 'epicfail'
import epicfail from 'epicfail';

epicfail({
assertExpected: (err) => err.name === 'ArgumentError',
})
});
```

### onError (default: `undefined`)

Pass the function that process the error and returns event id issued by external error aggregation service.

```js
import epicfail from 'epicfail'
import Sentry from '@sentry/node'
import epicfail from 'epicfail';
import Sentry from '@sentry/node';

epicfail({
onError: (err) => Sentry.captureException(err), // will returns an event id issued by Sentry
})
});
```

## Advanced Usage

### Print error message without extra information

Use `log()` to print error message in red text without any extra information (stack trace, environments, etc), then quit program. It is useful when you just want to show the expected error message without messing STDOUT around with verbose log messages.
Use `logAndExit()` to print error message in red text without any extra information (stack trace, environments, etc), then quit program. It is useful when you just want to show the expected error message without messing STDOUT around with verbose log messages.

```js
import epicfail, { log } from 'epicfail'
import epicfail, { logAndExit } from 'epicfail';

epicfail()
epicfail();

function cli(args) {
if (args.length === 0) {
log('usage: myapp <input>')
logAndExit('usage: myapp <input>');
}
}

cli(process.argv.slice(2))
cli(process.argv.slice(2));
```

You can also pass an Error instance:

```js
function cli(args) {
try {
someFunction();
} catch (err) {
logAndExit(err);
}
}
```

### Sentry integration

```js
import epicfail from 'epicfail'
import Sentry from '@sentry/node'
import epicfail from 'epicfail';
import Sentry from '@sentry/node';

epicfail({
stacktrace: false,
env: false,
onError: Sentry.captureException, // will returns event_id issued by Sentry
})
});

Sentry.init({
dsn: '<your sentry token here>',
defaultIntegrations: false, // required
})
});

// your CLI app code goes here
fs.readFileSync('foo') // => will cause "ENOENT: no such file or directory, open 'foo'"
fs.readFileSync('foo'); // => will cause "ENOENT: no such file or directory, open 'foo'"
```

![Sentry integration](https://raw.githubusercontent.com/uetchy/epicfail/master/docs/with-sentry.png)
Expand Down
30 changes: 22 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ export type EventID = string;
type MaybePromise<T> = T | Promise<T>;

export interface EpicfailOption {
name?: string;
message?: boolean;
stacktrace?: boolean;
issues?: boolean;
message?: boolean;
env?: Partial<EnvInfo> | false;
onError?: (err: Error, ...rest: any[]) => EventID | undefined;
assertExpected?: (err: Error) => MaybePromise<boolean>;
Expand All @@ -23,26 +24,39 @@ export class EpicfailError extends Error {

constructor(message?: string, option: EpicfailOption = {}) {
super(message);

if (option.name) this.name = option.name;

this.epicfail = option;
}
}

export function fail(message?: Error | string, Option: EpicfailOption = {}) {
export function fail(
message?: Error | string,
Option: EpicfailOption = {}
): never {
throw new EpicfailError(
message instanceof Error ? message.message : message,
Option
);
}

export function log(
export function logAndExit(
message?: Error | string,
option: EpicfailOption = { stacktrace: false, message: false, env: false }
) {
fail(message, option);
option: EpicfailOption = {}
): never {
fail(message, {
...{ stacktrace: false, message: false, env: false },
...option,
});
}

export default function handleErrors(cliFlags: EpicfailOption = {}) {
const pkgPath = getModulePackagePath(module.parent!.filename);
if (!module.parent) {
// couldn't handle errors
return;
}
const pkgPath = getModulePackagePath(module.parent.filename);
if (!pkgPath) throw new Error('Could not find package.json for the module.');

const handleError = async (
Expand All @@ -63,7 +77,7 @@ export default function handleErrors(cliFlags: EpicfailOption = {}) {
} = { ...cliFlags, ...(err.epicfail ?? {}) };

if (await Promise.resolve(assertExpected(err))) {
return log(err);
return logAndExit(err);
}

const stash = new Stash();
Expand Down
5 changes: 5 additions & 0 deletions tests/logAndExit/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import epicfail, { logAndExit } from '../../dist';

epicfail();

logAndExit('nailed', { name: 'NiceError' });
17 changes: 17 additions & 0 deletions tests/logAndExit/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import execa from 'execa';
import { join } from 'path';
import strip from 'strip-ansi';

let res: execa.ExecaReturnValue;

describe('logAndExit', () => {
beforeAll(async () => {
const runnable = join(__dirname, 'cli.js');
res = await execa('node', ['-r', 'esm', runnable]);
});

it('with title', () => {
expect(strip(res.stdout)).toEqual(`# NiceError
nailed`);
});
});
6 changes: 6 additions & 0 deletions tests/logAndExit/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "test",
"version": "1.0.0",
"main": "cli.js",
"bugs": "https://github.com/uetchy/simple/issues"
}
4 changes: 2 additions & 2 deletions tests/typescript/cli.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import handleErrors, { log } from '../..';
import handleErrors, { logAndExit } from '../..';

handleErrors();

log('Test');
logAndExit('Test');

0 comments on commit 5ed18a9

Please sign in to comment.