Skip to content

Commit d83e253

Browse files
aduh95danielleadams
authored andcommitted
errors: refactor to use more primordials
PR-URL: #35944 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ben Coe <bencoe@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
1 parent b700900 commit d83e253

File tree

2 files changed

+79
-50
lines changed

2 files changed

+79
-50
lines changed

lib/internal/errors.js

+65-40
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,49 @@
1111
// message may change, the code should not.
1212

1313
const {
14+
ArrayFrom,
1415
ArrayIsArray,
16+
ArrayPrototypeIncludes,
17+
ArrayPrototypeIndexOf,
18+
ArrayPrototypeJoin,
19+
ArrayPrototypeMap,
20+
ArrayPrototypePop,
21+
ArrayPrototypePush,
22+
ArrayPrototypeSlice,
23+
ArrayPrototypeSplice,
24+
ArrayPrototypeUnshift,
1525
Error,
1626
ErrorCaptureStackTrace,
1727
ErrorPrototypeToString,
1828
JSONStringify,
19-
Map,
2029
MathAbs,
2130
MathMax,
31+
Number,
2232
NumberIsInteger,
2333
ObjectDefineProperty,
2434
ObjectKeys,
2535
RangeError,
36+
ReflectApply,
37+
RegExpPrototypeTest,
38+
SafeMap,
39+
SafeWeakMap,
2640
String,
41+
StringPrototypeEndsWith,
42+
StringPrototypeIncludes,
43+
StringPrototypeSlice,
44+
StringPrototypeSplit,
2745
StringPrototypeStartsWith,
46+
StringPrototypeToLowerCase,
2847
Symbol,
2948
SymbolFor,
3049
SyntaxError,
3150
TypeError,
3251
URIError,
33-
WeakMap,
3452
} = primordials;
3553

3654
const isWindows = process.platform === 'win32';
3755

38-
const messages = new Map();
56+
const messages = new SafeMap();
3957
const codes = {};
4058

4159
const classRegExp = /^([A-Z][a-z0-9]*)+$/;
@@ -54,7 +72,7 @@ const kTypes = [
5472
];
5573

