generated from ehmicky/template-javascript
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.ts
More file actions
104 lines (90 loc) · 2.58 KB
/
main.ts
File metadata and controls
104 lines (90 loc) · 2.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import beautifulError from 'beautiful-error'
import handleCliError, {
validateOptions,
type Options as HandleCliErrorOptions,
} from 'handle-cli-error'
import type { ErrorInstance, Info, Plugin } from 'modern-errors'
/**
* Options of `modern-errors-cli`
*/
export type Options = Omit<HandleCliErrorOptions, 'classes' | 'custom'>
// `error.pretty()` is called with `errorString` as argument by
// `beautiful-error`. We ignore that argument and prevent it from being
// considered an invalid options object.
const isOptions = (options: unknown) => typeof options !== 'string'
const getOptions = (options: Options = {}) => {
validateOptions(options)
if (options.classes !== undefined) {
throw new TypeError('The "classes" option must not be defined.')
}
if (options.custom !== undefined) {
throw new TypeError('The "custom" option must not be defined.')
}
return { ...options, custom: 'pretty' }
}
/**
* Logs `error` on the console (`stderr`) then exits the process.
*
* This never throws. Invalid errors are silently
* [normalized](https://github.com/ehmicky/normalize-exception).
*
* @example
* ```js
* const cliMain = () => {
* try {
* // ...
* } catch (error) {
* // Logs `error` then exits the process
* BaseError.exit(error)
* }
* }
*
* cliMain()
* ```
*/
const exit = ({ error, options }: Info<Options>['instanceMethods']) => {
removePretty(error)
try {
handleCliError(error, options)
} finally {
restorePretty(error)
}
}
// Uses `.pretty()` to avoid conflict with `modern-errors-beautiful`.
// Temporarily unsets `error.pretty()` to avoid recursion.
// This is a workaround to support nested errors and is not documented.
const pretty = ({
error,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options: { exitCode, silent, timeout, log, ...beautifulErrorOptions },
}: Info<Options>['instanceMethods']) => {
removePretty(error)
try {
return beautifulError(error, beautifulErrorOptions)
} finally {
restorePretty(error)
}
}
const removePretty = (error: ErrorInstance) => {
// eslint-disable-next-line fp/no-mutating-methods
Object.defineProperty(error, 'pretty', {
value: undefined,
enumerable: false,
writable: true,
configurable: true,
})
}
const restorePretty = (error: ErrorInstance & { pretty?: undefined }) => {
// eslint-disable-next-line fp/no-delete
delete error.pretty
}
/**
* `modern-errors-cli` plugin
*/
const modernErrorsCli = {
name: 'cli' as const,
isOptions,
getOptions,
instanceMethods: { exit, pretty },
} satisfies Plugin
export default modernErrorsCli