From a3e2f62932f76588ff1df0d54fbd0862328f4ee8 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Tue, 24 May 2016 06:48:42 -0700 Subject: [PATCH] Respect original enumerability/writability when polyfilling globals Summary: Reuses the original property descriptor when overwriting / polyfilling globals to ensure enumerability and writability are the same Closes https://github.com/facebook/react-native/pull/7704 Differential Revision: D3338119 Pulled By: davidaurelio fbshipit-source-id: ab456324a3346cd3ec8b2c3e3a2378408c92087c --- .../InitializeJavaScriptAppEngine.js | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js index acc5890a789353..bcdc888297f00b 100644 --- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js +++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js @@ -64,40 +64,47 @@ function setUpConsole() { * https://github.com/facebook/react-native/issues/934 */ function polyfillGlobal(name, newValue, scope = global) { - const descriptor = Object.getOwnPropertyDescriptor(scope, name) || { - // jest for some bad reasons runs the polyfill code multiple times. In jest - // environment, XmlHttpRequest doesn't exist so getOwnPropertyDescriptor - // returns undefined and defineProperty default for writable is false. - // Therefore, the second time it runs, defineProperty will fatal :( - writable: true, - }; - - if (scope[name] !== undefined) { + const descriptor = Object.getOwnPropertyDescriptor(scope, name); + if (descriptor) { const backupName = `original${name[0].toUpperCase()}${name.substr(1)}`; Object.defineProperty(scope, backupName, {...descriptor, value: scope[name]}); } - Object.defineProperty(scope, name, {...descriptor, value: newValue}); + const {enumerable, writable} = descriptor || {}; + + // jest for some bad reasons runs the polyfill code multiple times. In jest + // environment, XmlHttpRequest doesn't exist so getOwnPropertyDescriptor + // returns undefined and defineProperty default for writable is false. + // Therefore, the second time it runs, defineProperty will fatal :( + + Object.defineProperty(scope, name, { + configurable: true, + enumerable: enumerable !== false, + writable: writable !== false, + value: newValue, + }); } function polyfillLazyGlobal(name, valueFn, scope = global) { - if (scope[name] !== undefined) { - const descriptor = Object.getOwnPropertyDescriptor(scope, name); + const descriptor = getPropertyDescriptor(scope, name); + if (descriptor) { const backupName = `original${name[0].toUpperCase()}${name.substr(1)}`; - Object.defineProperty(scope, backupName, {...descriptor, value: scope[name]}); + Object.defineProperty(scope, backupName, descriptor); } + const {enumerable, writable} = descriptor || {}; Object.defineProperty(scope, name, { configurable: true, - enumerable: true, + enumerable: enumerable !== false, get() { return (this[name] = valueFn()); }, set(value) { Object.defineProperty(this, name, { configurable: true, - enumerable: true, - value + enumerable: enumerable !== false, + writable: writable !== false, + value, }); } }); @@ -211,6 +218,16 @@ function setUpDevTools() { } } +function getPropertyDescriptor(object, name) { + while (object) { + const descriptor = Object.getOwnPropertyDescriptor(object, name); + if (descriptor) { + return descriptor; + } + object = Object.getPrototypeOf(object); + } +} + setUpProcess(); setUpConsole(); setUpTimers();