From d33b554f5d4bb7856cf2fc21175bab23d8225fe4 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 21 Jan 2016 07:22:20 -0800 Subject: [PATCH] Make the packager work with babel strict mode transform Summary: At the moment we have to disable strict mode for the transform-es2015-modules-commonjs because strict mode leaks to the global scope and breaks the bridge. It was due to the way the polyfills were bundled in the package. To fix it, I wrapped the polyfill modules in an IIFE. Then when strict mode was enabled some polyfills were broken due to strict mode errors so that was fixed too. Also removed the IIFE from the polyfills that included one. This diff doesn't enable the strict mode transform since some internal facebook modules depend on it not being enabled. When #5214 lands we could make the default babel config shipped with OSS react-native use strict mode modules and facebook could just modify the babel config to disable it if needed. This will allow removing `"strict": false` from https://github.com/facebook/react-native/blob/master/packager/react-packager/.babelrc#L16 Fixes #5316 Closes https://github.com/facebook/react-native/pull/5422 Reviewed By: svcscm Differential Revision: D2846422 Pulled By: davidaurelio fb-gh-sync-id: a3e2f8909aa87dabab2b872c61b887e80220fb56 --- .../InitializeJavaScriptAppEngine.js | 27 +- .../JavaScriptAppEngine/polyfills/document.js | 60 +- Libraries/vendor/emitter/mixInEventEmitter.js | 3 +- .../src/Resolver/__tests__/Resolver-test.js | 29 + packager/react-packager/src/Resolver/index.js | 12 +- .../Resolver/polyfills/Array.prototype.es6.js | 91 +- .../src/Resolver/polyfills/babelHelpers.js | 363 ++++--- .../src/Resolver/polyfills/console.js | 883 +++++++++--------- .../src/Resolver/polyfills/error-guard.js | 132 ++- .../src/Resolver/polyfills/loadBundles.js | 74 +- .../src/Resolver/polyfills/polyfills.js | 2 +- .../src/Resolver/polyfills/prelude.js | 7 +- .../src/Resolver/polyfills/prelude_dev.js | 7 +- .../Resolver/polyfills/require-unbundle.js | 113 ++- .../src/Resolver/polyfills/require.js | 218 +++-- .../__tests__/dead-module-elimination-test.js | 14 +- .../dead-module-elimination.js | 9 +- 17 files changed, 1032 insertions(+), 1012 deletions(-) diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js index 37f507c2e1..dea05fa952 100644 --- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js +++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js @@ -25,11 +25,11 @@ require('regenerator/runtime'); if (typeof GLOBAL === 'undefined') { - GLOBAL = this; + global.GLOBAL = this; } if (typeof window === 'undefined') { - window = GLOBAL; + global.window = GLOBAL; } function setUpConsole() { @@ -70,6 +70,15 @@ function polyfillGlobal(name, newValue, scope = GLOBAL) { Object.defineProperty(scope, name, {...descriptor, value: newValue}); } +/** + * Polyfill a module if it is not already defined in `scope`. + */ +function polyfillIfNeeded(name, polyfill, scope = GLOBAL, descriptor = {}) { + if (scope[name] === undefined) { + Object.defineProperty(scope, name, {...descriptor, value: polyfill}); + } +} + function setUpErrorHandler() { if (global.__fbDisableExceptionsManager) { return; @@ -78,7 +87,7 @@ function setUpErrorHandler() { function handleError(e, isFatal) { try { require('ExceptionsManager').handleException(e, isFatal); - } catch(ee) { + } catch (ee) { console.log('Failed to print error: ', ee.message); } } @@ -146,7 +155,11 @@ function setUpXHR() { } function setUpGeolocation() { - GLOBAL.navigator = GLOBAL.navigator || {}; + polyfillIfNeeded('navigator', {}, GLOBAL, { + writable: true, + enumerable: true, + configurable: true, + }); polyfillGlobal('geolocation', require('Geolocation'), GLOBAL.navigator); } @@ -179,9 +192,9 @@ function setUpProcessEnv() { } function setUpNumber() { - Number.EPSILON = Number.EPSILON || Math.pow(2, -52); - Number.MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1; - Number.MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER || -(Math.pow(2, 53) - 1); + polyfillIfNeeded('EPSILON', Math.pow(2, -52), Number); + polyfillIfNeeded('MAX_SAFE_INTEGER', Math.pow(2, 53) - 1, Number); + polyfillIfNeeded('MIN_SAFE_INTEGER', -(Math.pow(2, 53) - 1), Number); } function setUpDevTools() { diff --git a/Libraries/JavaScriptAppEngine/polyfills/document.js b/Libraries/JavaScriptAppEngine/polyfills/document.js index 4e76db9572..bff669cce9 100644 --- a/Libraries/JavaScriptAppEngine/polyfills/document.js +++ b/Libraries/JavaScriptAppEngine/polyfills/document.js @@ -1,34 +1,30 @@ -/* eslint global-strict: 0 */ -(function(GLOBAL) { - /** - * The document must be shimmed before anything else that might define the - * `ExecutionEnvironment` module (which checks for `document.createElement`). - */ +/* eslint strict: 0 */ - // The browser defines Text and Image globals by default. If you forget to - // require them, then the error message is very confusing. - function getInvalidGlobalUseError(name) { - return new Error( - 'You are trying to render the global ' + name + ' variable as a ' + - 'React element. You probably forgot to require ' + name + '.' - ); - } - GLOBAL.Text = { - get defaultProps() { - throw getInvalidGlobalUseError('Text'); - } - }; - GLOBAL.Image = { - get defaultProps() { - throw getInvalidGlobalUseError('Image'); - } - }; - // Force `ExecutionEnvironment.canUseDOM` to be false. - if (GLOBAL.document) { - GLOBAL.document.createElement = null; - } +// TODO: Remove document polyfill now that chrome debugging is in a web worker. - // There is no DOM so MutationObserver doesn't make sense. It is used - // as feature detection in Bluebird Promise implementation - GLOBAL.MutationObserver = undefined; -})(this); +// The browser defines Text and Image globals by default. If you forget to +// require them, then the error message is very confusing. +function getInvalidGlobalUseError(name) { + return new Error( + 'You are trying to render the global ' + name + ' variable as a ' + + 'React element. You probably forgot to require ' + name + '.' + ); +} +global.Text = { + get defaultProps() { + throw getInvalidGlobalUseError('Text'); + } +}; +global.Image = { + get defaultProps() { + throw getInvalidGlobalUseError('Image'); + } +}; +// Force `ExecutionEnvironment.canUseDOM` to be false. +if (global.document) { + global.document.createElement = null; +} + +// There is no DOM so MutationObserver doesn't make sense. It is used +// as feature detection in Bluebird Promise implementation +global.MutationObserver = undefined; diff --git a/Libraries/vendor/emitter/mixInEventEmitter.js b/Libraries/vendor/emitter/mixInEventEmitter.js index cc62d04d46..4dc938199d 100644 --- a/Libraries/vendor/emitter/mixInEventEmitter.js +++ b/Libraries/vendor/emitter/mixInEventEmitter.js @@ -49,12 +49,13 @@ var TYPES_KEY = keyOf({__types: true}); */ function mixInEventEmitter(klass, types) { invariant(types, 'Must supply set of valid event types'); - invariant(!this.__eventEmitter, 'An active emitter is already mixed in'); // If this is a constructor, write to the prototype, otherwise write to the // singleton object. var target = klass.prototype || klass; + invariant(!target.__eventEmitter, 'An active emitter is already mixed in'); + var ctor = klass.constructor; if (ctor) { invariant( diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js index 82184c61bb..825399b4a0 100644 --- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js +++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js @@ -58,6 +58,14 @@ describe('Resolver', function() { return module; } + function createPolyfill(id, dependencies) { + var polyfill = new Polyfill({}); + polyfill.getName.mockImpl(() => Promise.resolve(id)); + polyfill.getDependencies.mockImpl(() => Promise.resolve(dependencies)); + polyfill.isPolyfill.mockReturnValue(true); + return polyfill; + } + describe('getDependencies', function() { pit('should get dependencies with polyfills', function() { var module = createModule('index'); @@ -1020,5 +1028,26 @@ describe('Resolver', function() { ].join('\n')); }); }); + + pit('should resolve polyfills', function () { + const depResolver = new Resolver({ + projectRoot: '/root', + }); + const polyfill = createPolyfill('test polyfill', []); + const code = [ + 'global.fetch = () => 1;', + ].join(''); + return depResolver.wrapModule( + null, + polyfill, + code + ).then(processedCode => { + expect(processedCode.code).toEqual([ + '(function(global) {', + 'global.fetch = () => 1;', + "\n})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);", + ].join('')); + }); + }); }); }); diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js index cf021e16f9..0166681f0b 100644 --- a/packager/react-packager/src/Resolver/index.js +++ b/packager/react-packager/src/Resolver/index.js @@ -214,7 +214,9 @@ class Resolver { wrapModule(resolutionResponse, module, code) { if (module.isPolyfill()) { - return Promise.resolve({code}); + return Promise.resolve({ + code: definePolyfillCode(code), + }); } return this.resolveRequires(resolutionResponse, module, code).then( @@ -239,4 +241,12 @@ function defineModuleCode(moduleName, code) { ].join(''); } +function definePolyfillCode(code) { + return [ + '(function(global) {', + code, + `\n})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);`, + ].join(''); +} + module.exports = Resolver; diff --git a/packager/react-packager/src/Resolver/polyfills/Array.prototype.es6.js b/packager/react-packager/src/Resolver/polyfills/Array.prototype.es6.js index 80e62f05de..2752aab5e5 100644 --- a/packager/react-packager/src/Resolver/polyfills/Array.prototype.es6.js +++ b/packager/react-packager/src/Resolver/polyfills/Array.prototype.es6.js @@ -5,54 +5,51 @@ * @polyfill */ -/*eslint-disable */ -/*jslint bitwise: true */ +/* eslint-disable */ -(function(undefined) { - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex - function findIndex(predicate, context) { - if (this == null) { - throw new TypeError( - 'Array.prototype.findIndex called on null or undefined' - ); +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex +function findIndex(predicate, context) { + if (this == null) { + throw new TypeError( + 'Array.prototype.findIndex called on null or undefined' + ); + } + if (typeof predicate !== 'function') { + throw new TypeError('predicate must be a function'); + } + var list = Object(this); + var length = list.length >>> 0; + for (var i = 0; i < length; i++) { + if (predicate.call(context, list[i], i, list)) { + return i; } - if (typeof predicate !== 'function') { - throw new TypeError('predicate must be a function'); - } - var list = Object(this); - var length = list.length >>> 0; - for (var i = 0; i < length; i++) { - if (predicate.call(context, list[i], i, list)) { - return i; + } + return -1; +} + +if (!Array.prototype.findIndex) { + Object.defineProperty(Array.prototype, 'findIndex', { + enumerable: false, + writable: true, + configurable: true, + value: findIndex + }); +} + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find +if (!Array.prototype.find) { + Object.defineProperty(Array.prototype, 'find', { + enumerable: false, + writable: true, + configurable: true, + value: function(predicate, context) { + if (this == null) { + throw new TypeError( + 'Array.prototype.find called on null or undefined' + ); } + var index = findIndex.call(this, predicate, context); + return index === -1 ? undefined : this[index]; } - return -1; - } - - if (!Array.prototype.findIndex) { - Object.defineProperty(Array.prototype, 'findIndex', { - enumerable: false, - writable: true, - configurable: true, - value: findIndex - }); - } - - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find - if (!Array.prototype.find) { - Object.defineProperty(Array.prototype, 'find', { - enumerable: false, - writable: true, - configurable: true, - value: function(predicate, context) { - if (this == null) { - throw new TypeError( - 'Array.prototype.find called on null or undefined' - ); - } - var index = findIndex.call(this, predicate, context); - return index === -1 ? undefined : this[index]; - } - }); - } -})(); + }); +} diff --git a/packager/react-packager/src/Resolver/polyfills/babelHelpers.js b/packager/react-packager/src/Resolver/polyfills/babelHelpers.js index de54ebc2c1..ff44225740 100644 --- a/packager/react-packager/src/Resolver/polyfills/babelHelpers.js +++ b/packager/react-packager/src/Resolver/polyfills/babelHelpers.js @@ -7,8 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -/* global self:true */ -/* eslint-disable strict */ +/* eslint-disable */ // Created by running: // require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toArray toConsumableArray '.split(' ')) @@ -16,217 +15,215 @@ // // actually, that's a lie, because babel6 omits _extends and createRawReactElement -(function (global) { - var babelHelpers = global.babelHelpers = {}; +var babelHelpers = global.babelHelpers = {}; - babelHelpers.createRawReactElement = (function () { - var REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol.for && Symbol.for("react.element") || 0xeac7; - return function createRawReactElement(type, key, props) { - return { - $$typeof: REACT_ELEMENT_TYPE, - type: type, - key: key, - ref: null, - props: props, - _owner: null - }; +babelHelpers.createRawReactElement = (function () { + var REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol.for && Symbol.for("react.element") || 0xeac7; + return function createRawReactElement(type, key, props) { + return { + $$typeof: REACT_ELEMENT_TYPE, + type: type, + key: key, + ref: null, + props: props, + _owner: null }; - })(); - - babelHelpers.classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } }; +})(); - babelHelpers.createClass = (function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } +babelHelpers.classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +}; + +babelHelpers.createClass = (function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); } + } - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; - })(); - - babelHelpers.defineProperty = function (obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; }; +})(); - babelHelpers._extends = babelHelpers.extends = Object.assign || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target; - }; - - babelHelpers.get = function get(object, property, receiver) { - if (object === null) object = Function.prototype; - var desc = Object.getOwnPropertyDescriptor(object, property); - - if (desc === undefined) { - var parent = Object.getPrototypeOf(object); - - if (parent === null) { - return undefined; - } else { - return get(parent, property, receiver); - } - } else if ("value" in desc) { - return desc.value; - } else { - var getter = desc.get; - - if (getter === undefined) { - return undefined; - } - - return getter.call(receiver); - } - }; - - babelHelpers.inherits = function (subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - } - - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: false, - writable: true, - configurable: true - } +babelHelpers.defineProperty = function (obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true }); - if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; - }; + } else { + obj[key] = value; + } - babelHelpers.interopRequireDefault = function (obj) { - return obj && obj.__esModule ? obj : { - default: obj - }; - }; + return obj; +}; - babelHelpers.interopRequireWildcard = function (obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {}; +babelHelpers._extends = babelHelpers.extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; - if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; } - - newObj.default = obj; - return newObj; } - }; + } - babelHelpers.objectWithoutProperties = function (obj, keys) { - var target = {}; + return target; +}; - for (var i in obj) { - if (keys.indexOf(i) >= 0) continue; - if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; - target[i] = obj[i]; +babelHelpers.get = function get(object, property, receiver) { + if (object === null) object = Function.prototype; + var desc = Object.getOwnPropertyDescriptor(object, property); + + if (desc === undefined) { + var parent = Object.getPrototypeOf(object); + + if (parent === null) { + return undefined; + } else { + return get(parent, property, receiver); + } + } else if ("value" in desc) { + return desc.value; + } else { + var getter = desc.get; + + if (getter === undefined) { + return undefined; } - return target; - }; + return getter.call(receiver); + } +}; - babelHelpers.possibleConstructorReturn = function (self, call) { - if (!self) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); +babelHelpers.inherits = function (subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; +}; + +babelHelpers.interopRequireDefault = function (obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +}; + +babelHelpers.interopRequireWildcard = function (obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {}; + + if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } } - return call && (typeof call === "object" || typeof call === "function") ? call : self; - }; + newObj.default = obj; + return newObj; + } +}; - babelHelpers.slicedToArray = (function () { - function sliceIterator(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; +babelHelpers.objectWithoutProperties = function (obj, keys) { + var target = {}; + for (var i in obj) { + if (keys.indexOf(i) >= 0) continue; + if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; + target[i] = obj[i]; + } + + return target; +}; + +babelHelpers.possibleConstructorReturn = function (self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && (typeof call === "object" || typeof call === "function") ? call : self; +}; + +babelHelpers.slicedToArray = (function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; + if (!_n && _i["return"]) _i["return"](); } finally { - try { - if (!_n && _i["return"]) _i["return"](); - } finally { - if (_d) throw _e; - } + if (_d) throw _e; } - - return _arr; } - return function (arr, i) { - if (Array.isArray(arr)) { - return arr; - } else if (Symbol.iterator in Object(arr)) { - return sliceIterator(arr, i); - } else { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - }; - })(); - - babelHelpers.taggedTemplateLiteral = function (strings, raw) { - return Object.freeze(Object.defineProperties(strings, { - raw: { - value: Object.freeze(raw) - } - })); - }; + return _arr; + } - babelHelpers.toArray = function (arr) { - return Array.isArray(arr) ? arr : Array.from(arr); - }; - - babelHelpers.toConsumableArray = function (arr) { + return function (arr, i) { if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - - return arr2; + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); } else { - return Array.from(arr); + throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; -})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this); +})(); + +babelHelpers.taggedTemplateLiteral = function (strings, raw) { + return Object.freeze(Object.defineProperties(strings, { + raw: { + value: Object.freeze(raw) + } + })); +}; + +babelHelpers.toArray = function (arr) { + return Array.isArray(arr) ? arr : Array.from(arr); +}; + +babelHelpers.toConsumableArray = function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } else { + return Array.from(arr); + } +}; diff --git a/packager/react-packager/src/Resolver/polyfills/console.js b/packager/react-packager/src/Resolver/polyfills/console.js index a8e5a72f41..5406db73e6 100644 --- a/packager/react-packager/src/Resolver/polyfills/console.js +++ b/packager/react-packager/src/Resolver/polyfills/console.js @@ -14,495 +14,492 @@ * @nolint */ -(function(global) { - 'use strict'; +/* eslint-disable */ - var 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 +var 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: [], - stylize: stylizeNoColor - }; - return formatValue(ctx, obj, opts.depth); + function inspect(obj, opts) { + var ctx = { + seen: [], + 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) { + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; } - function stylizeNoColor(str, styleType) { - return str; + // 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); } - function arrayToHash(array) { - var hash = {}; - - array.forEach(function(val, idx) { - hash[val] = true; - }); - - return hash; - } - - - function formatValue(ctx, value, recurseTimes) { - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; + // 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'); } - - // 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)) { + 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); } + } - // 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 = ['{', '}']; - var base = '', array = false, braces = ['{', '}']; + // Make Array say that they are Array + if (isArray(value)) { + array = true; + 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 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 RegExps say that they are RegExps + // 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)) { - 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); + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); + return ctx.stylize('[Object]', 'special'); } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); } + ctx.seen.push(value); - 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)); - } + 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); }); - return output; } + ctx.seen.pop(); - 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'); + 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 = ctx.stylize('[Getter]', 'special'); + 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 { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } + str = ctx.stylize('[Circular]', 'special'); } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; } - 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'); - } + 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'); } - 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 isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; + } + + function objectToString(o) { + return Object.prototype.toString.call(o); + } + + function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); + } + + return inspect; +})(); + + +var OBJECT_COLUMN_NAME = '(index)'; +var LOG_LEVELS = { + trace: 0, + info: 1, + warn: 2, + error: 3 +}; + +function setupConsole(global) { + if (!global.nativeLoggingHook) { + return; + } + + function getNativeLogFunction(level) { + return function() { + var 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(', '); } - 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]; + var logLevel = level; + if (str.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; } + global.nativeLoggingHook(str, logLevel); + }; + } - 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 isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; - } - - function objectToString(o) { - return Object.prototype.toString.call(o); - } - - function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); - } - - return inspect; - })(); - - - var OBJECT_COLUMN_NAME = '(index)'; - var LOG_LEVELS = { - trace: 0, - info: 1, - warn: 2, - error: 3 + var repeat = function(element, n) { + return Array.apply(null, Array(n)).map(function() { return element; }); }; - function setupConsole(global) { - if (!global.nativeLoggingHook) { + 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; } - function getNativeLogFunction(level) { - return function() { - var 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(', '); - } + var columns = Object.keys(rows[0]).sort(); + var stringRows = []; + var columnWidths = []; - var logLevel = level; - if (str.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; - } - global.nativeLoggingHook(str, logLevel); - }; - } - - var repeat = function(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); - } - } + // 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); } - 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 | alligned) - var joinRow = function(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); - } - - // Preserve the original `console` as `originalConsole` - var originalConsole = global.console; - var descriptor = Object.getOwnPropertyDescriptor(global, 'console'); - if (descriptor) { - Object.defineProperty(global, 'originalConsole', descriptor); - } - - var 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), - table: consoleTablePolyfill - }; - - // don't reassign to the original descriptor. breaks on ios7 - Object.defineProperty(global, 'console', { - value: console, - configurable: descriptor ? descriptor.configurable : true, - enumerable: descriptor ? descriptor.enumerable : true, - writable: descriptor ? descriptor.writable : true, }); - // 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 => { - var reactNativeMethod = console[methodName]; - if (originalConsole[methodName]) { - console[methodName] = function() { - originalConsole[methodName](...arguments); - reactNativeMethod.apply(console, arguments); - }; - } + // Join all elements in the row into a single string with | separators + // (appends extra spaces to each cell to make separators | alligned) + var joinRow = function(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); } - if (typeof module !== 'undefined') { - module.exports = setupConsole; - } else { - setupConsole(global); + // Preserve the original `console` as `originalConsole` + var originalConsole = global.console; + var descriptor = Object.getOwnPropertyDescriptor(global, 'console'); + if (descriptor) { + Object.defineProperty(global, 'originalConsole', descriptor); } -})(this); + var 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), + table: consoleTablePolyfill + }; + + // don't reassign to the original descriptor. breaks on ios7 + Object.defineProperty(global, 'console', { + value: console, + configurable: descriptor ? descriptor.configurable : true, + enumerable: descriptor ? descriptor.enumerable : true, + writable: descriptor ? descriptor.writable : true, + }); + + // 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 => { + var reactNativeMethod = console[methodName]; + if (originalConsole[methodName]) { + console[methodName] = function() { + originalConsole[methodName](...arguments); + reactNativeMethod.apply(console, arguments); + }; + } + }); + } +} + +if (typeof module !== 'undefined') { + module.exports = setupConsole; +} else { + setupConsole(global); +} diff --git a/packager/react-packager/src/Resolver/polyfills/error-guard.js b/packager/react-packager/src/Resolver/polyfills/error-guard.js index ac99cadca5..8810a4b12a 100644 --- a/packager/react-packager/src/Resolver/polyfills/error-guard.js +++ b/packager/react-packager/src/Resolver/polyfills/error-guard.js @@ -13,74 +13,72 @@ * before any of the modules, this ErrorUtils must be defined (and the handler * set) globally before requiring anything. */ -/* eslint global-strict:0 */ -(function(global) { - var ErrorUtils = { - _inGuard: 0, - _globalHandler: null, - setGlobalHandler: function(fun) { - ErrorUtils._globalHandler = fun; - }, - reportError: function(error) { - ErrorUtils._globalHandler && ErrorUtils._globalHandler(error); - }, - reportFatalError: function(error) { - ErrorUtils._globalHandler && ErrorUtils._globalHandler(error, true); - }, - applyWithGuard: function(fun, context, args) { - try { - ErrorUtils._inGuard++; - return fun.apply(context, args); - } catch (e) { - ErrorUtils.reportError(e); - } finally { - ErrorUtils._inGuard--; - } - }, - applyWithGuardIfNeeded: function(fun, context, args) { - if (ErrorUtils.inGuard()) { - return fun.apply(context, args); - } else { - ErrorUtils.applyWithGuard(fun, context, args); - } - }, - inGuard: function() { - return ErrorUtils._inGuard; - }, - guard: function(fun, name, context) { - if (typeof fun !== 'function') { - console.warn('A function must be passed to ErrorUtils.guard, got ', fun); - return null; - } - name = name || fun.name || ''; - function guarded() { - return ( - ErrorUtils.applyWithGuard( - fun, - context || this, - arguments, - null, - name - ) - ); - } - - return guarded; +/* eslint strict:0 */ +var ErrorUtils = { + _inGuard: 0, + _globalHandler: null, + setGlobalHandler: function(fun) { + ErrorUtils._globalHandler = fun; + }, + reportError: function(error) { + ErrorUtils._globalHandler && ErrorUtils._globalHandler(error); + }, + reportFatalError: function(error) { + ErrorUtils._globalHandler && ErrorUtils._globalHandler(error, true); + }, + applyWithGuard: function(fun, context, args) { + try { + ErrorUtils._inGuard++; + return fun.apply(context, args); + } catch (e) { + ErrorUtils.reportError(e); + } finally { + ErrorUtils._inGuard--; + } + }, + applyWithGuardIfNeeded: function(fun, context, args) { + if (ErrorUtils.inGuard()) { + return fun.apply(context, args); + } else { + ErrorUtils.applyWithGuard(fun, context, args); + } + }, + inGuard: function() { + return ErrorUtils._inGuard; + }, + guard: function(fun, name, context) { + if (typeof fun !== 'function') { + console.warn('A function must be passed to ErrorUtils.guard, got ', fun); + return null; + } + name = name || fun.name || ''; + function guarded() { + return ( + ErrorUtils.applyWithGuard( + fun, + context || this, + arguments, + null, + name + ) + ); } - }; - global.ErrorUtils = ErrorUtils; - /** - * This is the error handler that is called when we encounter an exception - * when loading a module. This will report any errors encountered before - * ExceptionsManager is configured. - */ - function setupErrorGuard() { - var onError = function(e) { - global.console.error('Error: ' + e.message + ', stack:\n' + e.stack); - }; - global.ErrorUtils.setGlobalHandler(onError); + return guarded; } +}; +global.ErrorUtils = ErrorUtils; - setupErrorGuard(); -})(this); +/** + * This is the error handler that is called when we encounter an exception + * when loading a module. This will report any errors encountered before + * ExceptionsManager is configured. + */ +function setupErrorGuard() { + var onError = function(e) { + global.console.error('Error: ' + e.message + ', stack:\n' + e.stack); + }; + global.ErrorUtils.setGlobalHandler(onError); +} + +setupErrorGuard(); diff --git a/packager/react-packager/src/Resolver/polyfills/loadBundles.js b/packager/react-packager/src/Resolver/polyfills/loadBundles.js index 4e893eda9c..7bb9be104a 100644 --- a/packager/react-packager/src/Resolver/polyfills/loadBundles.js +++ b/packager/react-packager/src/Resolver/polyfills/loadBundles.js @@ -1,50 +1,34 @@ -/* eslint global-strict:0 */ -(global => { - let loadBundlesOnNative = (bundles) => - new Promise((resolve) => - require('NativeModules').RCTBundlesLoader.loadBundles(bundles, resolve)); +/* eslint strict:0 */ - let requestedBundles = Object.create(null); +let loadBundlesOnNative = (bundles) => + new Promise((resolve) => + require('NativeModules').RCTBundlesLoader.loadBundles(bundles, resolve)); - /** - * Returns a promise that is fulfilled once all the indicated bundles are - * loaded into memory and injected into the JS engine. - * This invokation might need to go through the bridge - * and run native code to load some, if not all, the requested bundles. - * If all the bundles have already been loaded, the promise is resolved - * immediately. Otherwise, we'll determine which bundles still need to get - * loaded considering both, the ones already loaded, and the ones being - * currently asynchronously loaded by other invocations to `__loadBundles`, - * and return a promise that will get fulfilled once all these are finally - * loaded. - * - * Note this function should only be invoked by generated code. - */ - global.__loadBundles = function(bundles) { - // split bundles by whether they've already been requested or not - const bundlesToRequest = bundles.filter(b => !requestedBundles[b]); - const bundlesAlreadyRequested = bundles.filter(b => !!requestedBundles[b]); +let requestedBundles = Object.create(null); - // keep a reference to the promise loading each bundle - if (bundlesToRequest.length > 0) { - const nativePromise = loadBundlesOnNative(bundlesToRequest); - bundlesToRequest.forEach(b => requestedBundles[b] = nativePromise); - } +/** + * Returns a promise that is fulfilled once all the indicated bundles are + * loaded into memory and injected into the JS engine. + * This invokation might need to go through the bridge + * and run native code to load some, if not all, the requested bundles. + * If all the bundles have already been loaded, the promise is resolved + * immediately. Otherwise, we'll determine which bundles still need to get + * loaded considering both, the ones already loaded, and the ones being + * currently asynchronously loaded by other invocations to `__loadBundles`, + * and return a promise that will get fulfilled once all these are finally + * loaded. + * + * Note this function should only be invoked by generated code. + */ +global.__loadBundles = function(bundles) { + // split bundles by whether they've already been requested or not + const bundlesToRequest = bundles.filter(b => !requestedBundles[b]); - return Promise.all(bundles.map(bundle => requestedBundles[bundle])); - }; -})(global); + // keep a reference to the promise loading each bundle + if (bundlesToRequest.length > 0) { + const nativePromise = loadBundlesOnNative(bundlesToRequest); + bundlesToRequest.forEach(b => requestedBundles[b] = nativePromise); + } - -// turns a callback async based function into a promised based one -function promisify(fn) { - return function() { - var self = this; - var args = Array.prototype.slice.call(arguments); - - return new Promise((resolve, reject) => { - args.push(resolve); - fn.apply(self, args); - }); - }; -} + return Promise.all(bundles.map(bundle => requestedBundles[bundle])); +}; diff --git a/packager/react-packager/src/Resolver/polyfills/polyfills.js b/packager/react-packager/src/Resolver/polyfills/polyfills.js index 9698b4911d..5652334218 100644 --- a/packager/react-packager/src/Resolver/polyfills/polyfills.js +++ b/packager/react-packager/src/Resolver/polyfills/polyfills.js @@ -15,7 +15,7 @@ // WARNING: This is an optimized version that fails on hasOwnProperty checks // and non objects. It's not spec-compliant. It's a perf optimization. -/* eslint global-strict:0 */ +/* eslint strict:0 */ Object.assign = function(target, sources) { if (__DEV__) { if (target == null) { diff --git a/packager/react-packager/src/Resolver/polyfills/prelude.js b/packager/react-packager/src/Resolver/polyfills/prelude.js index a1004b7d4c..02386ae101 100644 --- a/packager/react-packager/src/Resolver/polyfills/prelude.js +++ b/packager/react-packager/src/Resolver/polyfills/prelude.js @@ -1,5 +1,4 @@ -/* eslint global-strict:0 */ -__DEV__ = false; +/* eslint strict:0 */ +global.__DEV__ = false; -/* global __BUNDLE_START_TIME__:true */ -__BUNDLE_START_TIME__ = Date.now(); +global.__BUNDLE_START_TIME__ = Date.now(); diff --git a/packager/react-packager/src/Resolver/polyfills/prelude_dev.js b/packager/react-packager/src/Resolver/polyfills/prelude_dev.js index 14b97faad6..99b9de2c11 100644 --- a/packager/react-packager/src/Resolver/polyfills/prelude_dev.js +++ b/packager/react-packager/src/Resolver/polyfills/prelude_dev.js @@ -1,5 +1,4 @@ -/* eslint global-strict:0 */ -__DEV__ = true; +/* eslint strict:0 */ +global.__DEV__ = true; -/* global __BUNDLE_START_TIME__:true */ -__BUNDLE_START_TIME__ = Date.now(); +global.__BUNDLE_START_TIME__ = Date.now(); diff --git a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js index 1ea71705d4..c6c7cbc79c 100644 --- a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js +++ b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js @@ -1,73 +1,70 @@ 'use strict'; -((global) => { - const {ErrorUtils, __nativeRequire} = global; - global.require = require; - global.__d = define; +const {ErrorUtils, __nativeRequire} = global; +global.require = require; +global.__d = define; - const modules = Object.create(null); +const modules = Object.create(null); - const loadModule = ErrorUtils ? - guardedLoadModule : loadModuleImplementation; +const loadModule = ErrorUtils ? + guardedLoadModule : loadModuleImplementation; - function define(moduleId, factory) { - modules[moduleId] = { - factory, - hasError: false, - exports: undefined, - }; +function define(moduleId, factory) { + modules[moduleId] = { + factory, + hasError: false, + exports: undefined, + }; +} + +function require(moduleId) { + const module = modules[moduleId]; + return module && module.exports || loadModule(moduleId, module); +} + +function guardedLoadModule(moduleId, module) { + try { + return loadModuleImplementation(moduleId, module); + } catch (e) { + ErrorUtils.reportFatalError(e); + } +} + +function loadModuleImplementation(moduleId, module) { + if (!module) { + __nativeRequire(moduleId); + module = modules[moduleId]; } - function require(moduleId) { - const module = modules[moduleId]; - return module && module.exports || loadModule(moduleId, module); + if (!module) { + throw unknownModuleError(moduleId); } - function guardedLoadModule(moduleId, module) { - try { - return loadModuleImplementation(moduleId, module); - } catch (e) { - ErrorUtils.reportFatalError(e); - } + if (module.hasError) { + throw moduleThrewError(moduleId); } - function loadModuleImplementation(moduleId, module) { - if (!module) { - __nativeRequire(moduleId); - module = modules[moduleId]; - } - - if (!module) { - throw unknownModuleError(moduleId); - } - - if (module.hasError) { - throw moduleThrewError(moduleId); - } - - const exports = module.exports = {}; - const {factory} = module; - try { - const moduleObject = {exports}; - factory(global, require, moduleObject, exports); - return (module.exports = moduleObject.exports); - } catch(e) { - module.hasError = true; - module.exports = undefined; - } + const exports = module.exports = {}; + const {factory} = module; + try { + const moduleObject = {exports}; + factory(global, require, moduleObject, exports); + return (module.exports = moduleObject.exports); + } catch (e) { + module.hasError = true; + module.exports = undefined; } +} - function unknownModuleError(id) { - let message = 'Requiring unknown module "' + id + '".'; - if (__DEV__) { - message += - 'If you are sure the module is there, try restarting the packager.'; - } - return Error(message); +function unknownModuleError(id) { + let message = 'Requiring unknown module "' + id + '".'; + if (__DEV__) { + message += + 'If you are sure the module is there, try restarting the packager.'; } + return Error(message); +} - function moduleThrewError(id) { - return Error('Requiring module "' + id + '", which threw an exception.'); - } - -})(this); +function moduleThrewError(id) { + return Error('Requiring module "' + id + '", which threw an exception.'); +} diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js index 36c2b6b90d..a5a7a55f01 100644 --- a/packager/react-packager/src/Resolver/polyfills/require.js +++ b/packager/react-packager/src/Resolver/polyfills/require.js @@ -1,130 +1,128 @@ /* eslint strict:0 */ -(function(global) { - var modules = Object.create(null); - var inGuard = false; +var modules = Object.create(null); +var inGuard = false; - function define(id, factory) { - modules[id] = { - factory, - module: {exports: {}}, - isInitialized: false, - hasError: false, - }; +function define(id, factory) { + modules[id] = { + factory, + module: {exports: {}}, + isInitialized: false, + hasError: false, + }; - if (__DEV__) { // HMR - Object.assign(modules[id].module, { - hot: { - acceptCallback: null, - accept: function(callback) { - modules[id].module.hot.acceptCallback = callback; - } + if (__DEV__) { // HMR + Object.assign(modules[id].module, { + hot: { + acceptCallback: null, + accept: function(callback) { + modules[id].module.hot.acceptCallback = callback; } - }); - } - } - - function require(id) { - var mod = modules[id]; - if (mod && mod.isInitialized) { - return mod.module.exports; - } - - return requireImpl(id); - } - - function requireImpl(id) { - if (global.ErrorUtils && !inGuard) { - inGuard = true; - var returnValue; - try { - returnValue = requireImpl.apply(this, arguments); - } catch (e) { - global.ErrorUtils.reportFatalError(e); } - inGuard = false; - return returnValue; - } - - var mod = modules[id]; - if (!mod) { - var msg = 'Requiring unknown module "' + id + '"'; - if (__DEV__) { - msg += '. If you are sure the module is there, try restarting the packager.'; - } - throw new Error(msg); - } - - if (mod.hasError) { - throw new Error( - 'Requiring module "' + id + '" which threw an exception' - ); - } - - try { - // We must optimistically mark mod as initialized before running the factory to keep any - // require cycles inside the factory from causing an infinite require loop. - mod.isInitialized = true; - - __DEV__ && Systrace().beginEvent('JS_require_' + id); - - // keep args in sync with with defineModuleCode in - // packager/react-packager/src/Resolver/index.js - mod.factory.call(global, global, require, mod.module, mod.module.exports); - - __DEV__ && Systrace().endEvent(); - } catch (e) { - mod.hasError = true; - mod.isInitialized = false; - throw e; - } + }); + } +} +function require(id) { + var mod = modules[id]; + if (mod && mod.isInitialized) { return mod.module.exports; } - const Systrace = __DEV__ && (() => { - var _Systrace; + return requireImpl(id); +} + +function requireImpl(id) { + if (global.ErrorUtils && !inGuard) { + inGuard = true; + var returnValue; try { - _Systrace = require('Systrace'); - } catch(e) {} + returnValue = requireImpl.apply(this, arguments); + } catch (e) { + global.ErrorUtils.reportFatalError(e); + } + inGuard = false; + return returnValue; + } - return _Systrace && _Systrace.beginEvent ? - _Systrace : { beginEvent: () => {}, endEvent: () => {} }; - }); + var mod = modules[id]; + if (!mod) { + var msg = 'Requiring unknown module "' + id + '"'; + if (__DEV__) { + msg += '. If you are sure the module is there, try restarting the packager.'; + } + throw new Error(msg); + } - global.__d = define; - global.require = require; + if (mod.hasError) { + throw new Error( + 'Requiring module "' + id + '" which threw an exception' + ); + } - if (__DEV__) { // HMR - function accept(id, factory) { - var mod = modules[id]; + try { + // We must optimistically mark mod as initialized before running the factory to keep any + // require cycles inside the factory from causing an infinite require loop. + mod.isInitialized = true; - if (!mod) { - define(id, factory); - return; // new modules don't need to be accepted - } + __DEV__ && Systrace().beginEvent('JS_require_' + id); - if (!mod.module.hot) { - console.warn( - 'Cannot accept module because Hot Module Replacement ' + - 'API was not installed.' - ); - return; - } + // keep args in sync with with defineModuleCode in + // packager/react-packager/src/Resolver/index.js + mod.factory.call(global, global, require, mod.module, mod.module.exports); - if (mod.module.hot.acceptCallback) { - mod.factory = factory; - mod.isInitialized = false; - require(id); + __DEV__ && Systrace().endEvent(); + } catch (e) { + mod.hasError = true; + mod.isInitialized = false; + throw e; + } - mod.module.hot.acceptCallback(); - } else { - console.warn( - '[HMR] Module `' + id + '` can\'t be hot reloaded because it ' + - 'doesn\'t provide accept callback hook. Reload the app to get the updates.' - ); - } + return mod.module.exports; +} + +const Systrace = __DEV__ && (() => { + var _Systrace; + try { + _Systrace = require('Systrace'); + } catch (e) {} + + return _Systrace && _Systrace.beginEvent ? + _Systrace : { beginEvent: () => {}, endEvent: () => {} }; +}); + +global.__d = define; +global.require = require; + +if (__DEV__) { // HMR + function accept(id, factory) { + var mod = modules[id]; + + if (!mod) { + define(id, factory); + return; // new modules don't need to be accepted } - global.__accept = accept; + if (!mod.module.hot) { + console.warn( + 'Cannot accept module because Hot Module Replacement ' + + 'API was not installed.' + ); + return; + } + + if (mod.module.hot.acceptCallback) { + mod.factory = factory; + mod.isInitialized = false; + require(id); + + mod.module.hot.acceptCallback(); + } else { + console.warn( + '[HMR] Module `' + id + '` can\'t be hot reloaded because it ' + + 'doesn\'t provide accept callback hook. Reload the app to get the updates.' + ); + } } -})(this); + + global.__accept = accept; +} diff --git a/packager/react-packager/src/transforms/whole-program-optimisations/__tests__/dead-module-elimination-test.js b/packager/react-packager/src/transforms/whole-program-optimisations/__tests__/dead-module-elimination-test.js index 7525fd0f01..4d7d142c48 100644 --- a/packager/react-packager/src/transforms/whole-program-optimisations/__tests__/dead-module-elimination-test.js +++ b/packager/react-packager/src/transforms/whole-program-optimisations/__tests__/dead-module-elimination-test.js @@ -33,7 +33,7 @@ const trim = (str) => describe('dead-module-elimination', () => { it('should inline __DEV__', () => { compare( - `__DEV__ = false; + `global.__DEV__ = false; var foo = __DEV__;`, `var foo = false;` ); @@ -41,7 +41,7 @@ describe('dead-module-elimination', () => { it('should accept unary operators with literals', () => { compare( - `__DEV__ = !1; + `global.__DEV__ = !1; var foo = __DEV__;`, `var foo = false;` ); @@ -49,7 +49,7 @@ describe('dead-module-elimination', () => { it('should kill dead branches', () => { compare( - `__DEV__ = false; + `global.__DEV__ = false; if (__DEV__) { doSomething(); }`, @@ -74,7 +74,7 @@ describe('dead-module-elimination', () => { it('should kill modules referenced only from dead branches', () => { compare( - `__DEV__ = false; + `global.__DEV__ = false; __d('bar', function() {}); if (__DEV__) { require('bar'); }`, `` @@ -83,7 +83,7 @@ describe('dead-module-elimination', () => { it('should replace logical expressions with the result', () => { compare( - `__DEV__ = false; + `global.__DEV__ = false; __d('bar', function() {}); __DEV__ && require('bar');`, `false;` @@ -92,7 +92,7 @@ describe('dead-module-elimination', () => { it('should keep if result branch', () => { compare( - `__DEV__ = false; + `global.__DEV__ = false; __d('bar', function() {}); if (__DEV__) { killWithFire(); @@ -106,7 +106,7 @@ describe('dead-module-elimination', () => { it('should replace falsy ternaries with alternate expression', () => { compare( - `__DEV__ = false; + `global.__DEV__ = false; __DEV__ ? foo() : bar(); `, `bar();` diff --git a/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js b/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js index 39eeb0a6c2..1d6c8f340f 100644 --- a/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js +++ b/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js @@ -60,7 +60,12 @@ module.exports = function () { AssignmentExpression(path) { const { node } = path; - if (node.left.type === 'Identifier' && node.left.name === '__DEV__') { + if ( + node.left.type === 'MemberExpression' && + node.left.object.name === 'global' && + node.left.property.type === 'Identifier' && + node.left.property.name === '__DEV__' + ) { var value; if (node.right.type === 'BooleanLiteral') { value = node.right.value; @@ -73,7 +78,7 @@ module.exports = function () { } else { return; } - globals[node.left.name] = value; + globals[node.left.property.name] = value; // workaround babel/source map bug - the minifier should strip it path.replaceWith(t.booleanLiteral(value));