summaryrefslogtreecommitdiff
path: root/lib/console.js
diff options
context:
space:
mode:
authorJoyee Cheung <joyeec9h3@gmail.com>2018-11-29 06:14:30 +0800
committerJoyee Cheung <joyeec9h3@gmail.com>2018-12-02 04:51:17 +0800
commitce8b0e196eca6816d77dda43f28e7da6b3784e6b (patch)
tree3f342b8aa462c07fd98bc3032e7e61a7266040d7 /lib/console.js
parentadbf9477eb244b0f83a705b06269705967194f03 (diff)
downloadnode-new-ce8b0e196eca6816d77dda43f28e7da6b3784e6b.tar.gz
lib: move lib/console.js to lib/internal/console/constructor.js
This is a broken commit: it's here so that git interpret this as a file move and preserve most of the history of the Console constructor. PR-URL: https://github.com/nodejs/node/pull/24709 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'lib/console.js')
-rw-r--r--lib/console.js571
1 files changed, 0 insertions, 571 deletions
diff --git a/lib/console.js b/lib/console.js
deleted file mode 100644
index ebd098e9af..0000000000
--- a/lib/console.js
+++ /dev/null
@@ -1,571 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-'use strict';
-
-const { trace } = internalBinding('trace_events');
-const {
- isStackOverflowError,
- codes: {
- ERR_CONSOLE_WRITABLE_STREAM,
- ERR_INVALID_ARG_TYPE,
- ERR_INVALID_ARG_VALUE,
- },
-} = require('internal/errors');
-const { previewEntries } = internalBinding('util');
-const { Buffer: { isBuffer } } = require('buffer');
-const util = require('util');
-const {
- isTypedArray, isSet, isMap, isSetIterator, isMapIterator,
-} = util.types;
-const kCounts = Symbol('counts');
-
-const kTraceConsoleCategory = 'node,node.console';
-const kTraceCount = 'C'.charCodeAt(0);
-const kTraceBegin = 'b'.charCodeAt(0);
-const kTraceEnd = 'e'.charCodeAt(0);
-const kTraceInstant = 'n'.charCodeAt(0);
-
-const {
- keys: ObjectKeys,
- values: ObjectValues,
-} = Object;
-const hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);
-
-const {
- isArray: ArrayIsArray,
- from: ArrayFrom,
-} = Array;
-
-// Lazy loaded for startup performance.
-let cliTable;
-
-// Track amount of indentation required via `console.group()`.
-const kGroupIndent = Symbol('kGroupIndent');
-const kFormatForStderr = Symbol('kFormatForStderr');
-const kFormatForStdout = Symbol('kFormatForStdout');
-const kGetInspectOptions = Symbol('kGetInspectOptions');
-const kColorMode = Symbol('kColorMode');
-const kIsConsole = Symbol('kIsConsole');
-const kWriteToConsole = Symbol('kWriteToConsole');
-const kBindProperties = Symbol('kBindProperties');
-const kBindStreamsEager = Symbol('kBindStreamsEager');
-const kBindStreamsLazy = Symbol('kBindStreamsLazy');
-const kUseStdout = Symbol('kUseStdout');
-const kUseStderr = Symbol('kUseStderr');
-
-// This constructor is not used to construct the global console.
-// It's exported for backwards compatibility.
-function Console(options /* or: stdout, stderr, ignoreErrors = true */) {
- // We have to test new.target here to see if this function is called
- // with new, because we need to define a custom instanceof to accommodate
- // the global console.
- if (!new.target) {
- return new Console(...arguments);
- }
-
- if (!options || typeof options.write === 'function') {
- options = {
- stdout: options,
- stderr: arguments[1],
- ignoreErrors: arguments[2]
- };
- }
-
- const {
- stdout,
- stderr = stdout,
- ignoreErrors = true,
- colorMode = 'auto'
- } = options;
-
- if (!stdout || typeof stdout.write !== 'function') {
- throw new ERR_CONSOLE_WRITABLE_STREAM('stdout');
- }
- if (!stderr || typeof stderr.write !== 'function') {
- throw new ERR_CONSOLE_WRITABLE_STREAM('stderr');
- }
-
- if (typeof colorMode !== 'boolean' && colorMode !== 'auto')
- throw new ERR_INVALID_ARG_VALUE('colorMode', colorMode);
-
- // bind the prototype functions to this Console instance
- var keys = Object.keys(Console.prototype);
- for (var v = 0; v < keys.length; v++) {
- var k = keys[v];
- // We have to bind the methods grabbed from the instance instead of from
- // the prototype so that users extending the Console can override them
- // from the prototype chain of the subclass.
- this[k] = this[k].bind(this);
- }
-
- this[kBindStreamsEager](stdout, stderr);
- this[kBindProperties](ignoreErrors, colorMode);
-}
-
-const consolePropAttributes = {
- writable: true,
- enumerable: false,
- configurable: true
-};
-
-// Fixup global.console instanceof global.console.Console
-Object.defineProperty(Console, Symbol.hasInstance, {
- value(instance) {
- return instance[kIsConsole];
- }
-});
-
-// Eager version for the Console constructor
-Console.prototype[kBindStreamsEager] = function(stdout, stderr) {
- Object.defineProperties(this, {
- '_stdout': { ...consolePropAttributes, value: stdout },
- '_stderr': { ...consolePropAttributes, value: stderr }
- });
-};
-
-// 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;
- Object.defineProperties(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; }
- }
- });
-};
-
-Console.prototype[kBindProperties] = function(ignoreErrors, colorMode) {
- Object.defineProperties(this, {
- '_stdoutErrorHandler': {
- ...consolePropAttributes,
- value: createWriteErrorHandler(this, kUseStdout)
- },
- '_stderrErrorHandler': {
- ...consolePropAttributes,
- value: createWriteErrorHandler(this, kUseStderr)
- },
- '_ignoreErrors': {
- ...consolePropAttributes,
- value: Boolean(ignoreErrors)
- },
- '_times': { ...consolePropAttributes, value: new Map() }
- });
-
- // TODO(joyeecheung): use consolePropAttributes for these
- // Corresponds to https://console.spec.whatwg.org/#count-map
- this[kCounts] = new Map();
- this[kColorMode] = colorMode;
- this[kIsConsole] = true;
- this[kGroupIndent] = '';
-};
-
-// Make a function that can serve as the callback passed to `stream.write()`.
-function createWriteErrorHandler(instance, streamSymbol) {
- return (err) => {
- // This conditional evaluates to true if and only if there was an error
- // that was not already emitted (which happens when the _write callback
- // is invoked asynchronously).
- const stream = streamSymbol === kUseStdout ?
- instance._stdout : instance._stderr;
- if (err !== null && !stream._writableState.errorEmitted) {
- // If there was an error, it will be emitted on `stream` as
- // an `error` event. Adding a `once` listener will keep that error
- // from becoming an uncaught exception, but since the handler is
- // removed after the event, non-console.* writes won't be affected.
- // we are only adding noop if there is no one else listening for 'error'
- if (stream.listenerCount('error') === 0) {
- stream.on('error', noop);
- }
- }
- };
-}
-
-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.indexOf('\n') !== -1) {
- 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.
- 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);
- }
-
- return color ? kColorInspectOptions : kNoColorInspectOptions;
-};
-
-Console.prototype[kFormatForStdout] = function(args) {
- const opts = this[kGetInspectOptions](this._stdout);
- return util.formatWithOptions(opts, ...args);
-};
-
-Console.prototype[kFormatForStderr] = function(args) {
- const opts = this[kGetInspectOptions](this._stderr);
- return util.formatWithOptions(opts, ...args);
-};
-
-Console.prototype.log = function log(...args) {
- this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args));
-};
-
-Console.prototype.debug = Console.prototype.log;
-Console.prototype.info = Console.prototype.log;
-Console.prototype.dirxml = Console.prototype.log;
-
-Console.prototype.warn = function warn(...args) {
- this[kWriteToConsole](kUseStderr, this[kFormatForStderr](args));
-};
-
-Console.prototype.error = Console.prototype.warn;
-
-Console.prototype.dir = function dir(object, options) {
- options = Object.assign({
- customInspect: false
- }, this[kGetInspectOptions](this._stdout), options);
- this[kWriteToConsole](kUseStdout, util.inspect(object, options));
-};
-
-Console.prototype.time = function time(label = 'default') {
- // Coerces everything other than Symbol to a string
- label = `${label}`;
- if (this._times.has(label)) {
- process.emitWarning(`Label '${label}' already exists for console.time()`);
- return;
- }
- trace(kTraceBegin, kTraceConsoleCategory, `time::${label}`, 0);
- this._times.set(label, process.hrtime());
-};
-
-Console.prototype.timeEnd = function timeEnd(label = 'default') {
- // Coerces everything other than Symbol to a string
- label = `${label}`;
- const hasWarned = timeLogImpl(this, 'timeEnd', label);
- trace(kTraceEnd, kTraceConsoleCategory, `time::${label}`, 0);
- if (!hasWarned) {
- this._times.delete(label);
- }
-};
-
-Console.prototype.timeLog = function timeLog(label = 'default', ...data) {
- // Coerces everything other than Symbol to a string
- label = `${label}`;
- timeLogImpl(this, 'timeLog', label, data);
- trace(kTraceInstant, kTraceConsoleCategory, `time::${label}`, 0);
-};
-
-// Returns true if label was not found
-function timeLogImpl(self, name, label, data) {
- const time = self._times.get(label);
- if (!time) {
- process.emitWarning(`No such label '${label}' for console.${name}()`);
- return true;
- }
- const duration = process.hrtime(time);
- const ms = duration[0] * 1000 + duration[1] / 1e6;
- if (data === undefined) {
- self.log('%s: %sms', label, ms.toFixed(3));
- } else {
- self.log('%s: %sms', label, ms.toFixed(3), ...data);
- }
- return false;
-}
-
-Console.prototype.trace = function trace(...args) {
- const err = {
- name: 'Trace',
- message: this[kFormatForStderr](args)
- };
- Error.captureStackTrace(err, trace);
- this.error(err.stack);
-};
-
-Console.prototype.assert = function assert(expression, ...args) {
- if (!expression) {
- args[0] = `Assertion failed${args.length === 0 ? '' : `: ${args[0]}`}`;
- this.warn(...args); // the arguments will be formatted in warn() again
- }
-};
-
-// 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);
- trace(kTraceCount, kTraceConsoleCategory, `count::${label}`, 0, count);
- this.log(`${label}: ${count}`);
-};
-
-// Defined by: https://console.spec.whatwg.org/#countreset
-Console.prototype.countReset = function countReset(label = 'default') {
- const counts = this[kCounts];
- if (!counts.has(label)) {
- process.emitWarning(`Count for '${label}' does not exist`);
- return;
- }
- trace(kTraceCount, kTraceConsoleCategory, `count::${label}`, 0, 0);
- counts.delete(`${label}`);
-};
-
-Console.prototype.group = function group(...data) {
- if (data.length > 0) {
- this.log(...data);
- }
- this[kGroupIndent] += ' ';
-};
-Console.prototype.groupCollapsed = Console.prototype.group;
-
-Console.prototype.groupEnd = function groupEnd() {
- this[kGroupIndent] =
- this[kGroupIndent].slice(0, this[kGroupIndent].length - 2);
-};
-
-const keyKey = 'Key';
-const valuesKey = 'Values';
-const indexKey = '(index)';
-const iterKey = '(iteration index)';
-
-const isArray = (v) => ArrayIsArray(v) || isTypedArray(v) || isBuffer(v);
-
-// https://console.spec.whatwg.org/#table
-Console.prototype.table = function(tabularData, properties) {
- if (properties !== undefined && !ArrayIsArray(properties))
- throw new ERR_INVALID_ARG_TYPE('properties', 'Array', properties);
-
- if (tabularData === null || typeof tabularData !== 'object')
- return this.log(tabularData);
-
- if (cliTable === undefined) cliTable = require('internal/cli_table');
- const final = (k, v) => this.log(cliTable(k, v));
-
- const inspect = (v) => {
- const opt = { depth: 0, maxArrayLength: 3 };
- if (v !== null && typeof v === 'object' &&
- !isArray(v) && ObjectKeys(v).length > 2)
- opt.depth = -1;
- Object.assign(opt, this[kGetInspectOptions](this._stdout));
- return util.inspect(v, opt);
- };
- const getIndexArray = (length) => ArrayFrom({ length }, (_, i) => inspect(i));
-
- const mapIter = isMapIterator(tabularData);
- let isKeyValue = false;
- let i = 0;
- if (mapIter) {
- const res = previewEntries(tabularData, true);
- tabularData = res[0];
- isKeyValue = res[1];
- }
-
- if (isKeyValue || isMap(tabularData)) {
- const keys = [];
- const values = [];
- let length = 0;
- if (mapIter) {
- for (; i < tabularData.length / 2; ++i) {
- keys.push(inspect(tabularData[i * 2]));
- values.push(inspect(tabularData[i * 2 + 1]));
- length++;
- }
- } else {
- for (const [k, v] of tabularData) {
- keys.push(inspect(k));
- values.push(inspect(v));
- length++;
- }
- }
- return final([
- iterKey, keyKey, valuesKey
- ], [
- getIndexArray(length),
- keys,
- values,
- ]);
- }
-
- const setIter = isSetIterator(tabularData);
- if (setIter)
- tabularData = previewEntries(tabularData);
-
- const setlike = setIter || (mapIter && !isKeyValue) || isSet(tabularData);
- if (setlike) {
- const values = [];
- let length = 0;
- for (const v of tabularData) {
- values.push(inspect(v));
- length++;
- }
- return final([setlike ? iterKey : indexKey, valuesKey], [
- getIndexArray(length),
- values,
- ]);
- }
-
- const map = {};
- let hasPrimitives = false;
- const valuesKeyArray = [];
- const indexKeyArray = ObjectKeys(tabularData);
-
- for (; i < indexKeyArray.length; i++) {
- const item = tabularData[indexKeyArray[i]];
- const primitive = item === null ||
- (typeof item !== 'function' && typeof item !== 'object');
- if (properties === undefined && primitive) {
- hasPrimitives = true;
- valuesKeyArray[i] = inspect(item);
- } else {
- const keys = properties || ObjectKeys(item);
- for (const key of keys) {
- if (map[key] === undefined)
- map[key] = [];
- if ((primitive && properties) || !hasOwnProperty(item, key))
- map[key][i] = '';
- else
- map[key][i] = item == null ? item : inspect(item[key]);
- }
- }
- }
-
- const keys = ObjectKeys(map);
- const values = ObjectValues(map);
- if (hasPrimitives) {
- keys.push(valuesKey);
- values.push(valuesKeyArray);
- }
- keys.unshift(indexKey);
- values.unshift(indexKeyArray);
-
- return final(keys, values);
-};
-
-function noop() {}
-
-// See https://console.spec.whatwg.org/#console-namespace
-// > For historical web-compatibility reasons, the namespace object
-// > for console must have as its [[Prototype]] an empty object,
-// > created as if by ObjectCreate(%ObjectPrototype%),
-// > instead of %ObjectPrototype%.
-
-// Since in Node.js, the Console constructor has been exposed through
-// require('console'), we need to keep the Console constructor but
-// we cannot actually use `new Console` to construct the global console.
-// Therefore, the console.Console.prototype is not
-// in the global console prototype chain anymore.
-
-// TODO(joyeecheung):
-// - Move the Console constructor into internal/console.js
-// - Move the global console creation code along with the inspector console
-// wrapping code in internal/bootstrap/node.js into a separate file.
-// - Make this file a simple re-export of those two files.
-const globalConsole = Object.create({});
-
-// Since Console is not on the prototype chain of the global console,
-// the symbol properties on Console.prototype have to be looked up from
-// the global console itself. In addition, we need to make the global
-// console a namespace by binding the console methods directly onto
-// the global console with the receiver fixed.
-for (const prop of Reflect.ownKeys(Console.prototype)) {
- if (prop === 'constructor') { continue; }
- const desc = Reflect.getOwnPropertyDescriptor(Console.prototype, prop);
- if (typeof desc.value === 'function') { // fix the receiver
- desc.value = desc.value.bind(globalConsole);
- }
- Reflect.defineProperty(globalConsole, prop, desc);
-}
-
-globalConsole[kBindStreamsLazy](process);
-globalConsole[kBindProperties](true, 'auto');
-
-module.exports = globalConsole;
-module.exports.Console = Console;