Skip to content

Commit

Permalink
util: Move handling null logic to inspect file
Browse files Browse the repository at this point in the history
  • Loading branch information
antsmartian committed Sep 27, 2018
1 parent d14c3e6 commit 215700c
Showing 1 changed file with 64 additions and 23 deletions.
87 changes: 64 additions & 23 deletions lib/internal/util/inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ function getEmptyFormatArray() {
}

function getConstructorName(obj) {
let firstProto;
while (obj) {
const descriptor = Object.getOwnPropertyDescriptor(obj, 'constructor');
if (descriptor !== undefined &&
Expand All @@ -335,25 +336,35 @@ function getConstructorName(obj) {
}

obj = Object.getPrototypeOf(obj);
if (firstProto === undefined) {
firstProto = obj;
}
}

if (firstProto === null) {
return null;
}
// TODO(BridgeAR): Improve prototype inspection.
// We could use inspect on the prototype itself to improve the output.

return '';
}

function getPrefix(constructor, tag, fallback) {
if (constructor === null) {
if (tag !== '') {
return `[${fallback}: null prototype] [${tag}] `;
}
return `[${fallback}: null prototype] `;
}

if (constructor !== '') {
if (tag !== '' && constructor !== tag) {
return `${constructor} [${tag}] `;
}
return `${constructor} `;
}

if (tag !== '')
return `[${tag}] `;

if (fallback !== undefined)
return `${fallback} `;

return '';
}

Expand Down Expand Up @@ -427,21 +438,49 @@ function findTypedConstructor(value) {
}
}

let lazyNullPrototypeCache;
// Creates a subclass and name
// the constructor as `${clazz} : null prototype`
function clazzWithNullPrototype(clazz, name) {
if (lazyNullPrototypeCache === undefined) {
lazyNullPrototypeCache = new Map();
} else {
const cachedClass = lazyNullPrototypeCache.get(clazz);
if (cachedClass !== undefined) {
return cachedClass;
}
}
class NullPrototype extends clazz {
get [Symbol.toStringTag]() {
return '';
}
}
Object.defineProperty(NullPrototype.prototype.constructor, 'name',
{ value: `[${name}: null prototype]` });
lazyNullPrototypeCache.set(clazz, NullPrototype);
return NullPrototype;
}

function noPrototypeIterator(ctx, value, recurseTimes) {
let newVal;
// TODO: Create a Subclass in case there's no prototype and show
// `null-prototype`.
if (isSet(value)) {
const clazz = Object.getPrototypeOf(value) || Set;
const clazz = Object.getPrototypeOf(value) ||
clazzWithNullPrototype(Set, 'Set');
newVal = new clazz(setValues(value));
} else if (isMap(value)) {
const clazz = Object.getPrototypeOf(value) || Map;
const clazz = Object.getPrototypeOf(value) ||
clazzWithNullPrototype(Map, 'Map');
newVal = new clazz(mapEntries(value));
} else if (Array.isArray(value)) {
const clazz = Object.getPrototypeOf(value) || Array;
const clazz = Object.getPrototypeOf(value) ||
clazzWithNullPrototype(Array, 'Array');
newVal = new clazz(value.length || 0);
} else if (isTypedArray(value)) {
const clazz = findTypedConstructor(value) || Uint8Array;
let clazz = Object.getPrototypeOf(value);
if (!clazz) {
const constructor = findTypedConstructor(value);
clazz = clazzWithNullPrototype(constructor, constructor.name);
}
newVal = new clazz(value);
}
if (newVal) {
Expand Down Expand Up @@ -527,29 +566,32 @@ function formatRaw(ctx, value, recurseTimes) {
if (Array.isArray(value)) {
keys = getOwnNonIndexProperties(value, filter);
// Only set the constructor for non ordinary ("Array [...]") arrays.
const prefix = getPrefix(constructor, tag);
const prefix = getPrefix(constructor, tag, 'Array');
braces = [`${prefix === 'Array ' ? '' : prefix}[`, ']'];
if (value.length === 0 && keys.length === 0)
return `${braces[0]}]`;
extrasType = kArrayExtrasType;
formatter = formatArray;
} else if (isSet(value)) {
keys = getKeys(value, ctx.showHidden);
const prefix = getPrefix(constructor, tag);
const prefix = getPrefix(constructor, tag, 'Set');
if (value.size === 0 && keys.length === 0)
return `${prefix}{}`;
braces = [`${prefix}{`, '}'];
formatter = formatSet;
} else if (isMap(value)) {
keys = getKeys(value, ctx.showHidden);
const prefix = getPrefix(constructor, tag);
const prefix = getPrefix(constructor, tag, 'Map');
if (value.size === 0 && keys.length === 0)
return `${prefix}{}`;
braces = [`${prefix}{`, '}'];
formatter = formatMap;
} else if (isTypedArray(value)) {
keys = getOwnNonIndexProperties(value, filter);
braces = [`${getPrefix(constructor, tag)}[`, ']'];
const prefix = constructor !== null ?
getPrefix(constructor, tag) :
getPrefix(constructor, tag, findTypedConstructor(value).name);
braces = [`${prefix}[`, ']'];
if (value.length === 0 && keys.length === 0 && !ctx.showHidden)
return `${braces[0]}]`;
formatter = formatTypedArray;
Expand All @@ -575,7 +617,7 @@ function formatRaw(ctx, value, recurseTimes) {
return '[Arguments] {}';
braces[0] = '[Arguments] {';
} else if (tag !== '') {
braces[0] = `${getPrefix(constructor, tag)}{`;
braces[0] = `${getPrefix(constructor, tag, 'Object')}{`;
if (keys.length === 0) {
return `${braces[0]}}`;
}
Expand Down Expand Up @@ -622,13 +664,12 @@ function formatRaw(ctx, value, recurseTimes) {
base = `[${base.slice(0, stackStart)}]`;
}
} else if (isAnyArrayBuffer(value)) {
let prefix = getPrefix(constructor, tag);
if (prefix === '') {
prefix = isArrayBuffer(value) ? 'ArrayBuffer ' : 'SharedArrayBuffer ';
}
// Fast path for ArrayBuffer and SharedArrayBuffer.
// Can't do the same for DataView because it has a non-primitive
// .buffer property that we need to recurse for.
const arrayType = isArrayBuffer(value) ? 'ArrayBuffer' :
'SharedArrayBuffer';
const prefix = getPrefix(constructor, tag, arrayType);
if (keys.length === 0)
return prefix +
`{ byteLength: ${formatNumber(ctx.stylize, value.byteLength)} }`;
Expand Down Expand Up @@ -693,9 +734,9 @@ function formatRaw(ctx, value, recurseTimes) {
} else if (keys.length === 0) {
if (isExternal(value))
return ctx.stylize('[External]', 'special');
return `${getPrefix(constructor, tag)}{}`;
return `${getPrefix(constructor, tag, 'Object')}{}`;
} else {
braces[0] = `${getPrefix(constructor, tag)}{`;
braces[0] = `${getPrefix(constructor, tag, 'Object')}{`;
}
}
}
Expand Down

0 comments on commit 215700c

Please sign in to comment.