Skip to content
Permalink
Browse files

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 addaleax committed Apr 26, 2017
1 parent 91b7843 commit 9c1199e88f7eb9209594daa1d9e10be0793fbcde
Showing with 194 additions and 0 deletions.
  1. +70 −0 doc/api/console.md
  2. +39 −0 lib/console.js
  3. +22 −0 test/parallel/test-console-clear.js
  4. +63 −0 test/parallel/test-console-count.js
@@ -167,6 +167,76 @@ console.assert(false, 'this message will print, but no error thrown');
console.log('this will also print'); 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]) ### console.dir(obj[, options])
<!-- YAML <!-- YAML
added: v0.1.101 added: v0.1.101
@@ -22,6 +22,7 @@
'use strict'; 'use strict';


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


function Console(stdout, stderr, ignoreErrors = true) { function Console(stdout, stderr, ignoreErrors = true) {
if (!(this instanceof Console)) { if (!(this instanceof Console)) {
@@ -54,6 +55,8 @@ function Console(stdout, stderr, ignoreErrors = true) {
prop.value = createWriteErrorHandler(stderr); prop.value = createWriteErrorHandler(stderr);
Object.defineProperty(this, '_stderrErrorHandler', prop); Object.defineProperty(this, '_stderrErrorHandler', prop);


this[kCounts] = new Map();

// bind the prototype functions to this Console instance // bind the prototype functions to this Console instance
var keys = Object.keys(Console.prototype); var keys = Object.keys(Console.prototype);
for (var v = 0; v < keys.length; v++) { for (var v = 0; v < keys.length; v++) {
@@ -165,6 +168,42 @@ Console.prototype.assert = function assert(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 = new Console(process.stdout, process.stderr);
module.exports.Console = Console; module.exports.Console = Console;
@@ -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, '');
@@ -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$/);

0 comments on commit 9c1199e

Please sign in to comment.
You can’t perform that action at this time.