diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 42fefdd147654d..a39779838a43a6 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -134,6 +134,9 @@ const builtInObjects = new Set( ObjectGetOwnPropertyNames(global).filter((e) => /^[A-Z][a-zA-Z0-9]+$/.test(e)) ); +// https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot +const isUndetectableObject = (v) => typeof v === 'undefined' && v !== undefined; + // These options must stay in sync with `getUserOptions`. So if any option will // be added or removed, `getUserOptions` must also be updated accordingly. const inspectDefaultOptions = ObjectSeal({ @@ -482,7 +485,7 @@ function getEmptyFormatArray() { function getConstructorName(obj, ctx, recurseTimes, protoProps) { let firstProto; const tmp = obj; - while (obj) { + while (obj || isUndetectableObject(obj)) { const descriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor'); if (descriptor !== undefined && typeof descriptor.value === 'function' && @@ -680,7 +683,9 @@ function findTypedConstructor(value) { // value afterwards again. function formatValue(ctx, value, recurseTimes, typedArray) { // Primitive types cannot have properties. - if (typeof value !== 'object' && typeof value !== 'function') { + if (typeof value !== 'object' && + typeof value !== 'function' && + !isUndetectableObject(value)) { return formatPrimitive(ctx.stylize, value, ctx); } if (value === null) { diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 7fb677d49524d0..5540acfee30247 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -26,6 +26,7 @@ const { internalBinding } = require('internal/test/binding'); const JSStream = internalBinding('js_stream').JSStream; const util = require('util'); const vm = require('vm'); +const v8 = require('v8'); const { previewEntries } = internalBinding('util'); const { inspect } = util; const { MessageChannel } = require('worker_threads'); @@ -2748,3 +2749,11 @@ assert.strictEqual( assert.deepStrictEqual(colors.gray, originalValue); assert.strictEqual(colors.grey, colors.gray); } + +// https://github.com/nodejs/node/issues/31889 +{ + v8.setFlagsFromString('--allow-natives-syntax'); + const undetectable = vm.runInThisContext('%GetUndetectable()'); + v8.setFlagsFromString('--no-allow-natives-syntax'); + assert.strictEqual(inspect(undetectable), '{}'); +}