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