summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/util.js463
-rw-r--r--test/parallel/test-util-inspect.js2
2 files changed, 223 insertions, 242 deletions
diff --git a/lib/util.js b/lib/util.js
index 82d924fdd8..35bd9ec46f 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -33,11 +33,16 @@ const { isBuffer } = require('buffer').Buffer;
const { internalBinding } = require('internal/bootstrap/loaders');
const {
+ getOwnNonIndexProperties,
getPromiseDetails,
getProxyDetails,
kPending,
kRejected,
- previewEntries
+ previewEntries,
+ propertyFilter: {
+ ALL_PROPERTIES,
+ ONLY_ENUMERABLE
+ }
} = internalBinding('util');
const types = internalBinding('types');
@@ -46,6 +51,7 @@ const {
isAnyArrayBuffer,
isArrayBuffer,
isArgumentsObject,
+ isBoxedPrimitive,
isDataView,
isExternal,
isMap,
@@ -61,7 +67,6 @@ const {
isStringObject,
isNumberObject,
isBooleanObject,
- isSymbolObject,
isBigIntObject,
isUint8Array,
isUint8ClampedArray,
@@ -97,6 +102,10 @@ const inspectDefaultOptions = Object.seal({
compact: true
});
+const kObjectType = 0;
+const kArrayType = 1;
+const kArrayExtrasType = 2;
+
const ReflectApply = Reflect.apply;
// This function is borrowed from the function with the same name on V8 Extras'
@@ -122,6 +131,7 @@ const stringValueOf = uncurryThis(String.prototype.valueOf);
const setValues = uncurryThis(Set.prototype.values);
const mapEntries = uncurryThis(Map.prototype.entries);
const dateGetTime = uncurryThis(Date.prototype.getTime);
+const hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
let CIRCULAR_ERROR_MESSAGE;
let internalDeepEqual;
@@ -475,10 +485,15 @@ function stylizeWithColor(str, styleType) {
return str;
}
-function stylizeNoColor(str, styleType) {
+function stylizeNoColor(str) {
return str;
}
+// Return a new empty array to push in the results of the default formatter.
+function getEmptyFormatArray() {
+ return [];
+}
+
function getConstructorName(obj) {
while (obj) {
const descriptor = Object.getOwnPropertyDescriptor(obj, 'constructor');
@@ -511,6 +526,56 @@ function getPrefix(constructor, tag, fallback) {
return '';
}
+const getBoxedValue = formatPrimitive.bind(null, stylizeNoColor);
+
+// Look up the keys of the object.
+function getKeys(value, showHidden) {
+ let keys;
+ const symbols = Object.getOwnPropertySymbols(value);
+ if (showHidden) {
+ keys = Object.getOwnPropertyNames(value);
+ if (symbols.length !== 0)
+ keys.push(...symbols);
+ } else {
+ // This might throw if `value` is a Module Namespace Object from an
+ // unevaluated module, but we don't want to perform the actual type
+ // check because it's expensive.
+ // TODO(devsnek): track https://github.com/tc39/ecma262/issues/1209
+ // and modify this logic as needed.
+ try {
+ keys = Object.keys(value);
+ } catch (err) {
+ if (types.isNativeError(err) &&
+ err.name === 'ReferenceError' &&
+ types.isModuleNamespaceObject(value)) {
+ keys = Object.getOwnPropertyNames(value);
+ } else {
+ throw err;
+ }
+ }
+ if (symbols.length !== 0) {
+ keys.push(...symbols.filter((key) => propertyIsEnumerable(value, key)));
+ }
+ }
+ return keys;
+}
+
+function formatProxy(ctx, proxy, recurseTimes) {
+ if (recurseTimes != null) {
+ if (recurseTimes < 0)
+ return ctx.stylize('Proxy [Array]', 'special');
+ recurseTimes -= 1;
+ }
+ ctx.indentationLvl += 2;
+ const res = [
+ formatValue(ctx, proxy[0], recurseTimes),
+ formatValue(ctx, proxy[1], recurseTimes)
+ ];
+ ctx.indentationLvl -= 2;
+ const str = reduceToSingleString(ctx, res, '', ['[', ']']);
+ return `Proxy ${str}`;
+}
+
function findTypedConstructor(value) {
for (const [check, clazz] of [
[isUint8Array, Uint8Array],
@@ -531,8 +596,6 @@ function findTypedConstructor(value) {
}
}
-const getBoxedValue = formatPrimitive.bind(null, stylizeNoColor);
-
function noPrototypeIterator(ctx, value, recurseTimes) {
let newVal;
// TODO: Create a Subclass in case there's no prototype and show
@@ -571,19 +634,7 @@ function formatValue(ctx, value, recurseTimes) {
if (ctx.showProxy) {
const proxy = getProxyDetails(value);
if (proxy !== undefined) {
- if (recurseTimes != null) {
- if (recurseTimes < 0)
- return ctx.stylize('Proxy [Array]', 'special');
- recurseTimes -= 1;
- }
- ctx.indentationLvl += 2;
- const res = [
- formatValue(ctx, proxy[0], recurseTimes),
- formatValue(ctx, proxy[1], recurseTimes)
- ];
- ctx.indentationLvl -= 2;
- const str = reduceToSingleString(ctx, res, '', ['[', ']']);
- return `Proxy ${str}`;
+ return formatProxy(ctx, proxy, recurseTimes);
}
}
@@ -614,78 +665,65 @@ function formatValue(ctx, value, recurseTimes) {
if (ctx.seen.indexOf(value) !== -1)
return ctx.stylize('[Circular]', 'special');
- let keys;
- let symbols = Object.getOwnPropertySymbols(value);
-
- // Look up the keys of the object.
- if (ctx.showHidden) {
- keys = Object.getOwnPropertyNames(value);
- } else {
- // This might throw if `value` is a Module Namespace Object from an
- // unevaluated module, but we don't want to perform the actual type
- // check because it's expensive.
- // TODO(devsnek): track https://github.com/tc39/ecma262/issues/1209
- // and modify this logic as needed.
- try {
- keys = Object.keys(value);
- } catch (err) {
- if (types.isNativeError(err) &&
- err.name === 'ReferenceError' &&
- types.isModuleNamespaceObject(value)) {
- keys = Object.getOwnPropertyNames(value);
- } else {
- throw err;
- }
- }
-
- if (symbols.length !== 0)
- symbols = symbols.filter((key) => propertyIsEnumerable(value, key));
- }
+ return formatRaw(ctx, value, recurseTimes);
+}
- const keyLength = keys.length + symbols.length;
+function formatRaw(ctx, value, recurseTimes) {
+ let keys;
const constructor = getConstructorName(value);
let tag = value[Symbol.toStringTag];
if (typeof tag !== 'string')
tag = '';
let base = '';
- let formatter = formatObject;
+ let formatter = getEmptyFormatArray;
let braces;
let noIterator = true;
- let extra;
let i = 0;
+ let skip = false;
+ const filter = ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE;
+
+ let extrasType = kObjectType;
// Iterators and the rest are split to reduce checks
if (value[Symbol.iterator]) {
noIterator = false;
if (Array.isArray(value)) {
+ keys = getOwnNonIndexProperties(value, filter);
// Only set the constructor for non ordinary ("Array [...]") arrays.
const prefix = getPrefix(constructor, tag);
braces = [`${prefix === 'Array ' ? '' : prefix}[`, ']'];
- if (value.length === 0 && keyLength === 0)
+ 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);
- if (value.size === 0 && keyLength === 0)
+ 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);
- if (value.size === 0 && keyLength === 0)
+ 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)}[`, ']'];
- if (value.length === 0 && keyLength === 0 && !ctx.showHidden)
+ if (value.length === 0 && keys.length === 0 && !ctx.showHidden)
return `${braces[0]}]`;
formatter = formatTypedArray;
+ extrasType = kArrayExtrasType;
} else if (isMapIterator(value)) {
+ keys = getKeys(value, ctx.showHidden);
braces = [`[${tag}] {`, '}'];
formatter = formatMapIterator;
} else if (isSetIterator(value)) {
+ keys = getKeys(value, ctx.showHidden);
braces = [`[${tag}] {`, '}'];
formatter = formatSetIterator;
} else {
@@ -693,34 +731,35 @@ function formatValue(ctx, value, recurseTimes) {
}
}
if (noIterator) {
+ keys = getKeys(value, ctx.showHidden);
braces = ['{', '}'];
if (constructor === 'Object') {
if (isArgumentsObject(value)) {
- if (keyLength === 0)
+ if (keys.length === 0)
return '[Arguments] {}';
braces[0] = '[Arguments] {';
} else if (tag !== '') {
braces[0] = `${getPrefix(constructor, tag)}{`;
- if (keyLength === 0) {
+ if (keys.length === 0) {
return `${braces[0]}}`;
}
- } else if (keyLength === 0) {
+ } else if (keys.length === 0) {
return '{}';
}
} else if (typeof value === 'function') {
const type = constructor || tag || 'Function';
const name = `${type}${value.name ? `: ${value.name}` : ''}`;
- if (keyLength === 0)
+ if (keys.length === 0)
return ctx.stylize(`[${name}]`, 'special');
base = `[${name}]`;
} else if (isRegExp(value)) {
// Make RegExps say that they are RegExps
- if (keyLength === 0 || recurseTimes < 0)
+ if (keys.length === 0 || recurseTimes < 0)
return ctx.stylize(regExpToString(value), 'regexp');
base = `${regExpToString(value)}`;
} else if (isDate(value)) {
// Make dates with properties first say the date
- if (keyLength === 0) {
+ if (keys.length === 0) {
if (Number.isNaN(dateGetTime(value)))
return ctx.stylize(String(value), 'date');
return ctx.stylize(dateToISOString(value), 'date');
@@ -739,7 +778,7 @@ function formatValue(ctx, value, recurseTimes) {
const indentation = ' '.repeat(ctx.indentationLvl);
base = formatError(value).replace(/\n/g, `\n${indentation}`);
}
- if (keyLength === 0)
+ if (keys.length === 0)
return base;
if (ctx.compact === false && stackStart !== -1) {
@@ -747,14 +786,14 @@ function formatValue(ctx, value, recurseTimes) {
base = `[${base.slice(0, stackStart)}]`;
}
} else if (isAnyArrayBuffer(value)) {
- // 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.
let prefix = getPrefix(constructor, tag);
if (prefix === '') {
prefix = isArrayBuffer(value) ? 'ArrayBuffer ' : 'SharedArrayBuffer ';
}
- if (keyLength === 0)
+ // 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.
+ if (keys.length === 0)
return prefix +
`{ byteLength: ${formatNumber(ctx.stylize, value.byteLength)} }`;
braces[0] = `${prefix}{`;
@@ -768,50 +807,42 @@ function formatValue(ctx, value, recurseTimes) {
formatter = formatPromise;
} else if (isWeakSet(value)) {
braces[0] = `${getPrefix(constructor, tag, 'WeakSet')}{`;
- if (ctx.showHidden) {
- formatter = formatWeakSet;
- } else {
- extra = ctx.stylize('<items unknown>', 'special');
- }
+ formatter = ctx.showHidden ? formatWeakSet : formatWeakCollection;
} else if (isWeakMap(value)) {
braces[0] = `${getPrefix(constructor, tag, 'WeakMap')}{`;
- if (ctx.showHidden) {
- formatter = formatWeakMap;
- } else {
- extra = ctx.stylize('<items unknown>', 'special');
- }
+ formatter = ctx.showHidden ? formatWeakMap : formatWeakCollection;
} else if (types.isModuleNamespaceObject(value)) {
braces[0] = `[${tag}] {`;
formatter = formatNamespaceObject;
- } else if (isNumberObject(value)) {
- base = `[Number: ${getBoxedValue(numberValueOf(value))}]`;
- if (keyLength === 0)
- return ctx.stylize(base, 'number');
- } else if (isBooleanObject(value)) {
- base = `[Boolean: ${getBoxedValue(booleanValueOf(value))}]`;
- if (keyLength === 0)
- return ctx.stylize(base, 'boolean');
- } else if (isBigIntObject(value)) {
- base = `[BigInt: ${getBoxedValue(bigIntValueOf(value))}]`;
- if (keyLength === 0)
- return ctx.stylize(base, 'bigint');
- } else if (isSymbolObject(value)) {
- base = `[Symbol: ${getBoxedValue(symbolValueOf(value))}]`;
- if (keyLength === 0)
- return ctx.stylize(base, 'symbol');
- } else if (isStringObject(value)) {
- const raw = stringValueOf(value);
- base = `[String: ${getBoxedValue(raw, ctx)}]`;
- if (keyLength === raw.length)
- return ctx.stylize(base, 'string');
- // For boxed Strings, we have to remove the 0-n indexed entries,
- // since they just noisy up the output and are redundant
- // Make boxed primitive Strings look like such
- keys = keys.slice(value.length);
- braces = ['{', '}'];
- // The input prototype got manipulated. Special handle these.
- // We have to rebuild the information so we are able to display everything.
+ skip = true;
+ } else if (isBoxedPrimitive(value)) {
+ let type;
+ if (isNumberObject(value)) {
+ base = `[Number: ${getBoxedValue(numberValueOf(value))}]`;
+ type = 'number';
+ } else if (isStringObject(value)) {
+ base = `[String: ${getBoxedValue(stringValueOf(value), ctx)}]`;
+ type = 'string';
+ // For boxed Strings, we have to remove the 0-n indexed entries,
+ // since they just noisy up the output and are redundant
+ // Make boxed primitive Strings look like such
+ keys = keys.slice(value.length);
+ } else if (isBooleanObject(value)) {
+ base = `[Boolean: ${getBoxedValue(booleanValueOf(value))}]`;
+ type = 'boolean';
+ } else if (isBigIntObject(value)) {
+ base = `[BigInt: ${getBoxedValue(bigIntValueOf(value))}]`;
+ type = 'bigint';
+ } else {
+ base = `[Symbol: ${getBoxedValue(symbolValueOf(value))}]`;
+ type = 'symbol';
+ }
+ if (keys.length === 0) {
+ return ctx.stylize(base, type);
+ }
} else {
+ // The input prototype got manipulated. Special handle these. We have to
+ // rebuild the information so we are able to display everything.
const specialIterator = noPrototypeIterator(ctx, value, recurseTimes);
if (specialIterator) {
return specialIterator;
@@ -823,7 +854,7 @@ function formatValue(ctx, value, recurseTimes) {
braces = [`[${tag || 'Set Iterator'}] {`, '}'];
formatter = formatSetIterator;
// Handle other regular objects again.
- } else if (keyLength === 0) {
+ } else if (keys.length === 0) {
if (isExternal(value))
return ctx.stylize('[External]', 'special');
return `${getPrefix(constructor, tag)}{}`;
@@ -841,36 +872,34 @@ function formatValue(ctx, value, recurseTimes) {
ctx.seen.push(value);
let output;
- // This corresponds to a depth of at least 333 and likely 500.
- if (ctx.indentationLvl < 1000) {
+ try {
output = formatter(ctx, value, recurseTimes, keys);
- } else {
- try {
- output = formatter(ctx, value, recurseTimes, keys);
- } catch (err) {
- if (errors.isStackOverflowError(err)) {
- ctx.seen.pop();
- return ctx.stylize(
- `[${constructor || tag || 'Object'}: Inspection interrupted ` +
- 'prematurely. Maximum call stack size exceeded.]',
- 'special'
- );
+ if (skip === false) {
+ for (i = 0; i < keys.length; i++) {
+ output.push(
+ formatProperty(ctx, value, recurseTimes, keys[i], extrasType));
}
- throw err;
}
+ } catch (err) {
+ return handleMaxCallStackSize(ctx, err, constructor, tag);
}
- if (extra !== undefined)
- output.unshift(extra);
-
- for (i = 0; i < symbols.length; i++) {
- output.push(formatProperty(ctx, value, recurseTimes, symbols[i], 0));
- }
-
ctx.seen.pop();
return reduceToSingleString(ctx, output, base, braces);
}
+function handleMaxCallStackSize(ctx, err, constructor, tag) {
+ if (errors.isStackOverflowError(err)) {
+ ctx.seen.pop();
+ return ctx.stylize(
+ `[${constructor || tag || 'Object'}: Inspection interrupted ` +
+ 'prematurely. Maximum call stack size exceeded.]',
+ 'special'
+ );
+ }
+ throw err;
+}
+
function formatNumber(fn, value) {
// Format -0 as '-0'. Checking `value === -0` won't distinguish 0 from -0.
if (Object.is(value, -0))
@@ -935,20 +964,13 @@ function formatError(value) {
return value.stack || errorToString(value);
}
-function formatObject(ctx, value, recurseTimes, keys) {
- const len = keys.length;
- const output = new Array(len);
- for (var i = 0; i < len; i++)
- output[i] = formatProperty(ctx, value, recurseTimes, keys[i], 0);
- return output;
-}
-
function formatNamespaceObject(ctx, value, recurseTimes, keys) {
const len = keys.length;
const output = new Array(len);
for (var i = 0; i < len; i++) {
try {
- output[i] = formatProperty(ctx, value, recurseTimes, keys[i], 0);
+ output[i] = formatProperty(ctx, value, recurseTimes, keys[i],
+ kObjectType);
} catch (err) {
if (!(types.isNativeError(err) && err.name === 'ReferenceError')) {
throw err;
@@ -957,7 +979,7 @@ function formatNamespaceObject(ctx, value, recurseTimes, keys) {
// line breaks are always correct. Otherwise it is very difficult to keep
// this aligned, even though this is a hacky way of dealing with this.
const tmp = { [keys[i]]: '' };
- output[i] = formatProperty(ctx, tmp, recurseTimes, keys[i], 0);
+ output[i] = formatProperty(ctx, tmp, recurseTimes, keys[i], kObjectType);
const pos = output[i].lastIndexOf(' ');
// We have to find the last whitespace and have to replace that value as
// it will be visualized as a regular string.
@@ -969,91 +991,67 @@ function formatNamespaceObject(ctx, value, recurseTimes, keys) {
}
// The array is sparse and/or has extra keys
-function formatSpecialArray(ctx, value, recurseTimes, keys, maxLength, valLen) {
- const output = [];
- const keyLen = keys.length;
- let i = 0;
- for (const key of keys) {
- if (output.length === maxLength)
- break;
- const index = +key;
+function formatSpecialArray(ctx, value, recurseTimes, maxLength, output, i) {
+ const keys = Object.keys(value);
+ let index = i;
+ for (; i < keys.length && output.length < maxLength; i++) {
+ const key = keys[i];
+ const tmp = +key;
// Arrays can only have up to 2^32 - 1 entries
- if (index > 2 ** 32 - 2)
+ if (tmp > 2 ** 32 - 2) {
break;
- if (`${i}` !== key) {
- if (!numberRegExp.test(key))
+ }
+ if (`${index}` !== key) {
+ if (!numberRegExp.test(key)) {
break;
- const emptyItems = index - i;
+ }
+ const emptyItems = tmp - index;
const ending = emptyItems > 1 ? 's' : '';
const message = `<${emptyItems} empty item${ending}>`;
output.push(ctx.stylize(message, 'undefined'));
- i = index;
- if (output.length === maxLength)
+ index = tmp;
+ if (output.length === maxLength) {
break;
+ }
}
- output.push(formatProperty(ctx, value, recurseTimes, key, 1));
- i++;
- }
- if (i < valLen && output.length !== maxLength) {
- const len = valLen - i;
- const ending = len > 1 ? 's' : '';
- const message = `<${len} empty item${ending}>`;
- output.push(ctx.stylize(message, 'undefined'));
- i = valLen;
- if (keyLen === 0)
- return output;
- }
- const remaining = valLen - i;
- if (remaining > 0) {
- output.push(`... ${remaining} more item${remaining > 1 ? 's' : ''}`);
- }
- if (ctx.showHidden && keys[keyLen - 1] === 'length') {
- // No extra keys
- output.push(formatProperty(ctx, value, recurseTimes, 'length', 2));
- } else if (valLen === 0 ||
- keyLen > valLen && keys[valLen - 1] === `${valLen - 1}`) {
- // The array is not sparse
- for (i = valLen; i < keyLen; i++)
- output.push(formatProperty(ctx, value, recurseTimes, keys[i], 2));
- } else if (keys[keyLen - 1] !== `${valLen - 1}`) {
- const extra = [];
- // Only handle special keys
- let key;
- for (i = keys.length - 1; i >= 0; i--) {
- key = keys[i];
- if (numberRegExp.test(key) && +key < 2 ** 32 - 1)
- break;
- extra.push(formatProperty(ctx, value, recurseTimes, key, 2));
+ output.push(formatProperty(ctx, value, recurseTimes, key, kArrayType));
+ index++;
+ }
+ const remaining = value.length - index;
+ if (output.length !== maxLength) {
+ if (remaining > 0) {
+ const ending = remaining > 1 ? 's' : '';
+ const message = `<${remaining} empty item${ending}>`;
+ output.push(ctx.stylize(message, 'undefined'));
}
- for (i = extra.length - 1; i >= 0; i--)
- output.push(extra[i]);
+ } else if (remaining > 0) {
+ output.push(`... ${remaining} more item${remaining > 1 ? 's' : ''}`);
}
return output;
}
-function formatArray(ctx, value, recurseTimes, keys) {
- const len = Math.min(Math.max(0, ctx.maxArrayLength), value.length);
- const hidden = ctx.showHidden ? 1 : 0;
+function formatArray(ctx, value, recurseTimes) {
const valLen = value.length;
- const keyLen = keys.length - hidden;
- if (keyLen !== valLen || keys[keyLen - 1] !== `${valLen - 1}`)
- return formatSpecialArray(ctx, value, recurseTimes, keys, len, valLen);
+ const len = Math.min(Math.max(0, ctx.maxArrayLength), valLen);
const remaining = valLen - len;
- const output = new Array(len + (remaining > 0 ? 1 : 0) + hidden);
- for (var i = 0; i < len; i++)
- output[i] = formatProperty(ctx, value, recurseTimes, keys[i], 1);
+ const output = [];
+ for (var i = 0; i < len; i++) {
+ // Special handle sparse arrays.
+ if (!hasOwnProperty(value, i)) {
+ return formatSpecialArray(ctx, value, recurseTimes, len, output, i);
+ }
+ output.push(formatProperty(ctx, value, recurseTimes, i, kArrayType));
+ }
if (remaining > 0)
- output[i++] = `... ${remaining} more item${remaining > 1 ? 's' : ''}`;
- if (ctx.showHidden === true)
- output[i] = formatProperty(ctx, value, recurseTimes, 'length', 2);
+ output.push(`... ${remaining} more item${remaining > 1 ? 's' : ''}`);
return output;
}
-function formatTypedArray(ctx, value, recurseTimes, keys) {
+function formatTypedArray(ctx, value, recurseTimes) {
const maxLength = Math.min(Math.max(0, ctx.maxArrayLength), value.length);
const remaining = value.length - maxLength;
- const output = new Array(maxLength + (remaining > 0 ? 1 : 0));
+ const output = new Array(maxLength);
const elementFormatter = value.length > 0 && typeof value[0] === 'number' ?
formatNumber :
formatBigInt;
@@ -1076,52 +1074,39 @@ function formatTypedArray(ctx, value, recurseTimes, keys) {
}
ctx.indentationLvl -= 2;
}
- // TypedArrays cannot have holes. Therefore it is safe to assume that all
- // extra keys are indexed after value.length.
- for (i = value.length; i < keys.length; i++) {
- output.push(formatProperty(ctx, value, recurseTimes, keys[i], 2));
- }
return output;
}
-function formatSet(ctx, value, recurseTimes, keys) {
- const output = new Array(value.size + keys.length + (ctx.showHidden ? 1 : 0));
- let i = 0;
+function formatSet(ctx, value, recurseTimes) {
+ const output = [];
ctx.indentationLvl += 2;
for (const v of value) {
- output[i++] = formatValue(ctx, v, recurseTimes);
+ output.push(formatValue(ctx, v, recurseTimes));
}
ctx.indentationLvl -= 2;
// With `showHidden`, `length` will display as a hidden property for
// arrays. For consistency's sake, do the same for `size`, even though this
// property isn't selected by Object.getOwnPropertyNames().
if (ctx.showHidden)
- output[i++] = `[size]: ${ctx.stylize(`${value.size}`, 'number')}`;
- for (var n = 0; n < keys.length; n++) {
- output[i++] = formatProperty(ctx, value, recurseTimes, keys[n], 0);
- }
+ output.push(`[size]: ${ctx.stylize(`${value.size}`, 'number')}`);
return output;
}
-function formatMap(ctx, value, recurseTimes, keys) {
- const output = new Array(value.size + keys.length + (ctx.showHidden ? 1 : 0));
- let i = 0;
+function formatMap(ctx, value, recurseTimes) {
+ const output = [];
ctx.indentationLvl += 2;
for (const [k, v] of value) {
- output[i++] = `${formatValue(ctx, k, recurseTimes)} => ` +
- formatValue(ctx, v, recurseTimes);
+ output.push(`${formatValue(ctx, k, recurseTimes)} => ` +
+ formatValue(ctx, v, recurseTimes));
}
ctx.indentationLvl -= 2;
// See comment in formatSet
if (ctx.showHidden)
- output[i++] = `[size]: ${ctx.stylize(`${value.size}`, 'number')}`;
- for (var n = 0; n < keys.length; n++) {
- output[i++] = formatProperty(ctx, value, recurseTimes, keys[n], 0);
- }
+ output.push(`[size]: ${ctx.stylize(`${value.size}`, 'number')}`);
return output;
}
-function formatSetIterInner(ctx, value, recurseTimes, keys, entries, state) {
+function formatSetIterInner(ctx, recurseTimes, entries, state) {
const maxArrayLength = Math.max(ctx.maxArrayLength, 0);
const maxLength = Math.min(maxArrayLength, entries.length);
let output = new Array(maxLength);
@@ -1139,12 +1124,10 @@ function formatSetIterInner(ctx, value, recurseTimes, keys, entries, state) {
if (remaining > 0) {
output.push(`... ${remaining} more item${remaining > 1 ? 's' : ''}`);
}
- for (i = 0; i < keys.length; i++)
- output.push(formatProperty(ctx, value, recurseTimes, keys[i], 0));
return output;
}
-function formatMapIterInner(ctx, value, recurseTimes, keys, entries, state) {
+function formatMapIterInner(ctx, recurseTimes, entries, state) {
const maxArrayLength = Math.max(ctx.maxArrayLength, 0);
// Entries exist as [key1, val1, key2, val2, ...]
const len = entries.length / 2;
@@ -1175,37 +1158,38 @@ function formatMapIterInner(ctx, value, recurseTimes, keys, entries, state) {
if (remaining > 0) {
output.push(`... ${remaining} more item${remaining > 1 ? 's' : ''}`);
}
- for (i = 0; i < keys.length; i++)
- output.push(formatProperty(ctx, value, recurseTimes, keys[i], 0));
return output;
}
-function formatWeakSet(ctx, value, recurseTimes, keys) {
+function formatWeakCollection(ctx) {
+ return [ctx.stylize('<items unknown>', 'special')];
+}
+
+function formatWeakSet(ctx, value, recurseTimes) {
const entries = previewEntries(value);
- return formatSetIterInner(ctx, value, recurseTimes, keys, entries, kWeak);
+ return formatSetIterInner(ctx, recurseTimes, entries, kWeak);
}
-function formatWeakMap(ctx, value, recurseTimes, keys) {
+function formatWeakMap(ctx, value, recurseTimes) {
const entries = previewEntries(value);
- return formatMapIterInner(ctx, value, recurseTimes, keys, entries, kWeak);
+ return formatMapIterInner(ctx, recurseTimes, entries, kWeak);
}
-function formatSetIterator(ctx, value, recurseTimes, keys) {
+function formatSetIterator(ctx, value, recurseTimes) {
const entries = previewEntries(value);
- return formatSetIterInner(ctx, value, recurseTimes, keys, entries, kIterator);
+ return formatSetIterInner(ctx, recurseTimes, entries, kIterator);
}
-function formatMapIterator(ctx, value, recurseTimes, keys) {
+function formatMapIterator(ctx, value, recurseTimes) {
const [entries, isKeyValue] = previewEntries(value, true);
if (isKeyValue) {
- return formatMapIterInner(
- ctx, value, recurseTimes, keys, entries, kMapEntries);
+ return formatMapIterInner(ctx, recurseTimes, entries, kMapEntries);
}
- return formatSetIterInner(ctx, value, recurseTimes, keys, entries, kIterator);
+ return formatSetIterInner(ctx, recurseTimes, entries, kIterator);
}
-function formatPromise(ctx, value, recurseTimes, keys) {
+function formatPromise(ctx, value, recurseTimes) {
let output;
const [state, result] = getPromiseDetails(value);
if (state === kPending) {
@@ -1222,19 +1206,16 @@ function formatPromise(ctx, value, recurseTimes, keys) {
str
];
}
- for (var n = 0; n < keys.length; n++) {
- output.push(formatProperty(ctx, value, recurseTimes, keys[n], 0));
- }
return output;
}
-function formatProperty(ctx, value, recurseTimes, key, array) {
+function formatProperty(ctx, value, recurseTimes, key, type) {
let name, str;
let extra = ' ';
const desc = Object.getOwnPropertyDescriptor(value, key) ||
{ value: value[key], enumerable: true };
if (desc.value !== undefined) {
- const diff = array !== 0 || ctx.compact === false ? 2 : 3;
+ const diff = (type !== kObjectType || ctx.compact === false) ? 2 : 3;
ctx.indentationLvl += diff;
str = formatValue(ctx, desc.value, recurseTimes);
if (diff === 3) {
@@ -1255,7 +1236,7 @@ function formatProperty(ctx, value, recurseTimes, key, array) {
} else {
str = ctx.stylize('undefined', 'undefined');
}
- if (array === 1) {
+ if (type === kArrayType) {
return str;
}
if (typeof key === 'symbol') {
diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js
index b5ccdf019a..0994f26299 100644
--- a/test/parallel/test-util-inspect.js
+++ b/test/parallel/test-util-inspect.js
@@ -872,7 +872,7 @@ if (typeof Symbol !== 'undefined') {
const set = new Set(['foo']);
set.bar = 42;
assert.strictEqual(
- util.inspect(set, true),
+ util.inspect(set, { showHidden: true }),
"Set { 'foo', [size]: 1, bar: 42 }"
);
}