123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. 'use strict';
  2. // modified from https://github.com/es-shims/es5-shim
  3. var has = Object.prototype.hasOwnProperty;
  4. var toStr = Object.prototype.toString;
  5. var slice = Array.prototype.slice;
  6. var isArgs = require('./isArguments');
  7. var isEnumerable = Object.prototype.propertyIsEnumerable;
  8. var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString');
  9. var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype');
  10. var dontEnums = [
  11. 'toString',
  12. 'toLocaleString',
  13. 'valueOf',
  14. 'hasOwnProperty',
  15. 'isPrototypeOf',
  16. 'propertyIsEnumerable',
  17. 'constructor'
  18. ];
  19. var equalsConstructorPrototype = function (o) {
  20. var ctor = o.constructor;
  21. return ctor && ctor.prototype === o;
  22. };
  23. var excludedKeys = {
  24. $applicationCache: true,
  25. $console: true,
  26. $external: true,
  27. $frame: true,
  28. $frameElement: true,
  29. $frames: true,
  30. $innerHeight: true,
  31. $innerWidth: true,
  32. $outerHeight: true,
  33. $outerWidth: true,
  34. $pageXOffset: true,
  35. $pageYOffset: true,
  36. $parent: true,
  37. $scrollLeft: true,
  38. $scrollTop: true,
  39. $scrollX: true,
  40. $scrollY: true,
  41. $self: true,
  42. $webkitIndexedDB: true,
  43. $webkitStorageInfo: true,
  44. $window: true
  45. };
  46. var hasAutomationEqualityBug = (function () {
  47. /* global window */
  48. if (typeof window === 'undefined') { return false; }
  49. for (var k in window) {
  50. try {
  51. if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') {
  52. try {
  53. equalsConstructorPrototype(window[k]);
  54. } catch (e) {
  55. return true;
  56. }
  57. }
  58. } catch (e) {
  59. return true;
  60. }
  61. }
  62. return false;
  63. }());
  64. var equalsConstructorPrototypeIfNotBuggy = function (o) {
  65. /* global window */
  66. if (typeof window === 'undefined' || !hasAutomationEqualityBug) {
  67. return equalsConstructorPrototype(o);
  68. }
  69. try {
  70. return equalsConstructorPrototype(o);
  71. } catch (e) {
  72. return false;
  73. }
  74. };
  75. var keysShim = function keys(object) {
  76. var isObject = object !== null && typeof object === 'object';
  77. var isFunction = toStr.call(object) === '[object Function]';
  78. var isArguments = isArgs(object);
  79. var isString = isObject && toStr.call(object) === '[object String]';
  80. var theKeys = [];
  81. if (!isObject && !isFunction && !isArguments) {
  82. throw new TypeError('Object.keys called on a non-object');
  83. }
  84. var skipProto = hasProtoEnumBug && isFunction;
  85. if (isString && object.length > 0 && !has.call(object, 0)) {
  86. for (var i = 0; i < object.length; ++i) {
  87. theKeys.push(String(i));
  88. }
  89. }
  90. if (isArguments && object.length > 0) {
  91. for (var j = 0; j < object.length; ++j) {
  92. theKeys.push(String(j));
  93. }
  94. } else {
  95. for (var name in object) {
  96. if (!(skipProto && name === 'prototype') && has.call(object, name)) {
  97. theKeys.push(String(name));
  98. }
  99. }
  100. }
  101. if (hasDontEnumBug) {
  102. var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
  103. for (var k = 0; k < dontEnums.length; ++k) {
  104. if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) {
  105. theKeys.push(dontEnums[k]);
  106. }
  107. }
  108. }
  109. return theKeys;
  110. };
  111. keysShim.shim = function shimObjectKeys() {
  112. if (Object.keys) {
  113. var keysWorksWithArguments = (function () {
  114. // Safari 5.0 bug
  115. return (Object.keys(arguments) || '').length === 2;
  116. }(1, 2));
  117. if (!keysWorksWithArguments) {
  118. var originalKeys = Object.keys;
  119. Object.keys = function keys(object) { // eslint-disable-line func-name-matching
  120. if (isArgs(object)) {
  121. return originalKeys(slice.call(object));
  122. } else {
  123. return originalKeys(object);
  124. }
  125. };
  126. }
  127. } else {
  128. Object.keys = keysShim;
  129. }
  130. return Object.keys || keysShim;
  131. };
  132. module.exports = keysShim;