diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 0b1a776c9cd1bb..804273f987f646 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -724,18 +724,16 @@ function getCtxStyle(value, constructor, tag) { return getPrefix(constructor, tag, fallback); } -function formatProxy(ctx, target, handler, recurseTimes, showProperties = true) { +function formatProxy(ctx, proxy, recurseTimes) { if (recurseTimes > ctx.depth && ctx.depth !== null) { return ctx.stylize('Proxy [Array]', 'special'); } recurseTimes += 1; ctx.indentationLvl += 2; - const res = showProperties ? - [ - formatValue(ctx, target, recurseTimes), - formatValue(ctx, handler, recurseTimes), - ] : - []; + const res = [ + formatValue(ctx, proxy[0], recurseTimes), + formatValue(ctx, proxy[1], recurseTimes), + ]; ctx.indentationLvl -= 2; return reduceToSingleString( ctx, res, '', ['Proxy [', ']'], kArrayExtrasType, recurseTimes); @@ -759,15 +757,15 @@ function formatValue(ctx, value, recurseTimes, typedArray) { const context = value; // Always check for proxies to prevent side effects and to prevent triggering // any proxy handlers. - const details = getProxyDetails(value, !!ctx.showProxy); - if (details !== undefined) { + const proxy = getProxyDetails(value, !!ctx.showProxy); + if (proxy !== undefined) { + if (proxy === null || proxy[2] === true) { + return ctx.stylize('', 'special'); + } if (ctx.showProxy) { - return formatProxy(ctx, details[0], details[1], recurseTimes); - } else if (details === null) { - // The proxy is revoked. Both target and handler of it are null. - return formatProxy(ctx, details, null, recurseTimes, ctx.showProxy); + return formatProxy(ctx, proxy, recurseTimes); } - value = details; + value = proxy; } // Provide a hook for user-specified inspect functions. @@ -783,7 +781,7 @@ function formatValue(ctx, value, recurseTimes, typedArray) { // a counter internally. const depth = ctx.depth === null ? null : ctx.depth - recurseTimes; const isCrossContext = - details !== undefined || !(context instanceof Object); + proxy !== undefined || !(context instanceof Object); const ret = FunctionPrototypeCall( maybeCustom, context, @@ -1939,12 +1937,9 @@ function reduceToSingleString( braces[0].length + base.length + 10; if (isBelowBreakLength(ctx, output, start, base)) { const joinedOutput = join(output, ', '); - const space = joinedOutput.length > 0 ? ' ' : ''; if (!joinedOutput.includes('\n')) { - return ( - `${base ? `${base} ` : ''}${braces[0]}${space}${joinedOutput}` + - `${space}${braces[1]}` - ); + return `${base ? `${base} ` : ''}${braces[0]} ${joinedOutput}` + + ` ${braces[1]}`; } } } @@ -1975,11 +1970,14 @@ function hasBuiltInToString(value) { const getFullProxy = false; const proxyTarget = getProxyDetails(value, getFullProxy); if (proxyTarget !== undefined) { + if (proxyTarget === null) { + return true; + } value = proxyTarget; } // Count objects that have no `toString` function as built-in. - if (typeof value?.toString !== 'function') { + if (typeof value.toString !== 'function') { return true; } diff --git a/src/node_util.cc b/src/node_util.cc index 2db45bd1fb40af..3c208f5bbe9575 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -117,6 +117,7 @@ static void GetProxyDetails(const FunctionCallbackInfo& args) { if (!args[0]->IsProxy()) return; + Environment* env = Environment::GetCurrent(args); Local proxy = args[0].As(); // TODO(BridgeAR): Remove the length check as soon as we prohibit access to @@ -125,7 +126,8 @@ static void GetProxyDetails(const FunctionCallbackInfo& args) { if (args.Length() == 1 || args[1]->IsTrue()) { Local ret[] = { proxy->GetTarget(), - proxy->GetHandler() + proxy->GetHandler(), + Boolean::New(env->isolate(), proxy->IsRevoked()) }; args.GetReturnValue().Set( diff --git a/test/parallel/test-util-inspect-proxy.js b/test/parallel/test-util-inspect-proxy.js index 30365f43f7b9a6..d71f20f4a86ea2 100644 --- a/test/parallel/test-util-inspect-proxy.js +++ b/test/parallel/test-util-inspect-proxy.js @@ -53,6 +53,7 @@ assert.strictEqual(handler, details[1]); details = processUtil.getProxyDetails(proxyObj); assert.strictEqual(target, details[0]); assert.strictEqual(handler, details[1]); +assert.strictEqual(details[2], false); details = processUtil.getProxyDetails(proxyObj, false); assert.strictEqual(target, details); @@ -66,17 +67,18 @@ r.revoke(); details = processUtil.getProxyDetails(r.proxy, true); assert.strictEqual(details[0], null); assert.strictEqual(details[1], null); +assert.strictEqual(details[2], true); details = processUtil.getProxyDetails(r.proxy, false); assert.strictEqual(details, null); -assert.strictEqual(util.inspect(r.proxy), 'Proxy []'); +assert.strictEqual(util.inspect(r.proxy), ''); assert.strictEqual( util.inspect(r, { showProxy: true }), - '{ proxy: Proxy [ null, null ], revoke: [Function (anonymous)] }', + '{ proxy: , revoke: [Function (anonymous)] }', ); -assert.strictEqual(util.format('%s', r.proxy), 'Proxy []'); +assert.strictEqual(util.format('%s', r.proxy), ''); assert.strictEqual( util.inspect(proxyObj, opts),