Skip to content

Commit ce13639

Browse files
jasnellMylesBorins
authored andcommitted
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 <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Daijiro Wachi <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
1 parent 3b9fea0 commit ce13639

File tree

4 files changed

+194
-0
lines changed

4 files changed

+194
-0
lines changed

doc/api/console.md

+70
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,76 @@ console.assert(false, 'this message will print, but no error thrown');
155155
console.log('this will also print');
156156
```
157157

158+
### console.clear()
159+
<!-- YAML
160+
added: REPLACEME
161+
-->
162+
163+
When `stdout` is a TTY, calling `console.clear()` will attempt to clear the
164+
TTY. When `stdout` is not a TTY, this method does nothing.
165+
166+
*Note*: The specific operation of `console.clear()` can vary across operating
167+
systems and terminal types. For most Linux operating systems, `console.clear()`
168+
operates similarly to the `clear` shell command. On Windows, `console.clear()`
169+
will clear only the output in the current terminal viewport for the Node.js
170+
binary.
171+
172+
### console.count([label])
173+
<!-- YAML
174+
added: REPLACEME
175+
-->
176+
177+
* `label` {string} The display label for the counter. Defaults to `'default'`.
178+
179+
Maintains an internal counter specific to `label` and outputs to `stdout` the
180+
number of times `console.count()` has been called with the given `label`.
181+
182+
<!-- eslint-skip -->
183+
```js
184+
> console.count()
185+
default: 1
186+
undefined
187+
> console.count('default')
188+
default: 2
189+
undefined
190+
> console.count('abc')
191+
abc: 1
192+
undefined
193+
> console.count('xyz')
194+
xyz: 1
195+
undefined
196+
> console.count('abc')
197+
abc: 2
198+
undefined
199+
> console.count()
200+
default: 3
201+
undefined
202+
>
203+
```
204+
205+
### console.countReset([label = 'default'])
206+
<!-- YAML
207+
added: REPLACEME
208+
-->
209+
210+
* `label` {string} The display label for the counter. Defaults to `'default'`.
211+
212+
Resets the internal counter specific to `label`.
213+
214+
<!-- eslint-skip -->
215+
```js
216+
> console.count('abc');
217+
abc: 1
218+
undefined
219+
> console.countReset('abc');
220+
undefined
221+
> console.count('abc');
222+
abc: 1
223+
undefined
224+
>
225+
```
226+
<!-- eslint-enable -->
227+
158228
### console.dir(obj[, options])
159229
<!-- YAML
160230
added: v0.1.101

lib/console.js

+39
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const util = require('util');
4+
const kCounts = Symbol('counts');
45

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

31+
this[kCounts] = new Map();
32+
3033
// bind the prototype functions to this Console instance
3134
var keys = Object.keys(Console.prototype);
3235
for (var v = 0; v < keys.length; v++) {
@@ -96,6 +99,42 @@ Console.prototype.assert = function(expression, ...args) {
9699
}
97100
};
98101

102+
// Defined by: https://console.spec.whatwg.org/#clear
103+
Console.prototype.clear = function clear() {
104+
// It only makes sense to clear if _stdout is a TTY.
105+
// Otherwise, do nothing.
106+
if (this._stdout.isTTY) {
107+
// The require is here intentionally to avoid readline being
108+
// required too early when console is first loaded.
109+
const { cursorTo, clearScreenDown } = require('readline');
110+
cursorTo(this._stdout, 0, 0);
111+
clearScreenDown(this._stdout);
112+
}
113+
};
114+
115+
// Defined by: https://console.spec.whatwg.org/#count
116+
Console.prototype.count = function count(label = 'default') {
117+
// Ensures that label is a string, and only things that can be
118+
// coerced to strings. e.g. Symbol is not allowed
119+
label = `${label}`;
120+
const counts = this[kCounts];
121+
let count = counts.get(label);
122+
if (count === undefined)
123+
count = 1;
124+
else
125+
count++;
126+
counts.set(label, count);
127+
this.log(`${label}: ${count}`);
128+
};
129+
130+
// Not yet defined by the https://console.spec.whatwg.org, but
131+
// proposed to be added and currently implemented by Edge. Having
132+
// the ability to reset counters is important to help prevent
133+
// the counter from being a memory leak.
134+
Console.prototype.countReset = function countReset(label = 'default') {
135+
const counts = this[kCounts];
136+
counts.delete(`${label}`);
137+
};
99138

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

test/parallel/test-console-clear.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict';
2+
3+
require('../common');
4+
const assert = require('assert');
5+
6+
const stdoutWrite = process.stdout.write;
7+
8+
// The sequence for moving the cursor to 0,0 and clearing screen down
9+
const check = '\u001b[1;1H\u001b[0J';
10+
11+
function doTest(isTTY, check) {
12+
let buf = '';
13+
process.stdout.isTTY = isTTY;
14+
process.stdout.write = (string) => buf += string;
15+
console.clear();
16+
process.stdout.write = stdoutWrite;
17+
assert.strictEqual(buf, check);
18+
}
19+
20+
// Fake TTY
21+
doTest(true, check);
22+
doTest(false, '');

test/parallel/test-console-count.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
'use strict';
2+
3+
require('../common');
4+
const assert = require('assert');
5+
6+
const stdoutWrite = process.stdout.write;
7+
8+
let buf = '';
9+
10+
process.stdout.write = (string) => buf = string;
11+
12+
console.count();
13+
assert.strictEqual(buf, 'default: 1\n');
14+
15+
// 'default' and undefined are equivalent
16+
console.count('default');
17+
assert.strictEqual(buf, 'default: 2\n');
18+
19+
console.count('a');
20+
assert.strictEqual(buf, 'a: 1\n');
21+
22+
console.count('b');
23+
assert.strictEqual(buf, 'b: 1\n');
24+
25+
console.count('a');
26+
assert.strictEqual(buf, 'a: 2\n');
27+
28+
console.count();
29+
assert.strictEqual(buf, 'default: 3\n');
30+
31+
console.count({});
32+
assert.strictEqual(buf, '[object Object]: 1\n');
33+
34+
console.count(1);
35+
assert.strictEqual(buf, '1: 1\n');
36+
37+
console.count(null);
38+
assert.strictEqual(buf, 'null: 1\n');
39+
40+
console.count('null');
41+
assert.strictEqual(buf, 'null: 2\n');
42+
43+
console.countReset();
44+
console.count();
45+
assert.strictEqual(buf, 'default: 1\n');
46+
47+
console.countReset('a');
48+
console.count('a');
49+
assert.strictEqual(buf, 'a: 1\n');
50+
51+
// countReset('a') only reset the a counter
52+
console.count();
53+
assert.strictEqual(buf, 'default: 2\n');
54+
55+
process.stdout.write = stdoutWrite;
56+
57+
// Symbol labels do not work
58+
assert.throws(
59+
() => console.count(Symbol('test')),
60+
/^TypeError: Cannot convert a Symbol value to a string$/);
61+
assert.throws(
62+
() => console.countReset(Symbol('test')),
63+
/^TypeError: Cannot convert a Symbol value to a string$/);

0 commit comments

Comments
 (0)