Skip to content

Commit 6a9f049

Browse files
committed
tools,lib: forbid native Error constructors
This adds a rule that forbids the use of native Error constructors in the `lib` directory. This is to encourage use of the `internal/errors` mechanism. The rule is disabled for errors that are not created with the `internal/errors` module but are still assigned an error code. PR-URL: #19373 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent ab8bf26 commit 6a9f049

File tree

16 files changed

+39
-0
lines changed

16 files changed

+39
-0
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ module.exports = {
148148
}
149149
],
150150
/* eslint-disable max-len, quotes */
151+
// If this list is modified, please copy the change to lib/.eslintrc.yaml
151152
'no-restricted-syntax': [
152153
'error',
153154
{

lib/.eslintrc.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
11
rules:
2+
no-restricted-syntax:
3+
# Config copied from .eslintrc.js
4+
- error
5+
- selector: "CallExpression[callee.object.name='assert'][callee.property.name='doesNotThrow']"
6+
message: "Please replace `assert.doesNotThrow()` and add a comment next to the code instead."
7+
- selector: "CallExpression[callee.object.name='assert'][callee.property.name='throws'][arguments.1.type='Literal']:not([arguments.1.regex])"
8+
message: "use a regular expression for second argument of assert.throws()"
9+
- selector: "CallExpression[callee.object.name='assert'][callee.property.name='throws'][arguments.length<2]"
10+
message: "assert.throws() must be invoked with at least two arguments."
11+
- selector: "CallExpression[callee.name='setTimeout'][arguments.length<2]"
12+
message: "setTimeout() must be invoked with at least two arguments."
13+
- selector: "CallExpression[callee.name='setInterval'][arguments.length<2]"
14+
message: "setInterval() must be invoked with at least 2 arguments."
15+
- selector: "ThrowStatement > CallExpression[callee.name=/Error$/]"
16+
message: "Use new keyword when throwing an Error."
17+
# Config specific to lib
18+
- selector: "NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError)$/])"
19+
message: "Use an error exported by the internal/errors module."
220
# Custom rules in tools/eslint-rules
321
node-core/require-buffer: error
422
node-core/buffer-constructor: error

lib/_http_client.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ function emitAbortNT() {
307307

308308

309309
function createHangUpError() {
310+
// eslint-disable-next-line no-restricted-syntax
310311
var error = new Error('socket hang up');
311312
error.code = 'ECONNRESET';
312313
return error;

lib/_tls_wrap.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ function onSocketClose(err) {
775775
// Emit ECONNRESET
776776
if (!this._controlReleased && !this[kErrorEmitted]) {
777777
this[kErrorEmitted] = true;
778+
// eslint-disable-next-line no-restricted-syntax
778779
const connReset = new Error('socket hang up');
779780
connReset.code = 'ECONNRESET';
780781
this._tlsOptions.server.emit('tlsClientError', connReset, this);
@@ -1103,6 +1104,7 @@ function onConnectEnd() {
11031104
if (!this._hadError) {
11041105
const options = this[kConnectOptions];
11051106
this._hadError = true;
1107+
// eslint-disable-next-line no-restricted-syntax
11061108
const error = new Error('Client network socket disconnected before ' +
11071109
'secure TLS connection was established');
11081110
error.code = 'ECONNRESET';

lib/assert.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ function innerOk(fn, argLen, value, message) {
216216
} else if (message == null) {
217217
// Use the call as error message if possible.
218218
// This does not work with e.g. the repl.
219+
// eslint-disable-next-line no-restricted-syntax
219220
const err = new Error();
220221
// Make sure the limit is set to 1. Otherwise it could fail (<= 0) or it
221222
// does to much work.

lib/buffer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,7 @@ if (process.binding('config').hasIntl) {
10731073
return result;
10741074

10751075
const code = icuErrName(result);
1076+
// eslint-disable-next-line no-restricted-syntax
10761077
const err = new Error(`Unable to transcode Buffer [${code}]`);
10771078
err.code = code;
10781079
err.errno = result;

lib/child_process.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ exports.execFile = function(file /*, args, options, callback*/) {
278278
cmd += ` ${args.join(' ')}`;
279279

280280
if (!ex) {
281+
// eslint-disable-next-line no-restricted-syntax
281282
ex = new Error('Command failed: ' + cmd + '\n' + stderr);
282283
ex.killed = child.killed || killed;
283284
ex.code = code < 0 ? getSystemErrorName(code) : code;
@@ -588,6 +589,7 @@ function checkExecSyncError(ret, args, cmd) {
588589
msg += cmd || args.join(' ');
589590
if (ret.stderr && ret.stderr.length > 0)
590591
msg += `\n${ret.stderr.toString()}`;
592+
// eslint-disable-next-line no-restricted-syntax
591593
err = new Error(msg);
592594
}
593595
if (err) {

lib/domain.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ if (process.hasUncaughtExceptionCaptureCallback()) {
8989
}
9090

9191
// Get the stack trace at the point where `domain` was required.
92+
// eslint-disable-next-line no-restricted-syntax
9293
const domainRequireStack = new Error('require(`domain`) at this point').stack;
9394

9495
const { setUncaughtExceptionCaptureCallback } = process;

lib/events.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ function _addListener(target, type, listener, prepend) {
240240
if (m && m > 0 && existing.length > m) {
241241
existing.warned = true;
242242
// No error code for this since it is a Warning
243+
// eslint-disable-next-line no-restricted-syntax
243244
const w = new Error('Possible EventEmitter memory leak detected. ' +
244245
`${existing.length} ${String(type)} listeners ` +
245246
'added. Use emitter.setMaxListeners() to ' +

lib/internal/bootstrap/loaders.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
// Model the error off the internal/errors.js model, but
128128
// do not use that module given that it could actually be
129129
// the one causing the error if there's a bug in Node.js
130+
// eslint-disable-next-line no-restricted-syntax
130131
const err = new Error(`No such built-in module: ${id}`);
131132
err.code = 'ERR_UNKNOWN_BUILTIN_MODULE';
132133
err.name = 'Error [ERR_UNKNOWN_BUILTIN_MODULE]';

0 commit comments

Comments
 (0)