@hg-ts/exception 0.5.17 → 0.5.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/src/consts.ts +1 -0
- package/src/exception.factory.ts +41 -0
- package/src/exceptions/aggregate-error.exception.ts +26 -0
- package/src/exceptions/base.aggregate.exception.ts +51 -0
- package/src/exceptions/base.exception.ts +139 -0
- package/src/exceptions/error.exception.ts +16 -0
- package/src/exceptions/forbidden.exception.ts +3 -0
- package/src/exceptions/index.ts +12 -0
- package/src/exceptions/invalid-input.exception.ts +3 -0
- package/src/exceptions/not-implemented.exception.ts +7 -0
- package/src/exceptions/unknown.exception.ts +7 -0
- package/src/exceptions/will-never-happened.exception.ts +7 -0
- package/src/index.ts +2 -0
- package/src/tests/serialization.test.ts +120 -0
- package/src/tests/test.aggregate-exception.ts +16 -0
- package/src/tests/test.exception.ts +7 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/stack-trace.formatter.ts +30 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hg-ts/exception",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.19",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"test:dev": "vitest watch"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@hg-ts-config/typescript": "0.5.
|
|
22
|
-
"@hg-ts/linter": "0.5.
|
|
23
|
-
"@hg-ts/tests": "0.5.
|
|
24
|
-
"@hg-ts/types": "0.5.
|
|
21
|
+
"@hg-ts-config/typescript": "0.5.19",
|
|
22
|
+
"@hg-ts/linter": "0.5.19",
|
|
23
|
+
"@hg-ts/tests": "0.5.19",
|
|
24
|
+
"@hg-ts/types": "0.5.19",
|
|
25
25
|
"@types/node": "22.19.1",
|
|
26
26
|
"@vitest/coverage-v8": "4.0.14",
|
|
27
27
|
"eslint": "9.18.0",
|
package/src/consts.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SOURCE_MAP_ENABLED = !!(new Error().stack?.includes('->'));
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AggregateErrorException,
|
|
3
|
+
BaseException,
|
|
4
|
+
ErrorException,
|
|
5
|
+
ForbiddenException,
|
|
6
|
+
InvalidInputException,
|
|
7
|
+
JSONBaseException,
|
|
8
|
+
NotImplementedException,
|
|
9
|
+
UnknownException,
|
|
10
|
+
WillNeverHappenedException,
|
|
11
|
+
} from './exceptions/index.js';
|
|
12
|
+
|
|
13
|
+
export class ExceptionFactory {
|
|
14
|
+
private constructor() {}
|
|
15
|
+
|
|
16
|
+
public static fromJson<T extends JSONBaseException>(json: T, ctorList: Class<BaseException, any[]>[]): BaseException {
|
|
17
|
+
const ctorToMap = [
|
|
18
|
+
...ctorList,
|
|
19
|
+
AggregateErrorException,
|
|
20
|
+
ErrorException,
|
|
21
|
+
ForbiddenException,
|
|
22
|
+
InvalidInputException,
|
|
23
|
+
NotImplementedException,
|
|
24
|
+
UnknownException,
|
|
25
|
+
WillNeverHappenedException,
|
|
26
|
+
];
|
|
27
|
+
for (const ctor of ctorToMap) {
|
|
28
|
+
const { name, ...exceptionData } = json;
|
|
29
|
+
if (ctor.name === name) {
|
|
30
|
+
const exception = Object.create(ctor.prototype);
|
|
31
|
+
|
|
32
|
+
Object.assign(exception, exceptionData);
|
|
33
|
+
Object.assign(exception, { serialized: json });
|
|
34
|
+
|
|
35
|
+
return exception;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
throw new InvalidInputException(`Exception constructor with name "${json.name}" not passed`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { BaseAggregateException } from './base.aggregate.exception.js';
|
|
2
|
+
import { BaseException } from './base.exception.js';
|
|
3
|
+
|
|
4
|
+
export class AggregateErrorException extends BaseAggregateException {
|
|
5
|
+
public constructor(error: AggregateError) {
|
|
6
|
+
const { errors } = error;
|
|
7
|
+
|
|
8
|
+
super(
|
|
9
|
+
errors
|
|
10
|
+
.map(error => {
|
|
11
|
+
if (error instanceof AggregateError) {
|
|
12
|
+
BaseAggregateException.fromError(error);
|
|
13
|
+
}
|
|
14
|
+
if (error instanceof Error) {
|
|
15
|
+
return BaseException.fromError(error);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return null;
|
|
19
|
+
})
|
|
20
|
+
.filter((exception): exception is BaseException => exception !== null),
|
|
21
|
+
error.message,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
(this as any).stack = error.stack;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { AggregateErrorException } from './aggregate-error.exception.js';
|
|
2
|
+
import {
|
|
3
|
+
BaseException,
|
|
4
|
+
ExceptionOptions,
|
|
5
|
+
JSONBaseException,
|
|
6
|
+
PAD_COUNT_PER_DEPTH,
|
|
7
|
+
} from './base.exception.js';
|
|
8
|
+
|
|
9
|
+
export type JSONBaseAggregateException = Omit<JSONBaseException, 'cause'> & {
|
|
10
|
+
exceptions: JSONBaseException[];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type BaseAggregateExceptionOptions = Omit<ExceptionOptions, 'cause'>;
|
|
14
|
+
|
|
15
|
+
export abstract class BaseAggregateException extends BaseException {
|
|
16
|
+
public readonly exceptions: BaseException[];
|
|
17
|
+
|
|
18
|
+
protected constructor(
|
|
19
|
+
exceptions: BaseException[],
|
|
20
|
+
message: string,
|
|
21
|
+
options?: BaseAggregateExceptionOptions,
|
|
22
|
+
) {
|
|
23
|
+
super(message, options);
|
|
24
|
+
|
|
25
|
+
this.exceptions = exceptions;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public override toJSON(): JSONBaseAggregateException {
|
|
29
|
+
const baseJson = super.toJSON();
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
...baseJson,
|
|
33
|
+
exceptions: this.exceptions.map(exception => exception.toJSON()),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public static override fromError(error: AggregateError): BaseAggregateException {
|
|
38
|
+
return new AggregateErrorException(error);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
protected override injectBeforeStack(padCount: number): string[] {
|
|
42
|
+
const innerExceptionsInfo = this.exceptions
|
|
43
|
+
.map(exception => exception['getStringifyFirstLine']())
|
|
44
|
+
.map(line => BaseException.padLine(line, padCount));
|
|
45
|
+
|
|
46
|
+
return [
|
|
47
|
+
BaseException.padLine('Aggregated exceptions info:', padCount - PAD_COUNT_PER_DEPTH),
|
|
48
|
+
...innerExceptionsInfo,
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import * as os from 'os';
|
|
2
|
+
import {
|
|
3
|
+
inspect,
|
|
4
|
+
InspectOptionsStylized,
|
|
5
|
+
} from 'util';
|
|
6
|
+
|
|
7
|
+
import { StackTraceFormatter } from '../utils/index.js';
|
|
8
|
+
import { ErrorException } from './error.exception.js';
|
|
9
|
+
|
|
10
|
+
export type JSONBaseException = {
|
|
11
|
+
name: string;
|
|
12
|
+
code: Nullable<number>;
|
|
13
|
+
message: string;
|
|
14
|
+
stack: string[];
|
|
15
|
+
cause?: JSONBaseException;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type ExceptionOptions = {
|
|
19
|
+
cause?: BaseException | undefined;
|
|
20
|
+
code?: number | undefined;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const PAD_COUNT_PER_DEPTH = 4;
|
|
24
|
+
|
|
25
|
+
export abstract class BaseException extends Error {
|
|
26
|
+
public readonly code: Nullable<number> = null;
|
|
27
|
+
public override readonly stack: string;
|
|
28
|
+
public override readonly message: string;
|
|
29
|
+
public override readonly cause?: BaseException;
|
|
30
|
+
private serialized: Nullable<JSONBaseException> = null;
|
|
31
|
+
|
|
32
|
+
public constructor(message: string, codeOrOptions: ExceptionOptions = {}) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.message = message;
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
if (codeOrOptions.cause) {
|
|
38
|
+
this.cause = codeOrOptions.cause;
|
|
39
|
+
}
|
|
40
|
+
if (codeOrOptions.code) {
|
|
41
|
+
this.code = codeOrOptions.code;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Error.captureStackTrace(this, this.getCtor());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public override get name(): string {
|
|
48
|
+
const { name } = this.getCtor();
|
|
49
|
+
|
|
50
|
+
return name;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public toJSON(): JSONBaseException {
|
|
54
|
+
if (this.serialized === null) {
|
|
55
|
+
const { name, message, stack, code, cause } = this;
|
|
56
|
+
|
|
57
|
+
this.serialized = {
|
|
58
|
+
name,
|
|
59
|
+
code,
|
|
60
|
+
message,
|
|
61
|
+
stack: StackTraceFormatter.format(stack, this.name),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
if (cause) {
|
|
65
|
+
this.serialized.cause = cause.toJSON();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return this.serialized;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public override toString(padCount = PAD_COUNT_PER_DEPTH): string {
|
|
73
|
+
const { stack } = this.toJSON();
|
|
74
|
+
const formattedStack = stack.map(line => BaseException.padLine(line, padCount));
|
|
75
|
+
|
|
76
|
+
const errorLines = [
|
|
77
|
+
this.getStringifyFirstLine(),
|
|
78
|
+
...this.injectBeforeStack(padCount + PAD_COUNT_PER_DEPTH),
|
|
79
|
+
...formattedStack,
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
return errorLines.join(os.EOL);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// eslint-disable-next-line @typescript/unbound-method
|
|
86
|
+
public [inspect.custom](_depth: Nullable<number>, { stylize }: InspectOptionsStylized): string {
|
|
87
|
+
return stylize(this.toString(), 'regexp');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public isFromNextTick(): boolean {
|
|
91
|
+
const lastLine = this.getLastStackLine();
|
|
92
|
+
|
|
93
|
+
return lastLine.includes('processTicksAndRejections');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public isFromImmediate(): boolean {
|
|
97
|
+
const lastLine = this.getLastStackLine();
|
|
98
|
+
|
|
99
|
+
return lastLine.includes('Immediate._onImmediate');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public isFromTimer(): boolean {
|
|
103
|
+
const lastLine = this.getLastStackLine();
|
|
104
|
+
|
|
105
|
+
return lastLine.includes('Timeout._onTimeout');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public static fromError(error: Error): BaseException {
|
|
109
|
+
return new ErrorException(error);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
protected getCtor(): Function {
|
|
113
|
+
return Object.getPrototypeOf(this)!.constructor;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
protected getStringifyFirstLine(): string {
|
|
117
|
+
const { name, code, message } = this.toJSON();
|
|
118
|
+
|
|
119
|
+
return `${name}${code === null ? '' : ` [code: ${code}]`}: ${message}`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
protected injectBeforeStack(padCount: number): string[] {
|
|
123
|
+
if (this.cause) {
|
|
124
|
+
return [BaseException.padLine(this.cause.getStringifyFirstLine(), padCount)];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
protected static padLine(line: string, padCount: number): string {
|
|
131
|
+
return `${' '.repeat(padCount)}${line}`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private getLastStackLine(): string {
|
|
135
|
+
const { stack } = this.toJSON();
|
|
136
|
+
|
|
137
|
+
return stack[stack.length - 1] ?? '';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseException } from './base.exception.js';
|
|
2
|
+
|
|
3
|
+
export class ErrorException extends BaseException {
|
|
4
|
+
public constructor(error: Error) {
|
|
5
|
+
const { cause } = error as any;
|
|
6
|
+
|
|
7
|
+
super(error.message, {
|
|
8
|
+
cause: cause instanceof Error
|
|
9
|
+
? new ErrorException(cause)
|
|
10
|
+
// eslint-disable-next-line no-undefined
|
|
11
|
+
: undefined,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
(this as any).stack = error.stack;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Error exceptions must be imported before base exceptions because of cyclical imports
|
|
2
|
+
export * from './error.exception.js';
|
|
3
|
+
export * from './aggregate-error.exception.js';
|
|
4
|
+
|
|
5
|
+
export * from './base.exception.js';
|
|
6
|
+
export * from './base.aggregate.exception.js';
|
|
7
|
+
|
|
8
|
+
export * from './unknown.exception.js';
|
|
9
|
+
export * from './not-implemented.exception.js';
|
|
10
|
+
export * from './will-never-happened.exception.js';
|
|
11
|
+
export * from './forbidden.exception.js';
|
|
12
|
+
export * from './invalid-input.exception.js';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Describe,
|
|
3
|
+
expect,
|
|
4
|
+
Suite,
|
|
5
|
+
Test,
|
|
6
|
+
} from '@hg-ts/tests';
|
|
7
|
+
import {
|
|
8
|
+
BaseAggregateException,
|
|
9
|
+
BaseException,
|
|
10
|
+
ErrorException,
|
|
11
|
+
} from '../exceptions/index.js';
|
|
12
|
+
import { TestAggregateException } from './test.aggregate-exception.js';
|
|
13
|
+
import { TestException } from './test.exception.js';
|
|
14
|
+
|
|
15
|
+
@Describe()
|
|
16
|
+
export class SerializationTestSuite extends Suite {
|
|
17
|
+
@Test()
|
|
18
|
+
public async commonTest(): Promise<void> {
|
|
19
|
+
const message = 'Test message';
|
|
20
|
+
const exception = new TestException(message);
|
|
21
|
+
|
|
22
|
+
expect(exception).toBeInstanceOf(Error);
|
|
23
|
+
expect(exception).toBeInstanceOf(BaseException);
|
|
24
|
+
expect(exception).toBeInstanceOf(TestException);
|
|
25
|
+
expect(exception.message).toEqual(message);
|
|
26
|
+
expect(exception.code).toBeNull();
|
|
27
|
+
expect(exception.toJSON().name).toEqual(TestException.name);
|
|
28
|
+
expect(exception.toJSON().stack).toBeInstanceOf(Array);
|
|
29
|
+
expect(exception.toJSON().stack).not.toEqual([]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Test()
|
|
33
|
+
public async baseExceptionFromError(): Promise<void> {
|
|
34
|
+
const message = 'Test message';
|
|
35
|
+
const error = new Error(message);
|
|
36
|
+
const exception = BaseException.fromError(error);
|
|
37
|
+
|
|
38
|
+
expect(exception).toBeInstanceOf(Error);
|
|
39
|
+
expect(exception).toBeInstanceOf(BaseException);
|
|
40
|
+
expect(exception).toBeInstanceOf(ErrorException);
|
|
41
|
+
expect(exception.message).toEqual(message);
|
|
42
|
+
expect(exception.code).toBeNull();
|
|
43
|
+
expect(exception.toJSON().stack).toBeInstanceOf(Array);
|
|
44
|
+
expect(exception.toJSON().stack).not.toEqual([]);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@Test()
|
|
48
|
+
public async aggregateExceptionTest(): Promise<void> {
|
|
49
|
+
const message = 'Test aggregate message';
|
|
50
|
+
const exception = new TestAggregateException(message);
|
|
51
|
+
|
|
52
|
+
expect(exception).toBeInstanceOf(Error);
|
|
53
|
+
expect(exception).toBeInstanceOf(BaseException);
|
|
54
|
+
expect(exception).toBeInstanceOf(BaseAggregateException);
|
|
55
|
+
expect(exception).toBeInstanceOf(TestAggregateException);
|
|
56
|
+
|
|
57
|
+
expect(exception.message).toEqual(message);
|
|
58
|
+
expect(exception.code).toBeNull();
|
|
59
|
+
|
|
60
|
+
expect(exception.exceptions).toBeInstanceOf(Array);
|
|
61
|
+
expect(exception.exceptions).toHaveLength(3);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@Test()
|
|
65
|
+
public async syncStackTest(): Promise<void> {
|
|
66
|
+
const { stack } = new TestException('Test message').toJSON();
|
|
67
|
+
|
|
68
|
+
expect(stack[0]!.startsWith(`at ${this.constructor.name}.syncStackTest`)).toBeTruthy();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@Test()
|
|
72
|
+
public async isFromNextTickTest(): Promise<void> {
|
|
73
|
+
return new Promise<void>(resolve => {
|
|
74
|
+
process.nextTick(() => {
|
|
75
|
+
const exception = new TestException('Test message');
|
|
76
|
+
|
|
77
|
+
expect(exception.isFromNextTick()).toBeTruthy();
|
|
78
|
+
resolve();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@Test()
|
|
84
|
+
public async isFromImmediateTest(): Promise<void> {
|
|
85
|
+
return new Promise<void>(resolve => {
|
|
86
|
+
setImmediate(() => {
|
|
87
|
+
const exception = new TestException('Test message');
|
|
88
|
+
|
|
89
|
+
expect(exception.isFromImmediate()).toBeTruthy();
|
|
90
|
+
resolve();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@Test()
|
|
96
|
+
public async fromTimeoutTest(): Promise<void> {
|
|
97
|
+
return new Promise<void>(resolve => {
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
const exception = new TestException('Test message');
|
|
100
|
+
|
|
101
|
+
expect(exception.isFromTimer()).toBeTruthy();
|
|
102
|
+
resolve();
|
|
103
|
+
}, 0);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@Test()
|
|
108
|
+
public async fromIntervalTest(): Promise<void> {
|
|
109
|
+
let interval: NodeJS.Timeout;
|
|
110
|
+
return new Promise<void>(resolve => {
|
|
111
|
+
interval = setInterval(() => {
|
|
112
|
+
const exception = new TestException('Test message');
|
|
113
|
+
|
|
114
|
+
expect(exception.isFromTimer()).toBeTruthy();
|
|
115
|
+
clearInterval(interval);
|
|
116
|
+
resolve();
|
|
117
|
+
}, 0);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseAggregateException } from '../exceptions/index.js';
|
|
2
|
+
import { TestException } from './test.exception.js';
|
|
3
|
+
|
|
4
|
+
export class TestAggregateException extends BaseAggregateException {
|
|
5
|
+
public constructor(message: string, code?: number) {
|
|
6
|
+
super(
|
|
7
|
+
[
|
|
8
|
+
new TestException('First inner exception'),
|
|
9
|
+
new TestException('Second inner exception'),
|
|
10
|
+
new TestException('Third inner exception'),
|
|
11
|
+
],
|
|
12
|
+
message,
|
|
13
|
+
{ code },
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './stack-trace.formatter.js';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import os from 'os';
|
|
2
|
+
import { SOURCE_MAP_ENABLED } from '../consts.js';
|
|
3
|
+
|
|
4
|
+
export class StackTraceFormatter {
|
|
5
|
+
public static format(stack: string, exceptionName: string): string[] {
|
|
6
|
+
return StackTraceFormatter.getStackLines(stack, exceptionName);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
protected static getStackLines(stack: string, exceptionName: string): string[] {
|
|
10
|
+
let lines = stack.split(os.EOL)
|
|
11
|
+
.splice(1)
|
|
12
|
+
.filter(stackLine => !StackTraceFormatter.isInternalStackLine(stackLine))
|
|
13
|
+
.map(line => line.trim());
|
|
14
|
+
|
|
15
|
+
if (SOURCE_MAP_ENABLED) {
|
|
16
|
+
lines = lines.slice(4);
|
|
17
|
+
}
|
|
18
|
+
const lineFromExceptionConstructor = lines.findIndex(line => line.startsWith(`at new ${exceptionName}`));
|
|
19
|
+
|
|
20
|
+
if (lineFromExceptionConstructor > -1) {
|
|
21
|
+
return lines.slice(lineFromExceptionConstructor + 1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return lines;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
protected static isInternalStackLine(line: string): boolean {
|
|
28
|
+
return line.includes('internal/') && !line.includes('processTicksAndRejections');
|
|
29
|
+
}
|
|
30
|
+
}
|