1 | type PotentialError = Errlop | Error | ErrorCodeHolder | string
|
2 | interface ErrorCodeHolder {
|
3 | exitCode?: string | number
|
4 | errno?: string | number
|
5 | code?: string | number
|
6 | }
|
7 |
|
8 |
|
9 | function parseCode(code: any): number | null {
|
10 | const number = Number(code)
|
11 | if (isNaN(number)) return null
|
12 | return number
|
13 | }
|
14 |
|
15 |
|
16 | function fetchCode(value: any): string | number | null {
|
17 | return (
|
18 | value &&
|
19 | (parseCode(value.exitCode) ||
|
20 | parseCode(value.errno) ||
|
21 | parseCode(value.code))
|
22 | )
|
23 | }
|
24 |
|
25 |
|
26 | function isValid(value: any): boolean {
|
27 |
|
28 | return value instanceof Error || Errlop.isErrlop(value)
|
29 | }
|
30 |
|
31 | export default class Errlop extends Error {
|
32 |
|
33 | public klass: typeof Errlop
|
34 |
|
35 | |
36 |
|
37 |
|
38 |
|
39 | public parent?: Errlop | Error | null
|
40 |
|
41 |
|
42 | public ancestors: Array<Errlop | Error>
|
43 |
|
44 | |
45 |
|
46 |
|
47 |
|
48 | public exitCode?: string | number
|
49 |
|
50 | |
51 |
|
52 |
|
53 |
|
54 | public orphanStack: string
|
55 |
|
56 | |
57 |
|
58 |
|
59 |
|
60 | public stack: string
|
61 |
|
62 | |
63 |
|
64 |
|
65 |
|
66 | static create(
|
67 | input: PotentialError,
|
68 | parent: Errlop | Error | null = null
|
69 | ): Errlop {
|
70 | return new this(input, parent)
|
71 | }
|
72 |
|
73 | |
74 |
|
75 |
|
76 |
|
77 | constructor(input: PotentialError, parent: Errlop | Error | null = null) {
|
78 | if (!input) throw new Error('Attempted to create an Errlop without a input')
|
79 |
|
80 |
|
81 | super((input as any).message || input)
|
82 |
|
83 |
|
84 | this.klass = Errlop
|
85 | this.parent = parent || (input as Errlop).parent
|
86 | this.ancestors = []
|
87 | let ancestor = this.parent
|
88 | while (ancestor) {
|
89 | this.ancestors.push(ancestor)
|
90 | ancestor = (ancestor as Errlop).parent
|
91 | }
|
92 |
|
93 |
|
94 |
|
95 | let exitCode = fetchCode(input)
|
96 | if (exitCode == null) exitCode = fetchCode(this)
|
97 | for (
|
98 | let index = 0;
|
99 | index < this.ancestors.length && exitCode == null;
|
100 | ++index
|
101 | ) {
|
102 | const error = this.ancestors[index]
|
103 | if (isValid(error)) exitCode = fetchCode(error)
|
104 | }
|
105 |
|
106 |
|
107 | if (exitCode != null) {
|
108 | this.exitCode = exitCode
|
109 | }
|
110 | this.orphanStack = ((input as any).stack || (this as any).stack).toString()
|
111 | this.stack = this.ancestors.reduce<string>(
|
112 | (accumulator, error) =>
|
113 | `${accumulator}\n↳ ${
|
114 | (error as Errlop).orphanStack || (error as Error).stack || error
|
115 | }`,
|
116 | this.orphanStack
|
117 | )
|
118 | }
|
119 |
|
120 |
|
121 | static isErrlop(value: any): boolean {
|
122 | return value && (value instanceof this || value.klass === this)
|
123 | }
|
124 |
|
125 |
|
126 | static ensure(value: any): Errlop {
|
127 | return this.isErrlop(value) ? value : this.create(value)
|
128 | }
|
129 | }
|