Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
console: implement minimal console.group()
Node.js exposes `console.group()` and `console.groupEnd()` via the
inspector. These functions have no apparent effect when called from
Node.js without the inspector. We cannot easily hide them when Node.js
is started without the inspector because we support opening the
inspector during runtime via `inspector.port()`.

Implement a minimal `console.group()`/`console.groupEnd()`. More
sophisticated implementations are possible, but they can be done in
userland and/or features can be added to this at a later time. (It lacks
the `label` argument to `console.group()` right now, for example. How to
handle `label`, or even whether to handle it,  may become
a bikeshed discussion. Landing a minimal implementation first avoids the
pitfall of that discussion or a similar discussion delaying the
implementation indefinitely.)

Refs: #12675
Fixes: #1716
  • Loading branch information
Trott committed Aug 22, 2017
commit 67516e14fbffe49c10afead8d0f8af6b5e9fd1e0
14 changes: 14 additions & 0 deletions doc/api/console.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,20 @@ If formatting elements (e.g. `%d`) are not found in the first string then
[`util.inspect()`][] is called on each argument and the resulting string
values are concatenated. See [`util.format()`][] for more information.

### console.group()
<!-- YAML
added: REPLACEME
-->

Increases indentation of subsequent lines by one tab (`\t`).

### console.groupEnd()
<!-- YAML
added: REPLACEME
-->

Decreases indentation of subsequent lines by one tab (`\t`).

### console.info([data][, ...args])
<!-- YAML
added: v0.1.100
Expand Down
19 changes: 16 additions & 3 deletions lib/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const errors = require('internal/errors');
const util = require('util');
const kCounts = Symbol('counts');

// Track amount of indentation required via `console.group()`.
const groupIndent = Symbol('groupIndent');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: kGroupIndent for consistency with the kCounts above.


function Console(stdout, stderr, ignoreErrors = true) {
if (!(this instanceof Console)) {
return new Console(stdout, stderr, ignoreErrors);
Expand Down Expand Up @@ -64,6 +67,8 @@ function Console(stdout, stderr, ignoreErrors = true) {
var k = keys[v];
this[k] = this[k].bind(this);
}

this[groupIndent] = '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally this should probably be "grouped" with kCounts above.

}

// Make a function that can serve as the callback passed to `stream.write()`.
Expand Down Expand Up @@ -111,7 +116,7 @@ function write(ignoreErrors, stream, string, errorhandler) {
Console.prototype.log = function log(...args) {
write(this._ignoreErrors,
this._stdout,
`${util.format.apply(null, args)}\n`,
`${this[groupIndent]}${util.format.apply(null, args)}\n`,
this._stdoutErrorHandler);
};

Expand All @@ -122,7 +127,7 @@ Console.prototype.info = Console.prototype.log;
Console.prototype.warn = function warn(...args) {
write(this._ignoreErrors,
this._stderr,
`${util.format.apply(null, args)}\n`,
`${this[groupIndent]}${util.format.apply(null, args)}\n`,
this._stderrErrorHandler);
};

Expand All @@ -134,7 +139,7 @@ Console.prototype.dir = function dir(object, options) {
options = Object.assign({ customInspect: false }, options);
write(this._ignoreErrors,
this._stdout,
`${util.inspect(object, options)}\n`,
`${this[groupIndent]}${util.inspect(object, options)}\n`,
this._stdoutErrorHandler);
};

Expand Down Expand Up @@ -214,6 +219,14 @@ Console.prototype.countReset = function countReset(label = 'default') {
counts.delete(`${label}`);
};

Console.prototype.group = function group() {
this[groupIndent] += ' ';
};

Console.prototype.groupEnd = function groupEnd() {
this[groupIndent] = this[groupIndent].slice(0, this[groupIndent].length - 2);
};

module.exports = new Console(process.stdout, process.stderr);
module.exports.Console = Console;

Expand Down
76 changes: 76 additions & 0 deletions test/parallel/test-console-group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use strict';
const common = require('../common');

const assert = require('assert');
const Console = require('console').Console;

let stdout, stderr;

function setup() {
stdout = '';
common.hijackStdout(function(data) {
stdout += data;
});

stderr = '';
common.hijackStderr(function(data) {
stderr += data;
});
}

function teardown() {
common.restoreStdout();
common.restoreStderr();
}

{
setup();
const expectedOut = 'This is the outer level\n' +
' Level 2\n' +
' Level 3\n' +
' Back to level 2\n' +
'Back to the outer level\n' +
'Still at the outer level\n';


const expectedErr = ' More of level 3\n';

console.log('This is the outer level');
console.group();
console.log('Level 2');
console.group();
console.log('Level 3');
console.warn('More of level 3');
console.groupEnd();
console.log('Back to level 2');
console.groupEnd();
console.log('Back to the outer level');
console.groupEnd();
console.log('Still at the outer level');

assert.strictEqual(stdout, expectedOut);
assert.strictEqual(stderr, expectedErr);
teardown();
}

// Group indentation is tracked per Console instance.
{
setup();
const expectedOut = 'No indentation\n' +
'None here either\n' +
' Now the first console is indenting\n' +
'But the second one does not\n';
const expectedErr = '';

const c1 = new Console(process.stdout, process.stderr);
const c2 = new Console(process.stdout, process.stderr);
c1.log('No indentation');
c2.log('None here either');
c1.group();
c1.log('Now the first console is indenting');
c2.log('But the second one does not');

assert.strictEqual(stdout, expectedOut);
assert.strictEqual(stderr, expectedErr);
teardown();
}