Repository navigation
util: possibly confusing util.inspect() output #15474
Description
Activity
- addedutilIssues and PRs related to the built-in util module.Issues and PRs related to the built-in util module.
on Sep 19, 2017 More complicated case:
'use strict'; function autoVivify(obj) { return new Proxy(obj, { get(target, property) { if (target[property] === undefined) target[property] = autoVivify({}); return target[property]; }, }); } const object = {}; const proxy = autoVivify(object); proxy.a.b.c = 'I am alive!'; console.log(proxy.a.b.c); console.log(object.a.b.c); console.log(object); console.log(proxy);
I am alive! I am alive! { a: { b: { c: 'I am alive!', [Symbol(util.inspect.custom)]: [Object] }, [Symbol(util.inspect.custom)]: { [Symbol(util.inspect.custom)]: [Object] } } } { a: { b: { c: 'I am alive!', [Symbol(util.inspect.custom)]: [Object], [Symbol(Symbol.toStringTag)]: [Object] }, [Symbol(util.inspect.custom)]: { [Symbol(util.inspect.custom)]: [Object], [Symbol(Symbol.toStringTag)]: [Object] }, [Symbol(Symbol.toStringTag)]: { [Symbol(util.inspect.custom)]: [Object] } }, [Symbol(util.inspect.custom)]: { [Symbol(util.inspect.custom)]: { [Symbol(util.inspect.custom)]: [Object] } } }
Reacted by Refael AckermannI do not think that this is intended. It changed from 7 -> 8 because of #9726. But showing symbols is not the issue here out of my perspective but that the
util.inspect.customsymbol is added to the output by default.I plan on having a look at this.
Reacted by Vse Mozhe Buty and Refael AckermannIMHO the issue is that
[Symbol(util.inspect.custom)]and[Symbol(Symbol.toStringTag)]are accessed without checking whether they areinthe subject, so they get autovivified.
Line 420 in 3c65a83
const maybeCustomInspect = value[customInspectSymbol] || value.inspect; P.S. @vsemozhetbyt autovivification with proxies is tricky exactly because of this - frameworks, and language features test for fields on the proxy and trigger vivification. When I use this pattern, I run it once or twice, see which fields are accessed, then filter them out in the proxy 🤷♂️
Reacted by Vse Mozhe Buty@refack you are absolutely right. There is little that can be done on utils side to improve the situation. Even though I think it is weird that
customInspectistrueas default. I think it would be good to change that to false. This was introduced in 2012 in this commit 4eb5399 and I think this should have never landed because having a individual inspect function on the object itself that you are inspecting is somewhat of a weird concept. That is also the reason why the symbol was introduced (a much cleaner approach, even though I personally would have preferred a option with which you can just pass on a function). As it is to late to remove it we might still think about changing the default tofalse.Reacted by Anna Henningsen@refack In addition, objects autovivified with proxies appear not to be serializable (
RangeError: Maximum call stack size exceededfromJSON.stringify()). But in this case, they are just a useful occasion to think about custom inspect edges)@BridgeAR we could do something less performant, but "safer":
const maybeCustomInspect = customInspectSymbol in value ? value[customInspectSymbol] : 'inspect' in value ? value.inspect : null;
@vsemozhetbyt you need to filter out
toJSON:function autoVivify(obj) { return new Proxy(obj, { get(target, property) { if (property == 'toJSON') return; if (property == util.inspect.custom) return; if (!property in target) target[property] = autoVivify({}); return target[property]; }, }); }
Reacted by Vse Mozhe Buty@refack is that really safer? It moves the check to a different trap and in this case the trap would not be called but I do not yet see a big advantage for this approach.
@BridgeAR You're right. Actually I now think the inspection should go to a lower level V8 API, and not done in JS.
Both inspection and serialization inevitably will trip a few traps in proxies...I don’t think this is very different from e.g. when
[Symbol.toPrimitive]()is called on such a proxy – the results are going to be the same as here, right? In that case, special-casing forutil.inspectdoesn’t seem to make sense to me.Well, after thinking about this further I guess everything is working as expected and also my comment about changing the default is probably not a good idea as it should probably "just work" when ever a user wants a individual inspection instead of having to explicitly activate it.
Therefore I think there is little left to do here and I close the issue. If someone disagrees - please feel free to reopen.
Reacted by Vse Mozhe Buty
I am trying to make a simple object autovivification with Proxy:
I understand that this is an edge case and maybe the output is correct. But I feel somehow that I should report this in case it is not completely intended. Feel free to close if it is by design.