123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641 |
- /**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @polyfill
- * @nolint
- * @format
- */
- /* eslint-disable no-shadow, eqeqeq, curly, no-unused-vars, no-void, no-control-regex */
- /**
- * This pipes all of our console logging functions to native logging so that
- * JavaScript errors in required modules show up in Xcode via NSLog.
- */
- const inspect = (function() {
- // 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.
- //
- // https://github.com/joyent/node/blob/master/lib/util.js
- function inspect(obj, opts) {
- var ctx = {
- seen: [],
- formatValueCalls: 0,
- stylize: stylizeNoColor,
- };
- return formatValue(ctx, obj, opts.depth);
- }
- function stylizeNoColor(str, styleType) {
- return str;
- }
- function arrayToHash(array) {
- var hash = {};
- array.forEach(function(val, idx) {
- hash[val] = true;
- });
- return hash;
- }
- function formatValue(ctx, value, recurseTimes) {
- ctx.formatValueCalls++;
- if (ctx.formatValueCalls > 200) {
- return `[TOO BIG formatValueCalls ${
- ctx.formatValueCalls
- } exceeded limit of 200]`;
- }
- // Primitive types cannot have properties
- var primitive = formatPrimitive(ctx, value);
- if (primitive) {
- return primitive;
- }
- // Look up the keys of the object.
- var keys = Object.keys(value);
- var visibleKeys = arrayToHash(keys);
- // IE doesn't make error fields non-enumerable
- // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
- if (
- isError(value) &&
- (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)
- ) {
- return formatError(value);
- }
- // Some type of object without properties can be shortcutted.
- if (keys.length === 0) {
- if (isFunction(value)) {
- var name = value.name ? ': ' + value.name : '';
- return ctx.stylize('[Function' + name + ']', 'special');
- }
- if (isRegExp(value)) {
- return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
- }
- if (isDate(value)) {
- return ctx.stylize(Date.prototype.toString.call(value), 'date');
- }
- if (isError(value)) {
- return formatError(value);
- }
- }
- var base = '',
- array = false,
- braces = ['{', '}'];
- // Make Array say that they are Array
- if (isArray(value)) {
- array = true;
- braces = ['[', ']'];
- }
- // Make functions say that they are functions
- if (isFunction(value)) {
- var n = value.name ? ': ' + value.name : '';
- base = ' [Function' + n + ']';
- }
- // Make RegExps say that they are RegExps
- if (isRegExp(value)) {
- base = ' ' + RegExp.prototype.toString.call(value);
- }
- // Make dates with properties first say the date
- if (isDate(value)) {
- base = ' ' + Date.prototype.toUTCString.call(value);
- }
- // Make error with message first say the error
- if (isError(value)) {
- base = ' ' + formatError(value);
- }
- if (keys.length === 0 && (!array || value.length == 0)) {
- return braces[0] + base + braces[1];
- }
- if (recurseTimes < 0) {
- if (isRegExp(value)) {
- return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
- } else {
- return ctx.stylize('[Object]', 'special');
- }
- }
- ctx.seen.push(value);
- var output;
- if (array) {
- output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
- } else {
- output = keys.map(function(key) {
- return formatProperty(
- ctx,
- value,
- recurseTimes,
- visibleKeys,
- key,
- array,
- );
- });
- }
- ctx.seen.pop();
- return reduceToSingleString(output, base, braces);
- }
- function formatPrimitive(ctx, value) {
- if (isUndefined(value)) return ctx.stylize('undefined', 'undefined');
- if (isString(value)) {
- var simple =
- "'" +
- JSON.stringify(value)
- .replace(/^"|"$/g, '')
- .replace(/'/g, "\\'")
- .replace(/\\"/g, '"') +
- "'";
- return ctx.stylize(simple, 'string');
- }
- if (isNumber(value)) return ctx.stylize('' + value, 'number');
- if (isBoolean(value)) return ctx.stylize('' + value, 'boolean');
- // For some reason typeof null is "object", so special case here.
- if (isNull(value)) return ctx.stylize('null', 'null');
- }
- function formatError(value) {
- return '[' + Error.prototype.toString.call(value) + ']';
- }
- function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
- var output = [];
- for (var i = 0, l = value.length; i < l; ++i) {
- if (hasOwnProperty(value, String(i))) {
- output.push(
- formatProperty(
- ctx,
- value,
- recurseTimes,
- visibleKeys,
- String(i),
- true,
- ),
- );
- } else {
- output.push('');
- }
- }
- keys.forEach(function(key) {
- if (!key.match(/^\d+$/)) {
- output.push(
- formatProperty(ctx, value, recurseTimes, visibleKeys, key, true),
- );
- }
- });
- return output;
- }
- function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
- var name, str, desc;
- desc = Object.getOwnPropertyDescriptor(value, key) || {value: value[key]};
- if (desc.get) {
- if (desc.set) {
- str = ctx.stylize('[Getter/Setter]', 'special');
- } else {
- str = ctx.stylize('[Getter]', 'special');
- }
- } else {
- if (desc.set) {
- str = ctx.stylize('[Setter]', 'special');
- }
- }
- if (!hasOwnProperty(visibleKeys, key)) {
- name = '[' + key + ']';
- }
- if (!str) {
- if (ctx.seen.indexOf(desc.value) < 0) {
- if (isNull(recurseTimes)) {
- str = formatValue(ctx, desc.value, null);
- } else {
- str = formatValue(ctx, desc.value, recurseTimes - 1);
- }
- if (str.indexOf('\n') > -1) {
- if (array) {
- str = str
- .split('\n')
- .map(function(line) {
- return ' ' + line;
- })
- .join('\n')
- .substr(2);
- } else {
- str =
- '\n' +
- str
- .split('\n')
- .map(function(line) {
- return ' ' + line;
- })
- .join('\n');
- }
- }
- } else {
- str = ctx.stylize('[Circular]', 'special');
- }
- }
- if (isUndefined(name)) {
- if (array && key.match(/^\d+$/)) {
- return str;
- }
- name = JSON.stringify('' + key);
- if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
- name = name.substr(1, name.length - 2);
- name = ctx.stylize(name, 'name');
- } else {
- name = name
- .replace(/'/g, "\\'")
- .replace(/\\"/g, '"')
- .replace(/(^"|"$)/g, "'");
- name = ctx.stylize(name, 'string');
- }
- }
- return name + ': ' + str;
- }
- function reduceToSingleString(output, base, braces) {
- var numLinesEst = 0;
- var length = output.reduce(function(prev, cur) {
- numLinesEst++;
- if (cur.indexOf('\n') >= 0) numLinesEst++;
- return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
- }, 0);
- if (length > 60) {
- return (
- braces[0] +
- (base === '' ? '' : base + '\n ') +
- ' ' +
- output.join(',\n ') +
- ' ' +
- braces[1]
- );
- }
- return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
- }
- // NOTE: These type checking functions intentionally don't use `instanceof`
- // because it is fragile and can be easily faked with `Object.create()`.
- function isArray(ar) {
- return Array.isArray(ar);
- }
- function isBoolean(arg) {
- return typeof arg === 'boolean';
- }
- function isNull(arg) {
- return arg === null;
- }
- function isNullOrUndefined(arg) {
- return arg == null;
- }
- function isNumber(arg) {
- return typeof arg === 'number';
- }
- function isString(arg) {
- return typeof arg === 'string';
- }
- function isSymbol(arg) {
- return typeof arg === 'symbol';
- }
- function isUndefined(arg) {
- return arg === void 0;
- }
- function isRegExp(re) {
- return isObject(re) && objectToString(re) === '[object RegExp]';
- }
- function isObject(arg) {
- return typeof arg === 'object' && arg !== null;
- }
- function isDate(d) {
- return isObject(d) && objectToString(d) === '[object Date]';
- }
- function isError(e) {
- return (
- isObject(e) &&
- (objectToString(e) === '[object Error]' || e instanceof Error)
- );
- }
- function isFunction(arg) {
- return typeof arg === 'function';
- }
- function objectToString(o) {
- return Object.prototype.toString.call(o);
- }
- function hasOwnProperty(obj, prop) {
- return Object.prototype.hasOwnProperty.call(obj, prop);
- }
- return inspect;
- })();
- const OBJECT_COLUMN_NAME = '(index)';
- const LOG_LEVELS = {
- trace: 0,
- info: 1,
- warn: 2,
- error: 3,
- };
- const INSPECTOR_LEVELS = [];
- INSPECTOR_LEVELS[LOG_LEVELS.trace] = 'debug';
- INSPECTOR_LEVELS[LOG_LEVELS.info] = 'log';
- INSPECTOR_LEVELS[LOG_LEVELS.warn] = 'warning';
- INSPECTOR_LEVELS[LOG_LEVELS.error] = 'error';
- // Strip the inner function in getNativeLogFunction(), if in dev also
- // strip method printing to originalConsole.
- const INSPECTOR_FRAMES_TO_SKIP = __DEV__ ? 2 : 1;
- function getNativeLogFunction(level) {
- return function() {
- let str;
- if (arguments.length === 1 && typeof arguments[0] === 'string') {
- str = arguments[0];
- } else {
- str = Array.prototype.map
- .call(arguments, function(arg) {
- return inspect(arg, {depth: 10});
- })
- .join(', ');
- }
- // TRICKY
- // If more than one argument is provided, the code above collapses them all
- // into a single formatted string. This transform wraps string arguments in
- // single quotes (e.g. "foo" -> "'foo'") which then breaks the "Warning:"
- // check below. So it's important that we look at the first argument, rather
- // than the formatted argument string.
- const firstArg = arguments[0];
- let logLevel = level;
- if (
- typeof firstArg === 'string' &&
- firstArg.slice(0, 9) === 'Warning: ' &&
- logLevel >= LOG_LEVELS.error
- ) {
- // React warnings use console.error so that a stack trace is shown,
- // but we don't (currently) want these to show a redbox
- // (Note: Logic duplicated in ExceptionsManager.js.)
- logLevel = LOG_LEVELS.warn;
- }
- if (global.__inspectorLog) {
- global.__inspectorLog(
- INSPECTOR_LEVELS[logLevel],
- str,
- [].slice.call(arguments),
- INSPECTOR_FRAMES_TO_SKIP,
- );
- }
- if (groupStack.length) {
- str = groupFormat('', str);
- }
- global.nativeLoggingHook(str, logLevel);
- };
- }
- function repeat(element, n) {
- return Array.apply(null, Array(n)).map(function() {
- return element;
- });
- }
- function consoleTablePolyfill(rows) {
- // convert object -> array
- if (!Array.isArray(rows)) {
- var data = rows;
- rows = [];
- for (var key in data) {
- if (data.hasOwnProperty(key)) {
- var row = data[key];
- row[OBJECT_COLUMN_NAME] = key;
- rows.push(row);
- }
- }
- }
- if (rows.length === 0) {
- global.nativeLoggingHook('', LOG_LEVELS.info);
- return;
- }
- var columns = Object.keys(rows[0]).sort();
- var stringRows = [];
- var columnWidths = [];
- // Convert each cell to a string. Also
- // figure out max cell width for each column
- columns.forEach(function(k, i) {
- columnWidths[i] = k.length;
- for (var j = 0; j < rows.length; j++) {
- var cellStr = (rows[j][k] || '?').toString();
- stringRows[j] = stringRows[j] || [];
- stringRows[j][i] = cellStr;
- columnWidths[i] = Math.max(columnWidths[i], cellStr.length);
- }
- });
- // Join all elements in the row into a single string with | separators
- // (appends extra spaces to each cell to make separators | aligned)
- function joinRow(row, space) {
- var cells = row.map(function(cell, i) {
- var extraSpaces = repeat(' ', columnWidths[i] - cell.length).join('');
- return cell + extraSpaces;
- });
- space = space || ' ';
- return cells.join(space + '|' + space);
- }
- var separators = columnWidths.map(function(columnWidth) {
- return repeat('-', columnWidth).join('');
- });
- var separatorRow = joinRow(separators, '-');
- var header = joinRow(columns);
- var table = [header, separatorRow];
- for (var i = 0; i < rows.length; i++) {
- table.push(joinRow(stringRows[i]));
- }
- // Notice extra empty line at the beginning.
- // Native logging hook adds "RCTLog >" at the front of every
- // logged string, which would shift the header and screw up
- // the table
- global.nativeLoggingHook('\n' + table.join('\n'), LOG_LEVELS.info);
- }
- const GROUP_PAD = '\u2502'; // Box light vertical
- const GROUP_OPEN = '\u2510'; // Box light down+left
- const GROUP_CLOSE = '\u2518'; // Box light up+left
- const groupStack = [];
- function groupFormat(prefix, msg) {
- // Insert group formatting before the console message
- return groupStack.join('') + prefix + ' ' + (msg || '');
- }
- function consoleGroupPolyfill(label) {
- global.nativeLoggingHook(groupFormat(GROUP_OPEN, label), LOG_LEVELS.info);
- groupStack.push(GROUP_PAD);
- }
- function consoleGroupCollapsedPolyfill(label) {
- global.nativeLoggingHook(groupFormat(GROUP_CLOSE, label), LOG_LEVELS.info);
- groupStack.push(GROUP_PAD);
- }
- function consoleGroupEndPolyfill() {
- groupStack.pop();
- global.nativeLoggingHook(groupFormat(GROUP_CLOSE), LOG_LEVELS.info);
- }
- function consoleAssertPolyfill(expression, label) {
- if (!expression) {
- global.nativeLoggingHook('Assertion failed: ' + label, LOG_LEVELS.error);
- }
- }
- if (global.nativeLoggingHook) {
- const originalConsole = global.console;
- // Preserve the original `console` as `originalConsole`
- if (__DEV__ && originalConsole) {
- const descriptor = Object.getOwnPropertyDescriptor(global, 'console');
- if (descriptor) {
- Object.defineProperty(global, 'originalConsole', descriptor);
- }
- }
- global.console = {
- error: getNativeLogFunction(LOG_LEVELS.error),
- info: getNativeLogFunction(LOG_LEVELS.info),
- log: getNativeLogFunction(LOG_LEVELS.info),
- warn: getNativeLogFunction(LOG_LEVELS.warn),
- trace: getNativeLogFunction(LOG_LEVELS.trace),
- debug: getNativeLogFunction(LOG_LEVELS.trace),
- table: consoleTablePolyfill,
- group: consoleGroupPolyfill,
- groupEnd: consoleGroupEndPolyfill,
- groupCollapsed: consoleGroupCollapsedPolyfill,
- assert: consoleAssertPolyfill,
- };
- Object.defineProperty(console, '_isPolyfilled', {
- value: true,
- enumerable: false,
- });
- // If available, also call the original `console` method since that is
- // sometimes useful. Ex: on OS X, this will let you see rich output in
- // the Safari Web Inspector console.
- if (__DEV__ && originalConsole) {
- Object.keys(console).forEach(methodName => {
- const reactNativeMethod = console[methodName];
- if (originalConsole[methodName]) {
- console[methodName] = function() {
- // TODO(T43930203): remove this special case once originalConsole.assert properly checks
- // the condition
- if (methodName === 'assert') {
- if (!arguments[0]) {
- originalConsole.assert(...arguments);
- }
- } else {
- originalConsole[methodName](...arguments);
- }
- reactNativeMethod.apply(console, arguments);
- };
- }
- });
- // The following methods are not supported by this polyfill but
- // we still should pass them to original console if they are
- // supported by it.
- ['clear', 'dir', 'dirxml', 'profile', 'profileEnd'].forEach(methodName => {
- if (typeof originalConsole[methodName] === 'function') {
- console[methodName] = function() {
- originalConsole[methodName](...arguments);
- };
- }
- });
- }
- } else if (!global.console) {
- function stub() {}
- const log = global.print || stub;
- global.console = {
- debug: log,
- error: log,
- info: log,
- log: log,
- trace: log,
- warn: log,
- assert(expression, label) {
- if (!expression) {
- log('Assertion failed: ' + label);
- }
- },
- clear: stub,
- dir: stub,
- dirxml: stub,
- group: stub,
- groupCollapsed: stub,
- groupEnd: stub,
- profile: stub,
- profileEnd: stub,
- table: stub,
- };
- Object.defineProperty(console, '_isPolyfilled', {
- value: true,
- enumerable: false,
- });
- }
|