5674
const MainContextError = Error;
57-
const overrideStackTrace = new WeakMap();
75+
const overrideStackTrace = new SafeWeakMap();
5876
const kNoOverride = Symbol('kNoOverride');
5977
const prepareStackTrace = (globalThis, error, trace) => {
6078
// API for node internals to override error stack formatting
@@ -370,8 +388,8 @@ function getMessage(key, args, self) {
370388
if (args.length === 0)
371389
return msg;
372390

373-
args.unshift(msg);
374-
return lazyInternalUtilInspect().format.apply(null, args);
391+
ArrayPrototypeUnshift(args, msg);
392+
return ReflectApply(lazyInternalUtilInspect().format, null, args);
375393
}
376394

377395
let uvBinding;
@@ -644,9 +662,9 @@ function addNumericalSeparator(val) {
644662
let i = val.length;
645663
const start = val[0] === '-' ? 1 : 0;
646664
for (; i >= start + 4; i -= 3) {
647-
res = `_${val.slice(i - 3, i)}${res}`;
665+
res = `_${StringPrototypeSlice(val, i - 3, i)}${res}`;
648666
}
649-
return `${val.slice(0, i)}${res}`;
667+
return `${StringPrototypeSlice(val, 0, i)}${res}`;
650668
}
651669

652670
// Used to enhance the stack that will be picked up by the inspector
@@ -681,7 +699,8 @@ const fatalExceptionStackEnhancers = {
681699
// ANSI escape sequences is not reliable.
682700
if (process.platform === 'win32') {
683701
const info = internalBinding('os').getOSInformation();
684-
const ver = info[2].split('.').map((a) => +a);
702+
const ver = ArrayPrototypeMap(StringPrototypeSplit(info[2], '.'),
703+
Number);
685704
if (ver[0] !== 10 || ver[2] < 14393) {
686705
useColors = false;
687706
}
@@ -975,11 +994,11 @@ E('ERR_INVALID_ARG_TYPE',
975994
}
976995

977996
let msg = 'The ';
978-
if (name.endsWith(' argument')) {
997+
if (StringPrototypeEndsWith(name, ' argument')) {
979998
// For cases like 'first argument'
980999
msg += `${name} `;
9811000
} else {
982-
const type = name.includes('.') ? 'property' : 'argument';
1001+
const type = StringPrototypeIncludes(name, '.') ? 'property' : 'argument';
9831002
msg += `"${name}" ${type} `;
9841003
}
9851004
msg += 'must be ';
@@ -991,31 +1010,31 @@ E('ERR_INVALID_ARG_TYPE',
9911010
for (const value of expected) {
9921011
assert(typeof value === 'string',
9931012
'All expected entries have to be of type string');
994-
if (kTypes.includes(value)) {
995-
types.push(value.toLowerCase());
996-
} else if (classRegExp.test(value)) {
997-
instances.push(value);
1013+
if (ArrayPrototypeIncludes(kTypes, value)) {
1014+
ArrayPrototypePush(types, StringPrototypeToLowerCase(value));
1015+
} else if (RegExpPrototypeTest(classRegExp, value)) {
1016+
ArrayPrototypePush(instances, value);
9981017
} else {
9991018
assert(value !== 'object',
10001019
'The value "object" should be written as "Object"');
1001-
other.push(value);
1020+
ArrayPrototypePush(other, value);
10021021
}
10031022
}
10041023

10051024
// Special handle `object` in case other instances are allowed to outline
10061025
// the differences between each other.
10071026
if (instances.length > 0) {
1008-
const pos = types.indexOf('object');
1027+
const pos = ArrayPrototypeIndexOf(types, 'object');
10091028
if (pos !== -1) {
1010-
types.splice(pos, 1);
1011-
instances.push('Object');
1029+
ArrayPrototypeSplice(types, pos, 1);
1030+
ArrayPrototypePush(instances, 'Object');
10121031
}
10131032
}
10141033

10151034
if (types.length > 0) {
10161035
if (types.length > 2) {
1017-
const last = types.pop();
1018-
msg += `one of type ${types.join(', ')}, or ${last}`;
1036+
const last = ArrayPrototypePop(types);
1037+
msg += `one of type ${ArrayPrototypeJoin(types, ', ')}, or ${last}`;
10191038
} else if (types.length === 2) {
10201039
msg += `one of type ${types[0]} or ${types[1]}`;
10211040
} else {
@@ -1027,8 +1046,9 @@ E('ERR_INVALID_ARG_TYPE',
10271046

10281047
if (instances.length > 0) {
10291048
if (instances.length > 2) {
1030-
const last = instances.pop();
1031-
msg += `an instance of ${instances.join(', ')}, or ${last}`;
1049+
const last = ArrayPrototypePop(instances);
1050+
msg +=
1051+
`an instance of ${ArrayPrototypeJoin(instances, ', ')}, or ${last}`;
10321052
} else {
10331053
msg += `an instance of ${instances[0]}`;
10341054
if (instances.length === 2) {
@@ -1041,12 +1061,12 @@ E('ERR_INVALID_ARG_TYPE',
10411061

10421062
if (other.length > 0) {
10431063
if (other.length > 2) {
1044-
const last = other.pop();
1045-
msg += `one of ${other.join(', ')}, or ${last}`;
1064+
const last = ArrayPrototypePop(other);
1065+
msg += `one of ${ArrayPrototypeJoin(other, ', ')}, or ${last}`;
10461066
} else if (other.length === 2) {
10471067
msg += `one of ${other[0]} or ${other[1]}`;
10481068
} else {
1049-
if (other[0].toLowerCase() !== other[0])
1069+
if (StringPrototypeToLowerCase(other[0]) !== other[0])
10501070
msg += 'an ';
10511071
msg += `${other[0]}`;
10521072
}
@@ -1068,17 +1088,17 @@ E('ERR_INVALID_ARG_TYPE',
10681088
let inspected = lazyInternalUtilInspect()
10691089
.inspect(actual, { colors: false });
10701090
if (inspected.length > 25)
1071-
inspected = `${inspected.slice(0, 25)}...`;
1091+
inspected = `${StringPrototypeSlice(inspected, 0, 25)}...`;
10721092
msg += `. Received type ${typeof actual} (${inspected})`;
10731093
}
10741094
return msg;
10751095
}, TypeError);
10761096
E('ERR_INVALID_ARG_VALUE', (name, value, reason = 'is invalid') => {
10771097
let inspected = lazyInternalUtilInspect().inspect(value);
10781098
if (inspected.length > 128) {
1079-
inspected = `${inspected.slice(0, 128)}...`;
1099+
inspected = `${StringPrototypeSlice(inspected, 0, 128)}...`;
10801100
}
1081-
const type = name.includes('.') ? 'property' : 'argument';
1101+
const type = StringPrototypeIncludes(name, '.') ? 'property' : 'argument';
10821102
return `The ${type} '${name}' ${reason}. Received ${inspected}`;
10831103
}, TypeError, RangeError);
10841104
E('ERR_INVALID_ASYNC_ID', 'Invalid %s value: %s', RangeError);
@@ -1195,9 +1215,10 @@ E('ERR_MANIFEST_ASSERT_INTEGRITY',
11951215
moduleURL
11961216
}" does not match the expected integrity.`;
11971217
if (realIntegrities.size) {
1198-
const sri = [...realIntegrities.entries()].map(([alg, dgs]) => {
1199-
return `${alg}-${dgs}`;
1200-
}).join(' ');
1218+
const sri = ArrayPrototypeJoin(
1219+
ArrayFrom(realIntegrities.entries(), ([alg, dgs]) => `${alg}-${dgs}`),
1220+
' '
1221+
);
12011222
msg += ` Integrities found are: ${sri}`;
12021223
} else {
12031224
msg += ' The resource was not found in the policy.';
@@ -1225,8 +1246,11 @@ E('ERR_MISSING_ARGS',
12251246
let msg = 'The ';
12261247
const len = args.length;
12271248
const wrap = (a) => `"${a}"`;
1228-
args = args.map(
1229-
(a) => (ArrayIsArray(a) ? a.map(wrap).join(' or ') : wrap(a))
1249+
args = ArrayPrototypeMap(
1250+
args,
1251+
(a) => (ArrayIsArray(a) ?
1252+
ArrayPrototypeJoin(ArrayPrototypeMap(a, wrap), ' or ') :
1253+
wrap(a))
12301254
);
12311255
switch (len) {
12321256
case 1:
@@ -1236,7 +1260,7 @@ E('ERR_MISSING_ARGS',
12361260
msg += `${args[0]} and ${args[1]} arguments`;
12371261
break;
12381262
default:
1239-
msg += args.slice(0, len - 1).join(', ');
1263+
msg += ArrayPrototypeJoin(ArrayPrototypeSlice(args, 0, len - 1), ', ');
12401264
msg += `, and ${args[len - 1]} arguments`;
12411265
break;
12421266
}
@@ -1299,9 +1323,10 @@ E('ERR_QUIC_INVALID_TLS_SESSION_TICKET',
12991323
'Invalid TLS session ticket', Error);
13001324
E('ERR_QUIC_VERSION_NEGOTIATION',
13011325
(version, requestedVersions, supportedVersions) => {
1326+
const requestedVersionsString = ArrayPrototypeJoin(requestedVersions, ', ');
13021327
return 'QUIC session received version negotiation from server. ' +
1303-
`Version: ${version}. Requested: ${requestedVersions.join(', ')} ` +
1304-
`Supported: ${supportedVersions.join(', ')}`;
1328+
`Version: ${version}. Requested: ${requestedVersionsString} ` +
1329+
`Supported: ${ArrayPrototypeJoin(supportedVersions, ', ')}`;
13051330
},
13061331
Error);
13071332
E('ERR_REQUIRE_ESM',
@@ -1447,18 +1472,18 @@ E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
14471472
E('ERR_WASI_ALREADY_STARTED', 'WASI instance has already started', Error);
14481473
E('ERR_WORKER_INIT_FAILED', 'Worker initialization failure: %s', Error);
14491474
E('ERR_WORKER_INVALID_EXEC_ARGV', (errors, msg = 'invalid execArgv flags') =>
1450-
`Initiated Worker with ${msg}: ${errors.join(', ')}`,
1475+
`Initiated Worker with ${msg}: ${ArrayPrototypeJoin(errors, ', ')}`,
14511476
Error);
14521477
E('ERR_WORKER_NOT_RUNNING', 'Worker instance not running', Error);
14531478
E('ERR_WORKER_OUT_OF_MEMORY',
14541479
'Worker terminated due to reaching memory limit: %s', Error);
14551480
E('ERR_WORKER_PATH', (filename) =>
14561481
'The worker script or module filename must be an absolute path or a ' +
14571482
'relative path starting with \'./\' or \'../\'.' +
1458-
(filename.startsWith('file://') ?
1483+
(StringPrototypeStartsWith(filename, 'file://') ?
14591484
' Wrap file:// URLs with `new URL`.' : ''
14601485
) +
1461-
(filename.startsWith('data:text/javascript') ?
1486+
(StringPrototypeStartsWith(filename, 'data:text/javascript') ?
14621487
' Wrap data: URLs with `new URL`.' : ''
14631488
) +
14641489
` Received "${filename}"`,

lib/internal/source_map/prepare_stack_trace.js

+14-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22

33
const {
44
ArrayPrototypeIndexOf,
5-
Error,
5+
ArrayPrototypeJoin,
6+
ArrayPrototypeMap,
7+
ErrorPrototypeToString,
8+
StringPrototypeRepeat,
9+
StringPrototypeSlice,
10+
StringPrototypeSplit,
611
StringPrototypeStartsWith,
712
} = primordials;
813

@@ -21,7 +26,6 @@ const { fileURLToPath } = require('internal/url');
2126

2227
// Create a prettified stacktrace, inserting context from source maps
2328
// if possible.
24-
const ErrorToString = Error.prototype.toString; // Capture original toString.
2529
const prepareStackTrace = (globalThis, error, trace) => {
2630
// API for node internals to override error stack formatting
2731
// without interfering with userland code.
@@ -36,7 +40,7 @@ const prepareStackTrace = (globalThis, error, trace) => {
3640
maybeOverridePrepareStackTrace(globalThis, error, trace);
3741
if (globalOverride !== kNoOverride) return globalOverride;
3842

39-
const errorString = ErrorToString.call(error);
43+
const errorString = ErrorPrototypeToString(error);
4044

4145
if (trace.length === 0) {
4246
return errorString;
@@ -45,7 +49,7 @@ const prepareStackTrace = (globalThis, error, trace) => {
4549
let errorSource = '';
4650
let firstLine;
4751
let firstColumn;
48-
const preparedTrace = trace.map((t, i) => {
52+
const preparedTrace = ArrayPrototypeJoin(ArrayPrototypeMap(trace, (t, i) => {
4953
if (i === 0) {
5054
firstLine = t.getLineNumber();
5155
firstColumn = t.getColumnNumber();
@@ -88,8 +92,8 @@ const prepareStackTrace = (globalThis, error, trace) => {
8892
debug(err.stack);
8993
}
9094
return str;
91-
});
92-
return `${errorSource}${errorString}\n at ${preparedTrace.join('')}`;
95+
}), '');
96+
return `${errorSource}${errorString}\n at ${preparedTrace}`;
9397
};
9498

9599
// Places a snippet of code from where the exception was originally thrown
@@ -118,18 +122,18 @@ function getErrorSource(payload, originalSource, firstLine, firstColumn) {
118122
}
119123
}
120124

121-
const lines = source.split(/\r?\n/, firstLine);
125+
const lines = StringPrototypeSplit(source, /\r?\n/, firstLine);
122126
const line = lines[firstLine - 1];
123127
if (!line) return exceptionLine;
124128

125129
// Display ^ in appropriate position, regardless of whether tabs or
126130
// spaces are used:
127131
let prefix = '';
128-
for (const character of line.slice(0, firstColumn)) {
132+
for (const character of StringPrototypeSlice(line, 0, firstColumn)) {
129133
prefix += (character === '\t') ? '\t' :
130-
' '.repeat(getStringWidth(character));
134+
StringPrototypeRepeat(' ', getStringWidth(character));
131135
}
132-
prefix = prefix.slice(0, -1); // The last character is the '^'.
136+
prefix = StringPrototypeSlice(prefix, 0, -1); // The last character is '^'.
133137

134138
exceptionLine =
135139
`${originalSourceNoScheme}:${firstLine}\n${line}\n${prefix}^\n\n`;

0 commit comments

Comments
 (0)