Skip to content

Commit 0c4cd0f

Browse files
authored
fix: use native ES2022 error cause (#5010)
This improves error messages and stack traces. For example: Before: ``` Error at new SubprocessError (.../dist/index.js:41:23) at ChildProcess.<anonymous> (.../dist/index.js:125:27) at ChildProcess.emit (node:events:513:28) at maybeClose (node:internal/child_process:1100:16) at Process.ChildProcess._handle.onexit (node:internal/child_process:304:5) ``` After: ``` SubprocessError: Signal exit from subprocess. at ChildProcess.<anonymous> (.../dist/index.js:122:27) at ChildProcess.emit (node:events:513:28) at maybeClose (node:internal/child_process:1100:16) at Process.ChildProcess._handle.onexit (node:internal/child_process:304:5) { code: 'ERR_SUBPROCESS_SIGNAL_EXIT', signal: 'SIGTERM' } ```
1 parent 9326871 commit 0c4cd0f

File tree

5 files changed

+10
-37
lines changed

5 files changed

+10
-37
lines changed

packages/@ionic/cli-framework/src/errors.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as lodash from 'lodash';
21
import * as util from 'util';
32

43
import { ValidationError } from './definitions';
@@ -10,25 +9,11 @@ export const ERROR_IPC_UNKNOWN_PROCEDURE = 'ERR_ICF_IPC_UNKNOWN_PROCEDURE';
109

1110
export abstract class BaseError extends Error {
1211
abstract readonly name: string;
13-
message: string;
14-
stack: string;
1512
code?: string;
16-
error?: Error;
1713
exitCode?: number;
1814

19-
constructor(message: string) {
20-
super(message);
21-
this.message = message;
22-
this.stack = (new Error()).stack || '';
23-
}
24-
2515
toString(): string {
26-
const repr = lodash.pick(this, lodash.pull(lodash.keys(this), 'error'));
27-
28-
return (
29-
`${this.name}: ${this.message} ${util.inspect(repr, { breakLength: Infinity })} ${this.stack} ` +
30-
`${this.error ? `\nWrapped: ${this.error.stack ? this.error.stack : this.error}` : ''}`
31-
);
16+
return util.inspect(this);
3217
}
3318

3419
inspect(): string {

packages/@ionic/cli/src/index.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { readPackageJsonFile } from '@ionic/cli-framework/utils/node';
33
import { processExit } from '@ionic/utils-process';
44
import * as Debug from 'debug';
55
import * as path from 'path';
6+
import * as util from 'util';
67

78
import { IonicNamespace } from './commands';
89
import { IPCMessage, IonicContext, IonicEnvironment } from './definitions';
@@ -171,11 +172,7 @@ export async function run(pargv: string[]): Promise<void> {
171172
} else if (err instanceof BaseError) {
172173
ienv.log.error(err.message);
173174
} else {
174-
ienv.log.msg(failure(String(err.stack ? err.stack : err)));
175-
176-
if (err.stack) {
177-
debug(failure(String(err.stack)));
178-
}
175+
ienv.log.rawmsg(failure(util.inspect(err)));
179176
}
180177
}
181178
}

packages/@ionic/cli/src/lib/project/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ export class ProjectDetailsError extends BaseException {
5555
/**
5656
* The underlying error that caused this error.
5757
*/
58-
readonly error?: Error
58+
cause?: Error
5959
) {
60-
super(msg);
60+
super(msg, { cause });
6161
}
6262
}
6363

@@ -193,7 +193,7 @@ export class ProjectDetails {
193193
if (e1) {
194194
log.error(
195195
`Error while loading config (project config: ${strong(prettyPath(result.configPath))})\n` +
196-
`${e1.error ? `${e1.message}: ${failure(e1.error.toString())}` : failure(e1.message)}. ` +
196+
`${e1.cause ? `${e1.message}: ${failure(e1.cause.toString())}` : failure(e1.message)}. ` +
197197
`Run ${input('ionic init')} to re-initialize your Ionic project. Without a valid project config, the CLI will not have project context.`
198198
);
199199

packages/@ionic/utils-subprocess/src/index.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,11 @@ export function convertPATH(path = process.env.PATH || ''): string {
3535

3636
export class SubprocessError extends Error {
3737
readonly name = 'SubprocessError';
38-
message: string;
39-
stack: string;
4038

4139
code?: typeof ERROR_COMMAND_NOT_FOUND | typeof ERROR_NON_ZERO_EXIT | typeof ERROR_SIGNAL_EXIT;
42-
error?: Error;
4340
output?: string;
4441
signal?: string;
4542
exitCode?: number;
46-
47-
constructor(message: string) {
48-
super(message);
49-
this.message = message;
50-
this.stack = (new Error()).stack || '';
51-
}
5243
}
5344

5445
export interface SubprocessOptions extends SpawnOptions {}
@@ -172,13 +163,12 @@ export class Subprocess {
172163
let err: SubprocessError;
173164

174165
if (error.code === 'ENOENT') {
175-
err = new SubprocessError('Command not found.');
166+
err = new SubprocessError('Command not found.', { cause: error });
176167
err.code = ERROR_COMMAND_NOT_FOUND;
177168
} else {
178-
err = new SubprocessError('Command error.');
169+
err = new SubprocessError('Command error.', { cause: error });
179170
}
180171

181-
err.error = error;
182172
reject(err);
183173
});
184174

tsconfig.base.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"target": "ES2021",
1313
"types": [],
1414
"lib": [
15-
"ES2021"
15+
"ES2021",
16+
"ES2022.Error"
1617
]
1718
}
1819
}

0 commit comments

Comments
 (0)