|
23 | 23 |
|
24 | 24 | const {
|
25 | 25 | isStackOverflowError,
|
26 |
| - codes: { ERR_CONSOLE_WRITABLE_STREAM }, |
| 26 | + codes: { |
| 27 | + ERR_CONSOLE_WRITABLE_STREAM, |
| 28 | + ERR_INVALID_ARG_TYPE, |
| 29 | + }, |
27 | 30 | } = require('internal/errors');
|
| 31 | +const { previewMapIterator, previewSetIterator } = require('internal/v8'); |
| 32 | +const { Buffer: { isBuffer } } = require('buffer'); |
| 33 | +const cliTable = require('internal/cli_table'); |
28 | 34 | const util = require('util');
|
| 35 | +const { |
| 36 | + isTypedArray, isSet, isMap, isSetIterator, isMapIterator, |
| 37 | +} = util.types; |
29 | 38 | const kCounts = Symbol('counts');
|
30 | 39 |
|
| 40 | +const { |
| 41 | + keys: ObjectKeys, |
| 42 | + values: ObjectValues, |
| 43 | +} = Object; |
| 44 | +const hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty); |
| 45 | + |
| 46 | +const { |
| 47 | + isArray: ArrayIsArray, |
| 48 | + from: ArrayFrom, |
| 49 | +} = Array; |
| 50 | + |
31 | 51 | // Track amount of indentation required via `console.group()`.
|
32 | 52 | const kGroupIndent = Symbol('groupIndent');
|
33 | 53 |
|
@@ -242,6 +262,113 @@ Console.prototype.groupEnd = function groupEnd() {
|
242 | 262 | this[kGroupIndent].slice(0, this[kGroupIndent].length - 2);
|
243 | 263 | };
|
244 | 264 |
|
| 265 | +const keyKey = 'Key'; |
| 266 | +const valuesKey = 'Values'; |
| 267 | +const indexKey = '(index)'; |
| 268 | +const iterKey = '(iteration index)'; |
| 269 | + |
| 270 | + |
| 271 | +const isArray = (v) => ArrayIsArray(v) || isTypedArray(v) || isBuffer(v); |
| 272 | +const inspect = (v) => { |
| 273 | + const opt = { depth: 0, maxArrayLength: 3 }; |
| 274 | + if (v !== null && typeof v === 'object' && |
| 275 | + !isArray(v) && ObjectKeys(v).length > 2) |
| 276 | + opt.depth = -1; |
| 277 | + return util.inspect(v, opt); |
| 278 | +}; |
| 279 | + |
| 280 | +const getIndexArray = (length) => ArrayFrom({ length }, (_, i) => inspect(i)); |
| 281 | + |
| 282 | +// https://console.spec.whatwg.org/#table |
| 283 | +Console.prototype.table = function(tabularData, properties) { |
| 284 | + if (properties !== undefined && !ArrayIsArray(properties)) |
| 285 | + throw new ERR_INVALID_ARG_TYPE('properties', 'Array', properties); |
| 286 | + |
| 287 | + if (tabularData == null || |
| 288 | + (typeof tabularData !== 'object' && typeof tabularData !== 'function')) |
| 289 | + return this.log(tabularData); |
| 290 | + |
| 291 | + const final = (k, v) => this.log(cliTable(k, v)); |
| 292 | + |
| 293 | + const mapIter = isMapIterator(tabularData); |
| 294 | + if (mapIter) |
| 295 | + tabularData = previewMapIterator(tabularData); |
| 296 | + |
| 297 | + if (mapIter || isMap(tabularData)) { |
| 298 | + const keys = []; |
| 299 | + const values = []; |
| 300 | + let length = 0; |
| 301 | + for (const [k, v] of tabularData) { |
| 302 | + keys.push(inspect(k)); |
| 303 | + values.push(inspect(v)); |
| 304 | + length++; |
| 305 | + } |
| 306 | + return final([ |
| 307 | + iterKey, keyKey, valuesKey |
| 308 | + ], [ |
| 309 | + getIndexArray(length), |
| 310 | + keys, |
| 311 | + values, |
| 312 | + ]); |
| 313 | + } |
| 314 | + |
| 315 | + const setIter = isSetIterator(tabularData); |
| 316 | + if (setIter) |
| 317 | + tabularData = previewSetIterator(tabularData); |
| 318 | + |
| 319 | + const setlike = setIter || isSet(tabularData); |
| 320 | + if (setlike || |
| 321 | + (properties === undefined && |
| 322 | + (isArray(tabularData) || isTypedArray(tabularData)))) { |
| 323 | + const values = []; |
| 324 | + let length = 0; |
| 325 | + for (const v of tabularData) { |
| 326 | + values.push(inspect(v)); |
| 327 | + length++; |
| 328 | + } |
| 329 | + return final([setlike ? iterKey : indexKey, valuesKey], [ |
| 330 | + getIndexArray(length), |
| 331 | + values, |
| 332 | + ]); |
| 333 | + } |
| 334 | + |
| 335 | + const map = {}; |
| 336 | + let hasPrimitives = false; |
| 337 | + const valuesKeyArray = []; |
| 338 | + const indexKeyArray = ObjectKeys(tabularData); |
| 339 | + |
| 340 | + for (var i = 0; i < indexKeyArray.length; i++) { |
| 341 | + const item = tabularData[indexKeyArray[i]]; |
| 342 | + const primitive = item === null || |
| 343 | + (typeof item !== 'function' && typeof item !== 'object'); |
| 344 | + if (properties === undefined && primitive) { |
| 345 | + hasPrimitives = true; |
| 346 | + valuesKeyArray[i] = inspect(item); |
| 347 | + } else { |
| 348 | + const keys = properties || ObjectKeys(item); |
| 349 | + for (const key of keys) { |
| 350 | + if (map[key] === undefined) |
| 351 | + map[key] = []; |
| 352 | + if ((primitive && properties) || !hasOwnProperty(item, key)) |
| 353 | + map[key][i] = ''; |
| 354 | + else |
| 355 | + map[key][i] = item == null ? item : inspect(item[key]); |
| 356 | + } |
| 357 | + } |
| 358 | + } |
| 359 | + |
| 360 | + const keys = ObjectKeys(map); |
| 361 | + const values = ObjectValues(map); |
| 362 | + if (hasPrimitives) { |
| 363 | + keys.push(valuesKey); |
| 364 | + values.push(valuesKeyArray); |
| 365 | + } |
| 366 | + keys.unshift(indexKey); |
| 367 | + values.unshift(indexKeyArray); |
| 368 | + |
| 369 | + return final(keys, values); |
| 370 | +}; |
| 371 | + |
245 | 372 | module.exports = new Console(process.stdout, process.stderr);
|
246 | 373 | module.exports.Console = Console;
|
247 | 374 |
|
|
0 commit comments