Skip to content

Commit 79ea19e

Browse files
JakobJingleheimertargos
authored andcommitted
errors: extract type detection & use in ERR_INVALID_RETURN_VALUE
PR-URL: #43558 Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 6ede1c2 commit 79ea19e

File tree

4 files changed

+187
-30
lines changed

4 files changed

+187
-30
lines changed

‎lib/internal/errors.js‎

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,31 @@ const genericNodeError = hideStackFrames(function genericNodeError(message, erro
858858
returnerr;
859859
});
860860

861+
/**
862+
* Determine the specific type of a value for type-mismatch errors.
863+
* @param{*} value
864+
* @returns{string}
865+
*/
866+
functiondetermineSpecificType(value){
867+
if(value==null){
868+
return''+value;
869+
}
870+
if(typeofvalue==='function'&&value.name){
871+
return`function ${value.name}`;
872+
}
873+
if(typeofvalue==='object'){
874+
if(value.constructor?.name){
875+
return`an instance of ${value.constructor.name}`;
876+
}
877+
return`${lazyInternalUtilInspect().inspect(value,{depth: -1})}`;
878+
}
879+
letinspected=lazyInternalUtilInspect()
880+
.inspect(value,{colors: false});
881+
if(inspected.length>28){inspected=`${StringPrototypeSlice(inspected,0,25)}...`;}
882+
883+
return`type ${typeofvalue} (${inspected})`;
884+
}
885+
861886
module.exports={
862887
AbortError,
863888
aggregateTwoErrors,
@@ -866,6 +891,7 @@ module.exports ={
866891
connResetException,
867892
dnsException,
868893
// This is exported only to facilitate testing.
894+
determineSpecificType,
869895
E,
870896
errnoException,
871897
exceptionWithHostPort,
@@ -1237,25 +1263,8 @@ E('ERR_INVALID_ARG_TYPE',
12371263
}
12381264
}
12391265

1240-
if(actual==null){
1241-
msg+=`. Received ${actual}`;
1242-
}elseif(typeofactual==='function'&&actual.name){
1243-
msg+=`. Received function ${actual.name}`;
1244-
}elseif(typeofactual==='object'){
1245-
if(actual.constructor?.name){
1246-
msg+=`. Received an instance of ${actual.constructor.name}`;
1247-
}else{
1248-
constinspected=lazyInternalUtilInspect()
1249-
.inspect(actual,{depth: -1});
1250-
msg+=`. Received ${inspected}`;
1251-
}
1252-
}else{
1253-
letinspected=lazyInternalUtilInspect()
1254-
.inspect(actual,{colors: false});
1255-
if(inspected.length>25)
1256-
inspected=`${StringPrototypeSlice(inspected,0,25)}...`;
1257-
msg+=`. Received type ${typeofactual} (${inspected})`;
1258-
}
1266+
msg+=`. Received ${determineSpecificType(actual)}`;
1267+
12591268
returnmsg;
12601269
},TypeError);
12611270
E('ERR_INVALID_ARG_VALUE',(name,value,reason='is invalid')=>{
@@ -1335,12 +1344,8 @@ E('ERR_INVALID_RETURN_PROPERTY_VALUE', (input, name, prop, value) =>{
13351344
` "${name}" function but got ${type}.`;
13361345
},TypeError);
13371346
E('ERR_INVALID_RETURN_VALUE',(input,name,value)=>{
1338-
lettype;
1339-
if(value?.constructor?.name){
1340-
type=`instance of ${value.constructor.name}`;
1341-
}else{
1342-
type=`type ${typeofvalue}`;
1343-
}
1347+
consttype=determineSpecificType(value);
1348+
13441349
return`Expected ${input} to be returned from the "${name}"`+
13451350
` function but got ${type}.`;
13461351
},TypeError,RangeError);

‎test/common/index.js‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -737,14 +737,15 @@ function invalidArgTypeHelper(input){
737737
return` Received function ${input.name}`;
738738
}
739739
if(typeofinput==='object'){
740-
if(input.constructor&&input.constructor.name){
740+
if(input.constructor?.name){
741741
return` Received an instance of ${input.constructor.name}`;
742742
}
743743
return` Received ${inspect(input,{depth: -1})}`;
744744
}
745+
745746
letinspected=inspect(input,{colors: false});
746-
if(inspected.length>25)
747-
inspected=`${inspected.slice(0,25)}...`;
747+
if(inspected.length>28){inspected=`${inspected.slice(inspected,0,25)}...`;}
748+
748749
return` Received type ${typeofinput} (${inspected})`;
749750
}
750751

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Flags: --expose-internals
2+
3+
import'../common/index.mjs';
4+
import{strictEqual}from'node:assert';
5+
importerrorsModulefrom'internal/errors';
6+
7+
8+
const{ determineSpecificType }=errorsModule;
9+
10+
strictEqual(
11+
determineSpecificType(1n),
12+
'type bigint (1n)',
13+
);
14+
15+
strictEqual(
16+
determineSpecificType(false),
17+
'type boolean (false)',
18+
);
19+
20+
strictEqual(
21+
determineSpecificType(2),
22+
'type number (2)',
23+
);
24+
25+
strictEqual(
26+
determineSpecificType(NaN),
27+
'type number (NaN)',
28+
);
29+
30+
strictEqual(
31+
determineSpecificType(Infinity),
32+
'type number (Infinity)',
33+
);
34+
35+
strictEqual(
36+
determineSpecificType(Object.create(null)),
37+
'[Object: null prototype]{}',
38+
);
39+
40+
strictEqual(
41+
determineSpecificType(''),
42+
"type string ('')",
43+
);
44+
45+
strictEqual(
46+
determineSpecificType(Symbol('foo')),
47+
'type symbol (Symbol(foo))',
48+
);
49+
50+
strictEqual(
51+
determineSpecificType(functionfoo(){}),
52+
'function foo',
53+
);
54+
55+
strictEqual(
56+
determineSpecificType(null),
57+
'null',
58+
);
59+
60+
strictEqual(
61+
determineSpecificType(undefined),
62+
'undefined',
63+
);
64+
65+
strictEqual(
66+
determineSpecificType([]),
67+
'an instance of Array',
68+
);
69+
70+
strictEqual(
71+
determineSpecificType(newArray()),
72+
'an instance of Array',
73+
);
74+
strictEqual(
75+
determineSpecificType(newBigInt64Array()),
76+
'an instance of BigInt64Array',
77+
);
78+
strictEqual(
79+
determineSpecificType(newBigUint64Array()),
80+
'an instance of BigUint64Array',
81+
);
82+
strictEqual(
83+
determineSpecificType(newInt8Array()),
84+
'an instance of Int8Array',
85+
);
86+
strictEqual(
87+
determineSpecificType(newInt16Array()),
88+
'an instance of Int16Array',
89+
);
90+
strictEqual(
91+
determineSpecificType(newInt32Array()),
92+
'an instance of Int32Array',
93+
);
94+
strictEqual(
95+
determineSpecificType(newFloat32Array()),
96+
'an instance of Float32Array',
97+
);
98+
strictEqual(
99+
determineSpecificType(newFloat64Array()),
100+
'an instance of Float64Array',
101+
);
102+
strictEqual(
103+
determineSpecificType(newUint8Array()),
104+
'an instance of Uint8Array',
105+
);
106+
strictEqual(
107+
determineSpecificType(newUint8ClampedArray()),
108+
'an instance of Uint8ClampedArray',
109+
);
110+
strictEqual(
111+
determineSpecificType(newUint16Array()),
112+
'an instance of Uint16Array',
113+
);
114+
strictEqual(
115+
determineSpecificType(newUint32Array()),
116+
'an instance of Uint32Array',
117+
);
118+
119+
strictEqual(
120+
determineSpecificType(newDate()),
121+
'an instance of Date',
122+
);
123+
124+
strictEqual(
125+
determineSpecificType(newMap()),
126+
'an instance of Map',
127+
);
128+
strictEqual(
129+
determineSpecificType(newWeakMap()),
130+
'an instance of WeakMap',
131+
);
132+
133+
strictEqual(
134+
determineSpecificType({}),
135+
'an instance of Object',
136+
);
137+
138+
strictEqual(
139+
determineSpecificType(Promise.resolve('foo')),
140+
'an instance of Promise',
141+
);
142+
143+
strictEqual(
144+
determineSpecificType(newSet()),
145+
'an instance of Set',
146+
);
147+
strictEqual(
148+
determineSpecificType(newWeakSet()),
149+
'an instance of WeakSet',
150+
);

‎test/parallel/test-assert-async.js‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,9 @@ const invalidThenableFunc = () =>{
103103
promises.push(assert.rejects(promise,{
104104
name: 'TypeError',
105105
code: 'ERR_INVALID_RETURN_VALUE',
106+
// FIXME(JakobJingleheimer): This should match on key words, like /Promise/ and /undefined/.
106107
message: 'Expected instance of Promise to be returned '+
107-
'from the "promiseFn" function but got type undefined.'
108+
'from the "promiseFn" function but got undefined.'
108109
}));
109110

110111
promise=assert.rejects(Promise.resolve(),common.mustNotCall());
@@ -162,7 +163,7 @@ promises.push(assert.rejects(
162163
letpromise=assert.doesNotReject(()=>newMap(),common.mustNotCall());
163164
promises.push(assert.rejects(promise,{
164165
message: 'Expected instance of Promise to be returned '+
165-
'from the "promiseFn" function but got instance of Map.',
166+
'from the "promiseFn" function but got an instance of Map.',
166167
code: 'ERR_INVALID_RETURN_VALUE',
167168
name: 'TypeError'
168169
}));

0 commit comments

Comments
(0)