console: add table method

PR-URL: https://github.com/nodejs/node/pull/18137
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
This commit is contained in:
Gus Caplan
2018-01-13 13:55:19 -06:00
parent 83d44bee01
commit 97ace04492
5 changed files with 449 additions and 1 deletions

View File

@@ -23,11 +23,31 @@
const {
isStackOverflowError,
codes: { ERR_CONSOLE_WRITABLE_STREAM },
codes: {
ERR_CONSOLE_WRITABLE_STREAM,
ERR_INVALID_ARG_TYPE,
},
} = require('internal/errors');
const { previewMapIterator, previewSetIterator } = require('internal/v8');
const { Buffer: { isBuffer } } = require('buffer');
const cliTable = require('internal/cli_table');
const util = require('util');
const {
isTypedArray, isSet, isMap, isSetIterator, isMapIterator,
} = util.types;
const kCounts = Symbol('counts');
const {
keys: ObjectKeys,
values: ObjectValues,
} = Object;
const hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);
const {
isArray: ArrayIsArray,
from: ArrayFrom,
} = Array;
// Track amount of indentation required via `console.group()`.
const kGroupIndent = Symbol('groupIndent');
@@ -242,6 +262,113 @@ Console.prototype.groupEnd = function groupEnd() {
this[kGroupIndent].slice(0, this[kGroupIndent].length - 2);
};
const keyKey = 'Key';
const valuesKey = 'Values';
const indexKey = '(index)';
const iterKey = '(iteration index)';
const isArray = (v) => ArrayIsArray(v) || isTypedArray(v) || isBuffer(v);
const inspect = (v) => {
const opt = { depth: 0, maxArrayLength: 3 };
if (v !== null && typeof v === 'object' &&
!isArray(v) && ObjectKeys(v).length > 2)
opt.depth = -1;
return util.inspect(v, opt);
};
const getIndexArray = (length) => ArrayFrom({ length }, (_, i) => inspect(i));
// https://console.spec.whatwg.org/#table
Console.prototype.table = function(tabularData, properties) {
if (properties !== undefined && !ArrayIsArray(properties))
throw new ERR_INVALID_ARG_TYPE('properties', 'Array', properties);
if (tabularData == null ||
(typeof tabularData !== 'object' && typeof tabularData !== 'function'))
return this.log(tabularData);
const final = (k, v) => this.log(cliTable(k, v));
const mapIter = isMapIterator(tabularData);
if (mapIter)
tabularData = previewMapIterator(tabularData);
if (mapIter || isMap(tabularData)) {
const keys = [];
const values = [];
let length = 0;
for (const [k, v] of tabularData) {
keys.push(inspect(k));
values.push(inspect(v));
length++;
}
return final([
iterKey, keyKey, valuesKey
], [
getIndexArray(length),
keys,
values,
]);
}
const setIter = isSetIterator(tabularData);
if (setIter)
tabularData = previewSetIterator(tabularData);
const setlike = setIter || isSet(tabularData);
if (setlike ||
(properties === undefined &&
(isArray(tabularData) || isTypedArray(tabularData)))) {
const values = [];
let length = 0;
for (const v of tabularData) {
values.push(inspect(v));
length++;
}
return final([setlike ? iterKey : indexKey, valuesKey], [
getIndexArray(length),
values,
]);
}
const map = {};
let hasPrimitives = false;
const valuesKeyArray = [];
const indexKeyArray = ObjectKeys(tabularData);
for (var i = 0; i < indexKeyArray.length; i++) {
const item = tabularData[indexKeyArray[i]];
const primitive = item === null ||
(typeof item !== 'function' && typeof item !== 'object');
if (properties === undefined && primitive) {
hasPrimitives = true;
valuesKeyArray[i] = inspect(item);
} else {
const keys = properties || ObjectKeys(item);
for (const key of keys) {
if (map[key] === undefined)
map[key] = [];
if ((primitive && properties) || !hasOwnProperty(item, key))
map[key][i] = '';
else
map[key][i] = item == null ? item : inspect(item[key]);
}
}
}
const keys = ObjectKeys(map);
const values = ObjectValues(map);
if (hasPrimitives) {
keys.push(valuesKey);
values.push(valuesKeyArray);
}
keys.unshift(indexKey);
values.unshift(indexKeyArray);
return final(keys, values);
};
module.exports = new Console(process.stdout, process.stderr);
module.exports.Console = Console;