Skip to content

Commit a90c9aa

Browse files
BridgeARcodebytere
authored andcommitted
util: fix inspection of class instance prototypes
To achieve this, some internal custom inspect functions had to be changed. They relied upon the former behavior. Signed-off-by: Ruben Bridgewater <[email protected]> PR-URL: #33449 Fixes: #33419 Reviewed-By: Anto Aravinth <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
1 parent 134ed0e commit a90c9aa

8 files changed

+113
-72
lines changed

lib/internal/encoding.js

+45-46
Original file line numberDiff line numberDiff line change
@@ -514,54 +514,53 @@ function makeTextDecoderJS() {
514514
}
515515

516516
// Mix in some shared properties.
517-
{
518-
ObjectDefineProperties(
519-
TextDecoder.prototype,
520-
ObjectGetOwnPropertyDescriptors({
521-
get encoding() {
522-
validateDecoder(this);
523-
return this[kEncoding];
524-
},
525-
526-
get fatal() {
527-
validateDecoder(this);
528-
return (this[kFlags] & CONVERTER_FLAGS_FATAL) === CONVERTER_FLAGS_FATAL;
529-
},
530-
531-
get ignoreBOM() {
532-
validateDecoder(this);
533-
return (this[kFlags] & CONVERTER_FLAGS_IGNORE_BOM) ===
534-
CONVERTER_FLAGS_IGNORE_BOM;
535-
},
536-
537-
[inspect](depth, opts) {
538-
validateDecoder(this);
539-
if (typeof depth === 'number' && depth < 0)
540-
return this;
541-
const ctor = getConstructorOf(this);
542-
const obj = ObjectCreate({
543-
constructor: ctor === null ? TextDecoder : ctor
544-
});
545-
obj.encoding = this.encoding;
546-
obj.fatal = this.fatal;
547-
obj.ignoreBOM = this.ignoreBOM;
548-
if (opts.showHidden) {
549-
obj[kFlags] = this[kFlags];
550-
obj[kHandle] = this[kHandle];
551-
}
552-
// Lazy to avoid circular dependency
553-
return require('internal/util/inspect').inspect(obj, opts);
517+
ObjectDefineProperties(
518+
TextDecoder.prototype,
519+
ObjectGetOwnPropertyDescriptors({
520+
get encoding() {
521+
validateDecoder(this);
522+
return this[kEncoding];
523+
},
524+
525+
get fatal() {
526+
validateDecoder(this);
527+
return (this[kFlags] & CONVERTER_FLAGS_FATAL) === CONVERTER_FLAGS_FATAL;
528+
},
529+
530+
get ignoreBOM() {
531+
validateDecoder(this);
532+
return (this[kFlags] & CONVERTER_FLAGS_IGNORE_BOM) ===
533+
CONVERTER_FLAGS_IGNORE_BOM;
534+
},
535+
536+
[inspect](depth, opts) {
537+
validateDecoder(this);
538+
if (typeof depth === 'number' && depth < 0)
539+
return this;
540+
const constructor = getConstructorOf(this) || TextDecoder;
541+
const obj = ObjectCreate({ constructor });
542+
obj.encoding = this.encoding;
543+
obj.fatal = this.fatal;
544+
obj.ignoreBOM = this.ignoreBOM;
545+
if (opts.showHidden) {
546+
obj[kFlags] = this[kFlags];
547+
obj[kHandle] = this[kHandle];
554548
}
555-
}));
556-
ObjectDefineProperties(TextDecoder.prototype, {
557-
decode: { enumerable: true },
558-
[inspect]: { enumerable: false },
559-
[SymbolToStringTag]: {
560-
configurable: true,
561-
value: 'TextDecoder'
549+
// Lazy to avoid circular dependency
550+
const { inspect } = require('internal/util/inspect');
551+
return `${constructor.name} ${inspect(obj)}`;
562552
}
563-
});
564-
}
553+
})
554+
);
555+
556+
ObjectDefineProperties(TextDecoder.prototype, {
557+
decode: { enumerable: true },
558+
[inspect]: { enumerable: false },
559+
[SymbolToStringTag]: {
560+
configurable: true,
561+
value: 'TextDecoder'
562+
}
563+
});
565564

566565
module.exports = {
567566
getEncodingFromLabel,

lib/internal/url.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -358,11 +358,8 @@ class URL {
358358
if (typeof depth === 'number' && depth < 0)
359359
return this;
360360

361-
const ctor = getConstructorOf(this);
362-
363-
const obj = ObjectCreate({
364-
constructor: ctor === null ? URL : ctor
365-
});
361+
const constructor = getConstructorOf(this) || URL;
362+
const obj = ObjectCreate({ constructor });
366363

367364
obj.href = this.href;
368365
obj.origin = this.origin;
@@ -383,7 +380,7 @@ class URL {
383380
obj[context] = this[context];
384381
}
385382

386-
return inspect(obj, opts);
383+
return `${constructor.name} ${inspect(obj, opts)}`;
387384
}
388385
}
389386

lib/internal/util/inspect.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,8 @@ function getConstructorName(obj, ctx, recurseTimes, protoProps) {
498498
const descriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor');
499499
if (descriptor !== undefined &&
500500
typeof descriptor.value === 'function' &&
501-
descriptor.value.name !== '') {
501+
descriptor.value.name !== '' &&
502+
tmp instanceof descriptor.value) {
502503
if (protoProps !== undefined &&
503504
(firstProto !== obj ||
504505
!builtInObjects.has(descriptor.value.name))) {

lib/internal/vm/module.js

+18-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ const {
55
ArrayIsArray,
66
ObjectCreate,
77
ObjectDefineProperty,
8+
ObjectGetPrototypeOf,
9+
ObjectSetPrototypeOf,
810
SafePromise,
911
Symbol,
1012
WeakMap,
@@ -223,17 +225,27 @@ class Module {
223225
}
224226

225227
[customInspectSymbol](depth, options) {
226-
let ctor = getConstructorOf(this);
227-
ctor = ctor === null ? Module : ctor;
228-
228+
if (this[kWrap] === undefined) {
229+
throw new ERR_VM_MODULE_NOT_MODULE();
230+
}
229231
if (typeof depth === 'number' && depth < 0)
230-
return options.stylize(`[${ctor.name}]`, 'special');
232+
return this;
231233

232-
const o = ObjectCreate({ constructor: ctor });
234+
const constructor = getConstructorOf(this) || Module;
235+
const o = ObjectCreate({ constructor });
233236
o.status = this.status;
234237
o.identifier = this.identifier;
235238
o.context = this.context;
236-
return require('internal/util/inspect').inspect(o, options);
239+
240+
ObjectSetPrototypeOf(o, ObjectGetPrototypeOf(this));
241+
ObjectDefineProperty(o, Symbol.toStringTag, {
242+
value: constructor.name,
243+
configurable: true
244+
});
245+
246+
// Lazy to avoid circular dependency
247+
const { inspect } = require('internal/util/inspect');
248+
return inspect(o, { ...options, customInspect: false });
237249
}
238250
}
239251

test/parallel/test-util-format.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ assert.strictEqual(
266266
' func: <ref *1> [Function: func] {\n' +
267267
' [length]: 0,\n' +
268268
' [name]: \'func\',\n' +
269-
' [prototype]: func { [constructor]: [Circular *1] }\n' +
269+
' [prototype]: { [constructor]: [Circular *1] }\n' +
270270
' }\n' +
271271
'}');
272272
assert.strictEqual(
@@ -279,7 +279,7 @@ assert.strictEqual(
279279
' a: <ref *1> [Function: a] {\n' +
280280
' [length]: 0,\n' +
281281
' [name]: \'a\',\n' +
282-
' [prototype]: a { [constructor]: [Circular *1] }\n' +
282+
' [prototype]: { [constructor]: [Circular *1] }\n' +
283283
' }\n' +
284284
' },\n' +
285285
' [length]: 1\n' +
@@ -294,7 +294,7 @@ assert.strictEqual(
294294
' func: <ref *1> [Function: func] {\n' +
295295
' [length]: 0,\n' +
296296
' [name]: \'func\',\n' +
297-
' [prototype]: func { [constructor]: [Circular *1] }\n' +
297+
' [prototype]: { [constructor]: [Circular *1] }\n' +
298298
' }\n' +
299299
' }\n' +
300300
'}');
@@ -306,15 +306,15 @@ assert.strictEqual(
306306
' func: <ref *1> [Function: func] {\n' +
307307
' [length]: 0,\n' +
308308
' [name]: \'func\',\n' +
309-
' [prototype]: func { [constructor]: [Circular *1] }\n' +
309+
' [prototype]: { [constructor]: [Circular *1] }\n' +
310310
' }\n' +
311311
'} {\n' +
312312
' foo: \'bar\',\n' +
313313
' foobar: 1,\n' +
314314
' func: <ref *1> [Function: func] {\n' +
315315
' [length]: 0,\n' +
316316
' [name]: \'func\',\n' +
317-
' [prototype]: func { [constructor]: [Circular *1] }\n' +
317+
' [prototype]: { [constructor]: [Circular *1] }\n' +
318318
' }\n' +
319319
'}');
320320
assert.strictEqual(
@@ -325,7 +325,7 @@ assert.strictEqual(
325325
' func: <ref *1> [Function: func] {\n' +
326326
' [length]: 0,\n' +
327327
' [name]: \'func\',\n' +
328-
' [prototype]: func { [constructor]: [Circular *1] }\n' +
328+
' [prototype]: { [constructor]: [Circular *1] }\n' +
329329
' }\n' +
330330
'} %o');
331331

test/parallel/test-util-inspect.js

+31
Original file line numberDiff line numberDiff line change
@@ -2827,6 +2827,37 @@ assert.strictEqual(
28272827
'{ \x1B[2mabc: \x1B[33mtrue\x1B[39m\x1B[22m, ' +
28282828
'\x1B[2mdef: \x1B[33m5\x1B[39m\x1B[22m }'
28292829
);
2830+
2831+
assert.strictEqual(
2832+
inspect(Object.getPrototypeOf(bar), { showHidden: true, getters: true }),
2833+
'<ref *1> Foo [Map] {\n' +
2834+
' [constructor]: [class Bar extends Foo] {\n' +
2835+
' [length]: 0,\n' +
2836+
' [prototype]: [Circular *1],\n' +
2837+
" [name]: 'Bar',\n" +
2838+
' [Symbol(Symbol.species)]: [Getter: <Inspection threw ' +
2839+
"(Symbol.prototype.toString requires that 'this' be a Symbol)>]\n" +
2840+
' },\n' +
2841+
" [xyz]: [Getter: 'YES!'],\n" +
2842+
' [Symbol(nodejs.util.inspect.custom)]: ' +
2843+
'[Function: [nodejs.util.inspect.custom]] {\n' +
2844+
' [length]: 0,\n' +
2845+
" [name]: '[nodejs.util.inspect.custom]'\n" +
2846+
' },\n' +
2847+
' [abc]: [Getter: true],\n' +
2848+
' [def]: [Getter/Setter: false]\n' +
2849+
' }'
2850+
);
2851+
2852+
assert.strictEqual(
2853+
inspect(Object.getPrototypeOf(bar)),
2854+
'Foo [Map] {}'
2855+
);
2856+
2857+
assert.strictEqual(
2858+
inspect(Object.getPrototypeOf(new Foo())),
2859+
'Map {}'
2860+
);
28302861
}
28312862

28322863
// Test changing util.inspect.colors colors and aliases.

test/parallel/test-vm-module-basic.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,12 @@ const util = require('util');
8383

8484
assert.strictEqual(util.inspect(m, { depth: -1 }), '[SourceTextModule]');
8585

86-
assert.strictEqual(
87-
m[util.inspect.custom].call(Object.create(null)),
88-
'Module { status: undefined, identifier: undefined, context: undefined }',
86+
assert.throws(
87+
() => m[util.inspect.custom].call(Object.create(null)),
88+
{
89+
code: 'ERR_VM_MODULE_NOT_MODULE',
90+
message: 'Provided module is not an instance of Module'
91+
},
8992
);
9093
}
9194

test/parallel/test-whatwg-encoding-custom-textdecoder.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ if (common.hasIntl) {
8585
assert.strictEqual(dec.encoding, 'utf-8');
8686
assert.strictEqual(dec.fatal, false);
8787
assert.strictEqual(dec.ignoreBOM, false);
88+
assert.strictEqual(dec[Symbol.toStringTag], 'TextDecoder');
8889
}
8990

9091
// Test TextDecoder, UTF-16le
@@ -125,10 +126,7 @@ if (common.hasIntl) {
125126
' [Symbol(flags)]: 4,\n' +
126127
' [Symbol(handle)]: StringDecoder {\n' +
127128
" encoding: 'utf8',\n" +
128-
' [Symbol(kNativeDecoder)]: <Buffer 00 00 00 00 00 00 01>,\n' +
129-
' lastChar: [Getter],\n' +
130-
' lastNeed: [Getter],\n' +
131-
' lastTotal: [Getter]\n' +
129+
' [Symbol(kNativeDecoder)]: <Buffer 00 00 00 00 00 00 01>\n' +
132130
' }\n' +
133131
'}'
134132
);

0 commit comments

Comments
 (0)