Skip to content

Commit 7d7e34c

Browse files
aduh95targos
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 d678277 commit 7d7e34c

File tree

2 files changed

+77
-46
lines changed

2 files changed

+77
-46
lines changed

lib/internal/errors.js

+63-36
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
@@ -366,8 +384,8 @@ function getMessage(key, args, self) {
366384
if (args.length === 0)
367385
return msg;
368386

369-
args.unshift(msg);
370-
return lazyInternalUtilInspect().format.apply(null, args);
387+
ArrayPrototypeUnshift(args, msg);
388+
return ReflectApply(lazyInternalUtilInspect().format, null, args);
371389
}
372390

373391
let uvBinding;
@@ -640,9 +658,9 @@ function addNumericalSeparator(val) {
640658
let i = val.length;
641659
const start = val[0] === '-' ? 1 : 0;
642660
for (; i >= start + 4; i -= 3) {
643-
res = `_${val.slice(i - 3, i)}${res}`;
661+
res = `_${StringPrototypeSlice(val, i - 3, i)}${res}`;
644662
}
645-
return `${val.slice(0, i)}${res}`;
663+
return `${StringPrototypeSlice(val, 0, i)}${res}`;
646664
}
647665

648666
// Used to enhance the stack that will be picked up by the inspector
@@ -677,7 +695,8 @@ const fatalExceptionStackEnhancers = {
677695
// ANSI escape sequences is not reliable.
678696
if (process.platform === 'win32') {
679697
const info = internalBinding('os').getOSInformation();
680-
const ver = info[2].split('.').map((a) => +a);
698+
const ver = ArrayPrototypeMap(StringPrototypeSplit(info[2], '.'),
699+
Number);
681700
if (ver[0] !== 10 || ver[2] < 14393) {
682701
useColors = false;
683702
}
@@ -981,11 +1000,11 @@ E('ERR_INVALID_ARG_TYPE',
9811000
}
9821001

9831002
let msg = 'The ';
984-
if (name.endsWith(' argument')) {
1003+
if (StringPrototypeEndsWith(name, ' argument')) {
9851004
// For cases like 'first argument'
9861005
msg += `${name} `;
9871006
} else {
988-
const type = name.includes('.') ? 'property' : 'argument';
1007+
const type = StringPrototypeIncludes(name, '.') ? 'property' : 'argument';
9891008
msg += `"${name}" ${type} `;
9901009
}
9911010
msg += 'must be ';
@@ -997,31 +1016,31 @@ E('ERR_INVALID_ARG_TYPE',
9971016
for (const value of expected) {
9981017
assert(typeof value === 'string',
9991018
'All expected entries have to be of type string');
1000-
if (kTypes.includes(value)) {
1001-
types.push(value.toLowerCase());
1002-
} else if (classRegExp.test(value)) {
1003-
instances.push(value);
1019+
if (ArrayPrototypeIncludes(kTypes, value)) {
1020+
ArrayPrototypePush(types, StringPrototypeToLowerCase(value));
1021+
} else if (RegExpPrototypeTest(classRegExp, value)) {
1022+
ArrayPrototypePush(instances, value);
10041023
} else {
10051024
assert(value !== 'object',
10061025
'The value "object" should be written as "Object"');
1007-
other.push(value);
1026+
ArrayPrototypePush(other, value);
10081027
}
10091028
}
10101029

10111030
// Special handle `object` in case other instances are allowed to outline
10121031
// the differences between each other.
10131032
if (instances.length > 0) {
1014-
const pos = types.indexOf('object');
1033+
const pos = ArrayPrototypeIndexOf(types, 'object');
10151034
if (pos !== -1) {
1016-
types.splice(pos, 1);
1017-
instances.push('Object');
1035+
ArrayPrototypeSplice(types, pos, 1);
1036+
ArrayPrototypePush(instances, 'Object');
10181037
}
10191038
}
10201039

10211040
if (types.length > 0) {
10221041
if (types.length > 2) {
1023-
const last = types.pop();
1024-
msg += `one of type ${types.join(', ')}, or ${last}`;
1042+
const last = ArrayPrototypePop(types);
1043+
msg += `one of type ${ArrayPrototypeJoin(types, ', ')}, or ${last}`;
10251044
} else if (types.length === 2) {
10261045
msg += `one of type ${types[0]} or ${types[1]}`;
10271046
} else {
@@ -1033,8 +1052,9 @@ E('ERR_INVALID_ARG_TYPE',
10331052

10341053
if (instances.length > 0) {
10351054
if (instances.length > 2) {
1036-
const last = instances.pop();
1037-
msg += `an instance of ${instances.join(', ')}, or ${last}`;
1055+
const last = ArrayPrototypePop(instances);
1056+
msg +=
1057+
`an instance of ${ArrayPrototypeJoin(instances, ', ')}, or ${last}`;
10381058
} else {
10391059
msg += `an instance of ${instances[0]}`;
10401060
if (instances.length === 2) {
@@ -1047,12 +1067,12 @@ E('ERR_INVALID_ARG_TYPE',
10471067

10481068
if (other.length > 0) {
10491069
if (other.length > 2) {
1050-
const last = other.pop();
1051-
msg += `one of ${other.join(', ')}, or ${last}`;
1070+
const last = ArrayPrototypePop(other);
1071+
msg += `one of ${ArrayPrototypeJoin(other, ', ')}, or ${last}`;
10521072
} else if (other.length === 2) {
10531073
msg += `one of ${other[0]} or ${other[1]}`;
10541074
} else {
1055-
if (other[0].toLowerCase() !== other[0])
1075+
if (StringPrototypeToLowerCase(other[0]) !== other[0])
10561076
msg += 'an ';
10571077
msg += `${other[0]}`;
10581078
}
@@ -1074,15 +1094,15 @@ E('ERR_INVALID_ARG_TYPE',
10741094
let inspected = lazyInternalUtilInspect()
10751095
.inspect(actual, { colors: false });
10761096
if (inspected.length > 25)
1077-
inspected = `${inspected.slice(0, 25)}...`;
1097+
inspected = `${StringPrototypeSlice(inspected, 0, 25)}...`;
10781098
msg += `. Received type ${typeof actual} (${inspected})`;
10791099
}
10801100
return msg;
10811101
}, TypeError);
10821102
E('ERR_INVALID_ARG_VALUE', (name, value, reason = 'is invalid') => {
10831103
let inspected = lazyInternalUtilInspect().inspect(value);
10841104
if (inspected.length > 128) {
1085-
inspected = `${inspected.slice(0, 128)}...`;
1105+
inspected = `${StringPrototypeSlice(inspected, 0, 128)}...`;
10861106
}
10871107
return `The argument '${name}' ${reason}. Received ${inspected}`;
10881108
}, TypeError, RangeError);
@@ -1208,9 +1228,10 @@ E('ERR_MANIFEST_ASSERT_INTEGRITY',
12081228
moduleURL
12091229
}" does not match the expected integrity.`;
12101230
if (realIntegrities.size) {
1211-
const sri = [...realIntegrities.entries()].map(([alg, dgs]) => {
1212-
return `${alg}-${dgs}`;
1213-
}).join(' ');
1231+
const sri = ArrayPrototypeJoin(
1232+
ArrayFrom(realIntegrities.entries(), ([alg, dgs]) => `${alg}-${dgs}`),
1233+
' '
1234+
);
12141235
msg += ` Integrities found are: ${sri}`;
12151236
} else {
12161237
msg += ' The resource was not found in the policy.';
@@ -1237,7 +1258,13 @@ E('ERR_MISSING_ARGS',
12371258
assert(args.length > 0, 'At least one arg needs to be specified');
12381259
let msg = 'The ';
12391260
const len = args.length;
1240-
args = args.map((a) => `"${a}"`);
1261+
const wrap = (a) => `"${a}"`;
1262+
args = ArrayPrototypeMap(
1263+
args,
1264+
(a) => (ArrayIsArray(a) ?
1265+
ArrayPrototypeJoin(ArrayPrototypeMap(a, wrap), ' or ') :
1266+
wrap(a))
1267+
);
12411268
switch (len) {
12421269
case 1:
12431270
msg += `${args[0]} argument`;
@@ -1246,7 +1273,7 @@ E('ERR_MISSING_ARGS',
12461273
msg += `${args[0]} and ${args[1]} arguments`;
12471274
break;
12481275
default:
1249-
msg += args.slice(0, len - 1).join(', ');
1276+
msg += ArrayPrototypeJoin(ArrayPrototypeSlice(args, 0, len - 1), ', ');
12501277
msg += `, and ${args[len - 1]} arguments`;
12511278
break;
12521279
}
@@ -1449,18 +1476,18 @@ E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
14491476
E('ERR_WASI_ALREADY_STARTED', 'WASI instance has already started', Error);
14501477
E('ERR_WORKER_INIT_FAILED', 'Worker initialization failure: %s', Error);
14511478
E('ERR_WORKER_INVALID_EXEC_ARGV', (errors, msg = 'invalid execArgv flags') =>
1452-
`Initiated Worker with ${msg}: ${errors.join(', ')}`,
1479+
`Initiated Worker with ${msg}: ${ArrayPrototypeJoin(errors, ', ')}`,
14531480
Error);
14541481
E('ERR_WORKER_NOT_RUNNING', 'Worker instance not running', Error);
14551482
E('ERR_WORKER_OUT_OF_MEMORY',
14561483
'Worker terminated due to reaching memory limit: %s', Error);
14571484
E('ERR_WORKER_PATH', (filename) =>
14581485
'The worker script or module filename must be an absolute path or a ' +
14591486
'relative path starting with \'./\' or \'../\'.' +
1460-
(filename.startsWith('file://') ?
1487+
(StringPrototypeStartsWith(filename, 'file://') ?
14611488
' Wrap file:// URLs with `new URL`.' : ''
14621489
) +
1463-
(filename.startsWith('data:text/javascript') ?
1490+
(StringPrototypeStartsWith(filename, 'data:text/javascript') ?
14641491
' Wrap data: URLs with `new URL`.' : ''
14651492
) +
14661493
` 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)