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
Prev Previous commit
Next Next commit
console: add console.count() and console.clear()
Both are simple utility functions defined by the WHATWG
console spec (https://console.spec.whatwg.org/).

PR-URL: #12678
Ref: #12675
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Daijiro Wachi <daijiro.wachi@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
  • Loading branch information
jasnell authored and MylesBorins committed Jan 16, 2018
commit 17fb9facbec427d0ffdaa94adaaa288be0a43c99
70 changes: 70 additions & 0 deletions doc/api/console.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,76 @@ console.assert(false, 'this message will print, but no error thrown');
console.log('this will also print');
```

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

When `stdout` is a TTY, calling `console.clear()` will attempt to clear the
TTY. When `stdout` is not a TTY, this method does nothing.

*Note*: The specific operation of `console.clear()` can vary across operating
systems and terminal types. For most Linux operating systems, `console.clear()`
operates similarly to the `clear` shell command. On Windows, `console.clear()`
will clear only the output in the current terminal viewport for the Node.js
binary.

### console.count([label])
<!-- YAML
added: REPLACEME
-->

* `label` {string} The display label for the counter. Defaults to `'default'`.

Maintains an internal counter specific to `label` and outputs to `stdout` the
number of times `console.count()` has been called with the given `label`.

<!-- eslint-skip -->
```js
> console.count()
default: 1
undefined
> console.count('default')
default: 2
undefined
> console.count('abc')
abc: 1
undefined
> console.count('xyz')
xyz: 1
undefined
> console.count('abc')
abc: 2
undefined
> console.count()
default: 3
undefined
>
```

### console.countReset([label = 'default'])
<!-- YAML
added: REPLACEME
-->

* `label` {string} The display label for the counter. Defaults to `'default'`.

Resets the internal counter specific to `label`.

<!-- eslint-skip -->
```js
> console.count('abc');
abc: 1
undefined
> console.countReset('abc');
undefined
> console.count('abc');
abc: 1
undefined
>
```
<!-- eslint-enable -->

### console.dir(obj[, options])
<!-- YAML
added: v0.1.101
Expand Down
39 changes: 39 additions & 0 deletions lib/console.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const util = require('util');
const kCounts = Symbol('counts');

function Console(stdout, stderr) {
if (!(this instanceof Console)) {
Expand All @@ -27,6 +28,8 @@ function Console(stdout, stderr) {
prop.value = new Map();
Object.defineProperty(this, '_times', prop);

this[kCounts] = new Map();

// bind the prototype functions to this Console instance
var keys = Object.keys(Console.prototype);
for (var v = 0; v < keys.length; v++) {
Expand Down Expand Up @@ -96,6 +99,42 @@ Console.prototype.assert = function(expression, ...args) {
}
};

// Defined by: https://console.spec.whatwg.org/#clear
Console.prototype.clear = function clear() {
// It only makes sense to clear if _stdout is a TTY.
// Otherwise, do nothing.
if (this._stdout.isTTY) {
// The require is here intentionally to avoid readline being
// required too early when console is first loaded.
const { cursorTo, clearScreenDown } = require('readline');
cursorTo(this._stdout, 0, 0);
clearScreenDown(this._stdout);
}
};

// Defined by: https://console.spec.whatwg.org/#count
Console.prototype.count = function count(label = 'default') {
// Ensures that label is a string, and only things that can be
// coerced to strings. e.g. Symbol is not allowed
label = `${label}`;
const counts = this[kCounts];
let count = counts.get(label);
if (count === undefined)
count = 1;
else
count++;
counts.set(label, count);
this.log(`${label}: ${count}`);
};

// Not yet defined by the https://console.spec.whatwg.org, but
// proposed to be added and currently implemented by Edge. Having
// the ability to reset counters is important to help prevent
// the counter from being a memory leak.
Console.prototype.countReset = function countReset(label = 'default') {
const counts = this[kCounts];
counts.delete(`${label}`);
};

module.exports = new Console(process.stdout, process.stderr);
module.exports.Console = Console;
22 changes: 22 additions & 0 deletions test/parallel/test-console-clear.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

require('../common');
const assert = require('assert');

const stdoutWrite = process.stdout.write;

// The sequence for moving the cursor to 0,0 and clearing screen down
const check = '\u001b[1;1H\u001b[0J';

function doTest(isTTY, check) {
let buf = '';
process.stdout.isTTY = isTTY;
process.stdout.write = (string) => buf += string;
console.clear();
process.stdout.write = stdoutWrite;
assert.strictEqual(buf, check);
}

// Fake TTY
doTest(true, check);
doTest(false, '');
63 changes: 63 additions & 0 deletions test/parallel/test-console-count.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use strict';

require('../common');
const assert = require('assert');

const stdoutWrite = process.stdout.write;

let buf = '';

process.stdout.write = (string) => buf = string;

console.count();
assert.strictEqual(buf, 'default: 1\n');

// 'default' and undefined are equivalent
console.count('default');
assert.strictEqual(buf, 'default: 2\n');

console.count('a');
assert.strictEqual(buf, 'a: 1\n');

console.count('b');
assert.strictEqual(buf, 'b: 1\n');

console.count('a');
assert.strictEqual(buf, 'a: 2\n');

console.count();
assert.strictEqual(buf, 'default: 3\n');

console.count({});
assert.strictEqual(buf, '[object Object]: 1\n');

console.count(1);
assert.strictEqual(buf, '1: 1\n');

console.count(null);
assert.strictEqual(buf, 'null: 1\n');

console.count('null');
assert.strictEqual(buf, 'null: 2\n');

console.countReset();
console.count();
assert.strictEqual(buf, 'default: 1\n');

console.countReset('a');
console.count('a');
assert.strictEqual(buf, 'a: 1\n');

// countReset('a') only reset the a counter
console.count();
assert.strictEqual(buf, 'default: 2\n');

process.stdout.write = stdoutWrite;

// Symbol labels do not work
assert.throws(
() => console.count(Symbol('test')),
/^TypeError: Cannot convert a Symbol value to a string$/);
assert.throws(
() => console.countReset(Symbol('test')),
/^TypeError: Cannot convert a Symbol value to a string$/);