Skip to content
Closed
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: 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>
  • Loading branch information
BridgeAR committed May 23, 2020
commit 60b8282518cf6220cae2ae7f16351d6cabf21b89
276 changes: 147 additions & 129 deletions lib/internal/console/constructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,68 +155,156 @@ ObjectDefineProperty(Console, SymbolHasInstance, {
}
});

// Eager version for the Console constructor
Console.prototype[kBindStreamsEager] = function(stdout, stderr) {
ObjectDefineProperties(this, {
'_stdout': { ...consolePropAttributes, value: stdout },
'_stderr': { ...consolePropAttributes, value: stderr }
});
};
const kColorInspectOptions = { colors: true };
const kNoColorInspectOptions = {};

// Lazily load the stdout and stderr from an object so we don't
// create the stdio streams when they are not even accessed
Console.prototype[kBindStreamsLazy] = 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; }
ObjectDefineProperties(Console.prototype, {
[kBindStreamsEager]: {
...consolePropAttributes,
// Eager version for the Console constructor
value: function(stdout, stderr) {
ObjectDefineProperties(this, {
'_stdout': { ...consolePropAttributes, value: stdout },
'_stderr': { ...consolePropAttributes, value: stderr }
});
}
});
};
},
[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];

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);
}
}
},
[kGetInspectOptions]: {
...consolePropAttributes,
value: function(stream) {
let color = this[kColorMode];
if (color === 'auto') {
color = stream.isTTY && (
typeof stream.getColorDepth === 'function' ?
stream.getColorDepth() > 2 : true);
}

Console.prototype[kBindProperties] = 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
},
});
};
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()`.
function createWriteErrorHandler(instance, streamSymbol) {
Expand All @@ -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 = {
log(...args) {
this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args));
Expand Down