From 598df0bc201e4a177d51bd3d29a4249b997987df Mon Sep 17 00:00:00 2001
From: Dmitry Soshnikov <dmitrys@fb.com>
Date: Thu, 28 Jan 2016 17:20:39 -0800
Subject: [PATCH] Add Object.entries and Object.values polyfill

Reviewed By: martinbigio

Differential Revision: D2876430

fb-gh-sync-id: 25c7680a71c9187beb937f6faf030a83c9c81fc5
---
 packager/react-packager/src/Resolver/index.js |   1 +
 .../src/Resolver/polyfills/Object.es7.js      |  56 ++++++++
 .../polyfills/__tests__/Object.es7-test.js    | 120 ++++++++++++++++++
 3 files changed, 177 insertions(+)
 create mode 100644 packager/react-packager/src/Resolver/polyfills/Object.es7.js
 create mode 100644 packager/react-packager/src/Resolver/polyfills/__tests__/Object.es7-test.js

diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 0166681f0..4cb4707f1 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -157,6 +157,7 @@ class Resolver {
       path.join(__dirname, 'polyfills/String.prototype.es6.js'),
       path.join(__dirname, 'polyfills/Array.prototype.es6.js'),
       path.join(__dirname, 'polyfills/Array.es6.js'),
+      path.join(__dirname, 'polyfills/Object.es7.js'),
       path.join(__dirname, 'polyfills/babelHelpers.js'),
     ].concat(this._polyfillModuleNames);
 
diff --git a/packager/react-packager/src/Resolver/polyfills/Object.es7.js b/packager/react-packager/src/Resolver/polyfills/Object.es7.js
new file mode 100644
index 000000000..597c49e7f
--- /dev/null
+++ b/packager/react-packager/src/Resolver/polyfills/Object.es7.js
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @provides Object.es7
+ * @polyfill
+ */
+
+(function() {
+
+  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');
+      }
+
+      let entries = [];
+      for (let 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');
+      }
+
+      let values = [];
+      for (let key in object) {
+        if (hasOwnProperty.call(object, key)) {
+          values.push(object[key]);
+        }
+      }
+      return values;
+    };
+  }
+
+})();
\ No newline at end of file
diff --git a/packager/react-packager/src/Resolver/polyfills/__tests__/Object.es7-test.js b/packager/react-packager/src/Resolver/polyfills/__tests__/Object.es7-test.js
new file mode 100644
index 000000000..ee7782eb7
--- /dev/null
+++ b/packager/react-packager/src/Resolver/polyfills/__tests__/Object.es7-test.js
@@ -0,0 +1,120 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @emails oncall+jsinfra
+ */
+
+ /* eslint-disable fb-www/object-create-only-one-param */
+
+jest.autoMockOff();
+
+describe('Object (ES7)', () => {
+  beforeEach(() => {
+    delete Object.entries;
+    delete Object.values;
+    jest.resetModuleRegistry();
+    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', () => {
+      let foo = Object.defineProperties({}, {
+        x: {value: 10, enumerable: true},
+        y: {value: 20},
+      });
+
+      expect(Object.entries(foo)).toEqual([['x', 10]]);
+
+      let bar = {x: 10, y: 20};
+      expect(Object.entries(bar)).toEqual([['x', 10], ['y', 20]]);
+    });
+
+    it('should work with proto-less objects', () => {
+      let 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', () => {
+      let 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', () => {
+      let foo = Object.defineProperties({}, {
+        x: {value: 10, enumerable: true},
+        y: {value: 20},
+      });
+
+      expect(Object.values(foo)).toEqual([10]);
+
+      let bar = {x: 10, y: 20};
+      expect(Object.values(bar)).toEqual([10, 20]);
+    });
+
+    it('should work with proto-less objects', () => {
+      let foo = Object.create(null, {
+        x: {value: 10, enumerable: true},
+        y: {value: 20},
+      });
+
+      expect(Object.values(foo)).toEqual([10]);
+    });
+
+    it('should return only own values', () => {
+      let 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']);
+    });
+  });
+});
\ No newline at end of file