Skip to content

Commit

Permalink
console: implement minimal console.group()
Browse files Browse the repository at this point in the history
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: nodejs#12675
Fixes: nodejs#1716
  • Loading branch information
Trott committed Aug 22, 2017
1 parent d348512 commit 67516e1
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 3 deletions.
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');

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] = '';
}

// 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();
}

0 comments on commit 67516e1

Please sign in to comment.