1'use strict';
2var LIBRARY = require('./_library');
3var $export = require('./_export');
4var redefine = require('./_redefine');
5var hide = require('./_hide');
6var Iterators = require('./_iterators');
7var $iterCreate = require('./_iter-create');
8var setToStringTag = require('./_set-to-string-tag');
9var getPrototypeOf = require('./_object-gpo');
10var ITERATOR = require('./_wks')('iterator');
11var BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next`
12var FF_ITERATOR = '@@iterator';
13var KEYS = 'keys';
14var VALUES = 'values';
15
16var returnThis = function () { return this; };
17
18module.exports = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED) {
19  $iterCreate(Constructor, NAME, next);
20  var getMethod = function (kind) {
21    if (!BUGGY && kind in proto) return proto[kind];
22    switch (kind) {
23      case KEYS: return function keys() { return new Constructor(this, kind); };
24      case VALUES: return function values() { return new Constructor(this, kind); };
25    } return function entries() { return new Constructor(this, kind); };
26  };
27  var TAG = NAME + ' Iterator';
28  var DEF_VALUES = DEFAULT == VALUES;
29  var VALUES_BUG = false;
30  var proto = Base.prototype;
31  var $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT];
32  var $default = $native || getMethod(DEFAULT);
33  var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined;
34  var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;
35  var methods, key, IteratorPrototype;
36  // Fix native
37  if ($anyNative) {
38    IteratorPrototype = getPrototypeOf($anyNative.call(new Base()));
39    if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) {
40      // Set @@toStringTag to native iterators
41      setToStringTag(IteratorPrototype, TAG, true);
42      // fix for some old engines
43      if (!LIBRARY && typeof IteratorPrototype[ITERATOR] != 'function') hide(IteratorPrototype, ITERATOR, returnThis);
44    }
45  }
46  // fix Array#{values, @@iterator}.name in V8 / FF
47  if (DEF_VALUES && $native && $native.name !== VALUES) {
48    VALUES_BUG = true;
49    $default = function values() { return $native.call(this); };
50  }
51  // Define iterator
52  if ((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])) {
53    hide(proto, ITERATOR, $default);
54  }
55  // Plug for library
56  Iterators[NAME] = $default;
57  Iterators[TAG] = returnThis;
58  if (DEFAULT) {
59    methods = {
60      values: DEF_VALUES ? $default : getMethod(VALUES),
61      keys: IS_SET ? $default : getMethod(KEYS),
62      entries: $entries
63    };
64    if (FORCED) for (key in methods) {
65      if (!(key in proto)) redefine(proto, key, methods[key]);
66    } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods);
67  }
68  return methods;
69};
70