console: mark special console properties as non-enumerable

This makes sure internal console properties are not visible during
default inspection. They are still visible when inspecting the
console with `showHidden` set to `true`.

These properties are confusing while working with the REPL and easily
show up.

Signed-off-by: Ruben Bridgewater <ruben@bridgewater.de>

PR-URL: https://github.com/nodejs/node/pull/33524
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anto Aravinth <anto.aravinth.cse@gmail.com>
This commit is contained in:
Ruben Bridgewater 2020-05-22 14:04:51 +02:00
parent b61249e32d
commit 87629d7e7c

View File

@ -155,68 +155,156 @@ ObjectDefineProperty(Console, SymbolHasInstance, {
} }
}); });
// Eager version for the Console constructor const kColorInspectOptions = { colors: true };
Console.prototype[kBindStreamsEager] = function(stdout, stderr) { const kNoColorInspectOptions = {};
ObjectDefineProperties(this, {
'_stdout': { ...consolePropAttributes, value: stdout },
'_stderr': { ...consolePropAttributes, value: stderr }
});
};
// Lazily load the stdout and stderr from an object so we don't ObjectDefineProperties(Console.prototype, {
// create the stdio streams when they are not even accessed [kBindStreamsEager]: {
Console.prototype[kBindStreamsLazy] = function(object) { ...consolePropAttributes,
let stdout; // Eager version for the Console constructor
let stderr; value: function(stdout, stderr) {
ObjectDefineProperties(this, { ObjectDefineProperties(this, {
'_stdout': { '_stdout': { ...consolePropAttributes, value: stdout },
enumerable: false, '_stderr': { ...consolePropAttributes, value: stderr }
configurable: true, });
get() {
if (!stdout) stdout = object.stdout;
return stdout;
},
set(value) { stdout = value; }
},
'_stderr': {
enumerable: false,
configurable: true,
get() {
if (!stderr) { stderr = object.stderr; }
return stderr;
},
set(value) { stderr = value; }
} }
}); },
}; [kBindStreamsLazy]: {
...consolePropAttributes,
// Lazily load the stdout and stderr from an object so we don't
// create the stdio streams when they are not even accessed
value: function(object) {
let stdout;
let stderr;
ObjectDefineProperties(this, {
'_stdout': {
enumerable: false,
configurable: true,
get() {
if (!stdout) stdout = object.stdout;
return stdout;
},
set(value) { stdout = value; }
},
'_stderr': {
enumerable: false,
configurable: true,
get() {
if (!stderr) { stderr = object.stderr; }
return stderr;
},
set(value) { stderr = value; }
}
});
}
},
[kBindProperties]: {
...consolePropAttributes,
value: function(ignoreErrors, colorMode, groupIndentation = 2) {
ObjectDefineProperties(this, {
'_stdoutErrorHandler': {
...consolePropAttributes,
value: createWriteErrorHandler(this, kUseStdout)
},
'_stderrErrorHandler': {
...consolePropAttributes,
value: createWriteErrorHandler(this, kUseStderr)
},
'_ignoreErrors': {
...consolePropAttributes,
value: Boolean(ignoreErrors)
},
'_times': { ...consolePropAttributes, value: new Map() },
// Corresponds to https://console.spec.whatwg.org/#count-map
[kCounts]: { ...consolePropAttributes, value: new Map() },
[kColorMode]: { ...consolePropAttributes, value: colorMode },
[kIsConsole]: { ...consolePropAttributes, value: true },
[kGroupIndent]: { ...consolePropAttributes, value: '' },
[kGroupIndentationWidth]: {
...consolePropAttributes,
value: groupIndentation
},
});
}
},
[kWriteToConsole]: {
...consolePropAttributes,
value: function(streamSymbol, string) {
const ignoreErrors = this._ignoreErrors;
const groupIndent = this[kGroupIndent];
Console.prototype[kBindProperties] = function(ignoreErrors, colorMode, const useStdout = streamSymbol === kUseStdout;
groupIndentation = 2) { const stream = useStdout ? this._stdout : this._stderr;
ObjectDefineProperties(this, { const errorHandler = useStdout ?
'_stdoutErrorHandler': { this._stdoutErrorHandler : this._stderrErrorHandler;
...consolePropAttributes,
value: createWriteErrorHandler(this, kUseStdout) if (groupIndent.length !== 0) {
}, if (string.includes('\n')) {
'_stderrErrorHandler': { string = string.replace(/\n/g, `\n${groupIndent}`);
...consolePropAttributes, }
value: createWriteErrorHandler(this, kUseStderr) string = groupIndent + string;
}, }
'_ignoreErrors': { string += '\n';
...consolePropAttributes,
value: Boolean(ignoreErrors) if (ignoreErrors === false) return stream.write(string);
},
'_times': { ...consolePropAttributes, value: new Map() }, // There may be an error occurring synchronously (e.g. for files or TTYs
// Corresponds to https://console.spec.whatwg.org/#count-map // on POSIX systems) or asynchronously (e.g. pipes on POSIX systems), so
[kCounts]: { ...consolePropAttributes, value: new Map() }, // handle both situations.
[kColorMode]: { ...consolePropAttributes, value: colorMode }, try {
[kIsConsole]: { ...consolePropAttributes, value: true }, // Add and later remove a noop error handler to catch synchronous
[kGroupIndent]: { ...consolePropAttributes, value: '' }, // errors.
[kGroupIndentationWidth]: { if (stream.listenerCount('error') === 0)
...consolePropAttributes, stream.once('error', noop);
value: groupIndentation
}, stream.write(string, errorHandler);
}); } catch (e) {
}; // Console is a debugging utility, so it swallowing errors is not
// desirable even in edge cases such as low stack space.
if (isStackOverflowError(e))
throw e;
// Sorry, there's no proper way to pass along the error here.
} finally {
stream.removeListener('error', noop);
}
}
},
[kGetInspectOptions]: {
...consolePropAttributes,
value: function(stream) {
let color = this[kColorMode];
if (color === 'auto') {
color = stream.isTTY && (
typeof stream.getColorDepth === 'function' ?
stream.getColorDepth() > 2 : true);
}
const options = optionsMap.get(this);
if (options) {
if (options.colors === undefined) {
options.colors = color;
}
return options;
}
return color ? kColorInspectOptions : kNoColorInspectOptions;
}
},
[kFormatForStdout]: {
...consolePropAttributes,
value: function(args) {
const opts = this[kGetInspectOptions](this._stdout);
return formatWithOptions(opts, ...args);
}
},
[kFormatForStderr]: {
...consolePropAttributes,
value: function(args) {
const opts = this[kGetInspectOptions](this._stderr);
return formatWithOptions(opts, ...args);
}
},
});
// Make a function that can serve as the callback passed to `stream.write()`. // Make a function that can serve as the callback passed to `stream.write()`.
function createWriteErrorHandler(instance, streamSymbol) { function createWriteErrorHandler(instance, streamSymbol) {
@ -239,76 +327,6 @@ function createWriteErrorHandler(instance, streamSymbol) {
}; };
} }
Console.prototype[kWriteToConsole] = function(streamSymbol, string) {
const ignoreErrors = this._ignoreErrors;
const groupIndent = this[kGroupIndent];
const useStdout = streamSymbol === kUseStdout;
const stream = useStdout ? this._stdout : this._stderr;
const errorHandler = useStdout ?
this._stdoutErrorHandler : this._stderrErrorHandler;
if (groupIndent.length !== 0) {
if (string.includes('\n')) {
string = string.replace(/\n/g, `\n${groupIndent}`);
}
string = groupIndent + string;
}
string += '\n';
if (ignoreErrors === false) return stream.write(string);
// There may be an error occurring synchronously (e.g. for files or TTYs
// on POSIX systems) or asynchronously (e.g. pipes on POSIX systems), so
// handle both situations.
try {
// Add and later remove a noop error handler to catch synchronous errors.
if (stream.listenerCount('error') === 0)
stream.once('error', noop);
stream.write(string, errorHandler);
} catch (e) {
// Console is a debugging utility, so it swallowing errors is not desirable
// even in edge cases such as low stack space.
if (isStackOverflowError(e))
throw e;
// Sorry, there's no proper way to pass along the error here.
} finally {
stream.removeListener('error', noop);
}
};
const kColorInspectOptions = { colors: true };
const kNoColorInspectOptions = {};
Console.prototype[kGetInspectOptions] = function(stream) {
let color = this[kColorMode];
if (color === 'auto') {
color = stream.isTTY && (
typeof stream.getColorDepth === 'function' ?
stream.getColorDepth() > 2 : true);
}
const options = optionsMap.get(this);
if (options) {
if (options.colors === undefined) {
options.colors = color;
}
return options;
}
return color ? kColorInspectOptions : kNoColorInspectOptions;
};
Console.prototype[kFormatForStdout] = function(args) {
const opts = this[kGetInspectOptions](this._stdout);
return formatWithOptions(opts, ...args);
};
Console.prototype[kFormatForStderr] = function(args) {
const opts = this[kGetInspectOptions](this._stderr);
return formatWithOptions(opts, ...args);
};
const consoleMethods = { const consoleMethods = {
log(...args) { log(...args) {
this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args)); this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args));