diff --git a/Libraries/polyfills/Array.es6.js b/Libraries/polyfills/Array.es6.js new file mode 100644 index 0000000000..87c83ed256 --- /dev/null +++ b/Libraries/polyfills/Array.es6.js @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @polyfill + */ + +/* eslint-disable */ + +/** + * Creates an array from array like objects. + * + * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from + */ +if (!Array.from) { + Array.from = function(arrayLike /*, mapFn, thisArg */) { + if (arrayLike == null) { + throw new TypeError('Object is null or undefined'); + } + + // Optional args. + var mapFn = arguments[1]; + var thisArg = arguments[2]; + + var C = this; + var items = Object(arrayLike); + var symbolIterator = typeof Symbol === 'function' + ? Symbol.iterator + : '@@iterator'; + var mapping = typeof mapFn === 'function'; + var usingIterator = typeof items[symbolIterator] === 'function'; + var key = 0; + var ret; + var value; + + if (usingIterator) { + ret = typeof C === 'function' + ? new C() + : []; + var it = items[symbolIterator](); + var next; + + while (!(next = it.next()).done) { + value = next.value; + + if (mapping) { + value = mapFn.call(thisArg, value, key); + } + + ret[key] = value; + key += 1; + } + + ret.length = key; + return ret; + } + + var len = items.length; + if (isNaN(len) || len < 0) { + len = 0; + } + + ret = typeof C === 'function' + ? new C(len) + : new Array(len); + + while (key < len) { + value = items[key]; + + if (mapping) { + value = mapFn.call(thisArg, value, key); + } + + ret[key] = value; + + key += 1; + } + + ret.length = key; + return ret; + }; +} diff --git a/Libraries/polyfills/Array.prototype.es6.js b/Libraries/polyfills/Array.prototype.es6.js new file mode 100644 index 0000000000..612d3c3849 --- /dev/null +++ b/Libraries/polyfills/Array.prototype.es6.js @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @polyfill + */ + +/* eslint-disable */ + +// 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; + } + } + 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]; + } + }); +} + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes +if (!Array.prototype.includes) { + Object.defineProperty(Array.prototype, 'includes', { + enumerable: false, + writable: true, + configurable: true, + value: function (searchElement) { + var O = Object(this); + var len = parseInt(O.length) || 0; + if (len === 0) { + return false; + } + var n = parseInt(arguments[1]) || 0; + var k; + if (n >= 0) { + k = n; + } else { + k = len + n; + if (k < 0) { + k = 0; + } + } + var currentElement; + while (k < len) { + currentElement = O[k]; + if (searchElement === currentElement || + (searchElement !== searchElement && currentElement !== currentElement)) { + return true; + } + k++; + } + return false; + } + }); +} diff --git a/Libraries/polyfills/Number.es6.js b/Libraries/polyfills/Number.es6.js new file mode 100644 index 0000000000..bd669c3c4b --- /dev/null +++ b/Libraries/polyfills/Number.es6.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @polyfill + */ + +/* eslint-disable strict */ + +if (Number.EPSILON === undefined) { + Object.defineProperty(Number, 'EPSILON', { + value: Math.pow(2, -52), + }); +} +if (Number.MAX_SAFE_INTEGER === undefined) { + Object.defineProperty(Number, 'MAX_SAFE_INTEGER', { + value: Math.pow(2, 53) - 1, + }); +} +if (Number.MIN_SAFE_INTEGER === undefined) { + Object.defineProperty(Number, 'MIN_SAFE_INTEGER', { + value: -(Math.pow(2, 53) - 1), + }); +} +if (!Number.isNaN) { + // eslint-disable-next-line max-len + // https://github.com/dherman/tc39-codex-wiki/blob/master/data/es6/number/index.md#polyfill-for-numberisnan + const globalIsNaN = global.isNaN; + Object.defineProperty(Number, 'isNaN', { + configurable: true, + enumerable: false, + value: function isNaN(value) { + return typeof value === 'number' && globalIsNaN(value); + }, + writable: true, + }); +} diff --git a/Libraries/polyfills/Object.es6.js b/Libraries/polyfills/Object.es6.js new file mode 100644 index 0000000000..6494366430 --- /dev/null +++ b/Libraries/polyfills/Object.es6.js @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @polyfill + */ + +/* eslint-disable strict */ + +// WARNING: This is an optimized version that fails on hasOwnProperty checks +// and non objects. It's not spec-compliant. It's a perf optimization. +// This is only needed for iOS 8 and current Android JSC. + +Object.assign = function(target, sources) { + if (__DEV__) { + if (target == null) { + throw new TypeError('Object.assign target cannot be null or undefined'); + } + if (typeof target !== 'object' && typeof target !== 'function') { + throw new TypeError( + 'In this environment the target of assign MUST be an object.' + + 'This error is a performance optimization and not spec compliant.' + ); + } + } + + for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) { + var nextSource = arguments[nextIndex]; + if (nextSource == null) { + continue; + } + + if (__DEV__) { + if (typeof nextSource !== 'object' && + typeof nextSource !== 'function') { + throw new TypeError( + 'In this environment the sources for assign MUST be an object.' + + 'This error is a performance optimization and not spec compliant.' + ); + } + } + + // We don't currently support accessors nor proxies. Therefore this + // copy cannot throw. If we ever supported this then we must handle + // exceptions and side-effects. + + for (var key in nextSource) { + if (__DEV__) { + var hasOwnProperty = Object.prototype.hasOwnProperty; + if (!hasOwnProperty.call(nextSource, key)) { + throw new TypeError( + 'One of the sources for assign has an enumerable key on the ' + + 'prototype chain. Are you trying to assign a prototype property? ' + + 'We don\'t allow it, as this is an edge case that we do not support. ' + + 'This error is a performance optimization and not spec compliant.' + ); + } + } + target[key] = nextSource[key]; + } + } + + return target; +}; diff --git a/Libraries/polyfills/Object.es7.js b/Libraries/polyfills/Object.es7.js new file mode 100644 index 0000000000..dc5dc893b5 --- /dev/null +++ b/Libraries/polyfills/Object.es7.js @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @polyfill + */ + +(function() { + 'use strict'; + + const hasOwnProperty = Object.prototype.hasOwnProperty; + + /** + * Returns an array of the given object's own enumerable entries. + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries + */ + if (typeof Object.entries !== 'function') { + Object.entries = function(object) { + // `null` and `undefined` values are not allowed. + if (object == null) { + throw new TypeError('Object.entries called on non-object'); + } + + const entries = []; + for (const key in object) { + if (hasOwnProperty.call(object, key)) { + entries.push([key, object[key]]); + } + } + return entries; + }; + } + + /** + * Returns an array of the given object's own enumerable entries. + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values + */ + if (typeof Object.values !== 'function') { + Object.values = function(object) { + // `null` and `undefined` values are not allowed. + if (object == null) { + throw new TypeError('Object.values called on non-object'); + } + + const values = []; + for (const key in object) { + if (hasOwnProperty.call(object, key)) { + values.push(object[key]); + } + } + return values; + }; + } + +})(); diff --git a/Libraries/polyfills/String.prototype.es6.js b/Libraries/polyfills/String.prototype.es6.js new file mode 100644 index 0000000000..a033f35efd --- /dev/null +++ b/Libraries/polyfills/String.prototype.es6.js @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @polyfill + */ + +/* eslint-disable strict, no-extend-native, no-bitwise */ + +/* + * NOTE: We use (Number(x) || 0) to replace NaN values with zero. + */ + +if (!String.prototype.startsWith) { + String.prototype.startsWith = function(search) { + 'use strict'; + if (this == null) { + throw TypeError(); + } + var string = String(this); + var pos = arguments.length > 1 ? + (Number(arguments[1]) || 0) : 0; + var start = Math.min(Math.max(pos, 0), string.length); + return string.indexOf(String(search), pos) === start; + }; +} + +if (!String.prototype.endsWith) { + String.prototype.endsWith = function(search) { + 'use strict'; + if (this == null) { + throw TypeError(); + } + var string = String(this); + var stringLength = string.length; + var searchString = String(search); + var pos = arguments.length > 1 ? + (Number(arguments[1]) || 0) : stringLength; + var end = Math.min(Math.max(pos, 0), stringLength); + var start = end - searchString.length; + if (start < 0) { + return false; + } + return string.lastIndexOf(searchString, start) === start; + }; +} + +if (!String.prototype.repeat) { + String.prototype.repeat = function(count) { + 'use strict'; + if (this == null) { + throw TypeError(); + } + var string = String(this); + count = Number(count) || 0; + if (count < 0 || count === Infinity) { + throw RangeError(); + } + if (count === 1) { + return string; + } + var result = ''; + while (count) { + if (count & 1) { + result += string; + } + if ((count >>= 1)) { + string += string; + } + } + return result; + }; +} + +if (!String.prototype.includes) { + String.prototype.includes = function(search, start) { + 'use strict'; + if (typeof start !== 'number') { + start = 0; + } + + if (start + search.length > this.length) { + return false; + } else { + return this.indexOf(search, start) !== -1; + } + }; +} diff --git a/Libraries/polyfills/__tests__/Object.es7-test.js b/Libraries/polyfills/__tests__/Object.es7-test.js new file mode 100644 index 0000000000..e820848d97 --- /dev/null +++ b/Libraries/polyfills/__tests__/Object.es7-test.js @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @emails oncall+jsinfra + */ + +/* eslint-disable fb-www/object-create-only-one-param */ + +'use strict'; + +describe('Object (ES7)', () => { + beforeEach(() => { + delete Object.entries; + delete Object.values; + jest.resetModules(); + require('../Object.es7'); + }); + + describe('Object.entries', () => { + it('should have a length of 1', () => { + expect(Object.entries.length).toBe(1); + }); + + it('should check for type', () => { + expect(Object.entries.bind(null, null)).toThrow(TypeError( + 'Object.entries called on non-object' + )); + expect(Object.entries.bind(null, undefined)).toThrow(TypeError( + 'Object.entries called on non-object' + )); + expect(Object.entries.bind(null, [])).not.toThrow(); + expect(Object.entries.bind(null, () => {})).not.toThrow(); + expect(Object.entries.bind(null, {})).not.toThrow(); + expect(Object.entries.bind(null, 'abc')).not.toThrow(); + }); + + it('should return enumerable entries', () => { + const foo = Object.defineProperties({}, { + x: {value: 10, enumerable: true}, + y: {value: 20}, + }); + + expect(Object.entries(foo)).toEqual([['x', 10]]); + + const bar = {x: 10, y: 20}; + expect(Object.entries(bar)).toEqual([['x', 10], ['y', 20]]); + }); + + it('should work with proto-less objects', () => { + const foo = Object.create(null, { + x: {value: 10, enumerable: true}, + y: {value: 20}, + }); + + expect(Object.entries(foo)).toEqual([['x', 10]]); + }); + + it('should return only own entries', () => { + const foo = Object.create({z: 30}, { + x: {value: 10, enumerable: true}, + y: {value: 20}, + }); + + expect(Object.entries(foo)).toEqual([['x', 10]]); + }); + + it('should convert to object primitive string', () => { + expect(Object.entries('ab')).toEqual([['0', 'a'], ['1', 'b']]); + }); + }); + + describe('Object.values', () => { + it('should have a length of 1', () => { + expect(Object.values.length).toBe(1); + }); + + it('should check for type', () => { + expect(Object.values.bind(null, null)).toThrow(TypeError( + 'Object.values called on non-object' + )); + expect(Object.values.bind(null, [])).not.toThrow(); + expect(Object.values.bind(null, () => {})).not.toThrow(); + expect(Object.values.bind(null, {})).not.toThrow(); + }); + + it('should return enumerable values', () => { + const foo = Object.defineProperties({}, { + x: {value: 10, enumerable: true}, + y: {value: 20}, + }); + + expect(Object.values(foo)).toEqual([10]); + + const bar = {x: 10, y: 20}; + expect(Object.values(bar)).toEqual([10, 20]); + }); + + it('should work with proto-less objects', () => { + const foo = Object.create(null, { + x: {value: 10, enumerable: true}, + y: {value: 20}, + }); + + expect(Object.values(foo)).toEqual([10]); + }); + + it('should return only own values', () => { + const foo = Object.create({z: 30}, { + x: {value: 10, enumerable: true}, + y: {value: 20}, + }); + + expect(Object.values(foo)).toEqual([10]); + }); + + it('should convert to object primitive string', () => { + expect(Object.values('ab')).toEqual(['a', 'b']); + }); + }); +}); diff --git a/Libraries/polyfills/babelHelpers.js b/Libraries/polyfills/babelHelpers.js new file mode 100644 index 0000000000..51cb4523ec --- /dev/null +++ b/Libraries/polyfills/babelHelpers.js @@ -0,0 +1,247 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @polyfill + */ + +/* 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(' ')) +// then replacing the `global` reference in the last line to also use `this`. +// +// actually, that's a lie, because babel6 omits _extends and createRawReactElement + +var babelHelpers = global.babelHelpers = {}; + +babelHelpers.typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; +}; + +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); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +})(); + +babelHelpers.defineEnumerableProperties = function(obj, descs) { + for (var key in descs) { + var desc = descs[key]; + desc.configurable = (desc.enumerable = true); + if ('value' in desc) desc.writable = true; + Object.defineProperty(obj, key, desc); + } + return obj; +}; + +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; +}; + +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 + } + }); + 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]; + } + } + + newObj.default = obj; + return newObj; + } +}; + +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 { + if (!_n && _i["return"]) _i["return"](); + } finally { + 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) + } + })); +}; + +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/Libraries/polyfills/console.js b/Libraries/polyfills/console.js new file mode 100644 index 0000000000..c0ae004c38 --- /dev/null +++ b/Libraries/polyfills/console.js @@ -0,0 +1,515 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @polyfill + * @nolint + */ + +/* eslint-disable */ + +/** + * 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: [], + 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; + } + + // 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 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; +})(); + + +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; + +if (global.nativeLoggingHook) { + 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(', '); + } + + let 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; + } + if (global.__inspectorLog) { + global.__inspectorLog( + INSPECTOR_LEVELS[logLevel], + str, + [].slice.call(arguments), + INSPECTOR_FRAMES_TO_SKIP); + } + 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 | alligned) + 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 originalConsole = global.console; + 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 + }; + + // 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) { + // Preserve the original `console` as `originalConsole` + const descriptor = Object.getOwnPropertyDescriptor(global, 'console'); + if (descriptor) { + Object.defineProperty(global, 'originalConsole', descriptor); + } + + Object.keys(console).forEach(methodName => { + const reactNativeMethod = console[methodName]; + if (originalConsole[methodName]) { + console[methodName] = function() { + originalConsole[methodName](...arguments); + reactNativeMethod.apply(console, arguments); + }; + } + }); + } +} else if (!global.console) { + function consoleLoggingStub() {}; + global.console = { + error: consoleLoggingStub, + info: consoleLoggingStub, + log: consoleLoggingStub, + warn: consoleLoggingStub, + trace: consoleLoggingStub, + debug: consoleLoggingStub, + table: consoleLoggingStub + }; +} diff --git a/Libraries/polyfills/error-guard.js b/Libraries/polyfills/error-guard.js new file mode 100644 index 0000000000..b933050698 --- /dev/null +++ b/Libraries/polyfills/error-guard.js @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @polyfill + */ + +/* eslint-disable strict */ + +let _inGuard = 0; + +/** + * 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. + */ +let _globalHandler = function onError(e) { + throw e; +}; + +/** + * The particular require runtime that we are using looks for a global + * `ErrorUtils` object and if it exists, then it requires modules with the + * error handler specified via ErrorUtils.setGlobalHandler by calling the + * require function with applyWithGuard. Since the require module is loaded + * before any of the modules, this ErrorUtils must be defined (and the handler + * set) globally before requiring anything. + */ +const ErrorUtils = { + setGlobalHandler(fun) { + _globalHandler = fun; + }, + getGlobalHandler() { + return _globalHandler; + }, + reportError(error) { + _globalHandler && _globalHandler(error); + }, + reportFatalError(error) { + _globalHandler && _globalHandler(error, true); + }, + applyWithGuard(fun, context, args) { + try { + _inGuard++; + return fun.apply(context, args); + } catch (e) { + ErrorUtils.reportError(e); + } finally { + _inGuard--; + } + return null; + }, + applyWithGuardIfNeeded(fun, context, args) { + if (ErrorUtils.inGuard()) { + return fun.apply(context, args); + } else { + ErrorUtils.applyWithGuard(fun, context, args); + } + return null; + }, + inGuard() { + return _inGuard; + }, + guard(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; + }, +}; + +global.ErrorUtils = ErrorUtils; diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index a75d6d5c51..e817c9a19f 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -157,6 +157,7 @@ function getPackagerServer(args, config) { maxWorkers: args.maxWorkers, platforms: defaultPlatforms.concat(args.platforms), polyfillModuleNames: config.getPolyfillModuleNames(), + polyfills: config.polyfills, postMinifyProcess: config.postMinifyProcess, postProcessModules: config.postProcessModules, projectRoots: args.projectRoots, diff --git a/local-cli/util/Config.js b/local-cli/util/Config.js index 3085969f86..c47a576ae4 100644 --- a/local-cli/util/Config.js +++ b/local-cli/util/Config.js @@ -90,6 +90,12 @@ export type ConfigT = { */ getWorkerPath: () => ?string, + /** + * An optional list of polyfills to include in the bundle. The list defaults + * to a set of common polyfills for Number, String, Array, Object... + */ + polyfills: Array, + /** * An optional function that can modify the code and source map of bundle * after the minifaction took place. (Function applied per module). @@ -171,6 +177,17 @@ const Config = { getSourceExts: () => [], getTransformModulePath: () => require.resolve('metro-bundler/src/transformer.js'), getTransformOptions: async () => ({}), + polyfills: [ + require.resolve('../../Libraries/polyfills/Object.es6.js'), + require.resolve('../../Libraries/polyfills/console.js'), + require.resolve('../../Libraries/polyfills/error-guard.js'), + require.resolve('../../Libraries/polyfills/Number.es6.js'), + require.resolve('../../Libraries/polyfills/String.prototype.es6.js'), + require.resolve('../../Libraries/polyfills/Array.prototype.es6.js'), + require.resolve('../../Libraries/polyfills/Array.es6.js'), + require.resolve('../../Libraries/polyfills/Object.es7.js'), + require.resolve('../../Libraries/polyfills/babelHelpers.js'), + ], postMinifyProcess: x => x, postProcessModules: modules => modules, postProcessModulesForBuck: modules => modules, @@ -222,7 +239,6 @@ const Config = { }, loadFileCustom(pathToConfig: string, defaults: TConfig): TConfig { - //$FlowFixMe: necessary dynamic require const config: {} = require(pathToConfig); return {...defaults, ...config}; },