// ES2015 Symbol polyfill for environments that do not (or partially) support it 'use strict'; var d = require('d') , validateSymbol = require('./validate-symbol') , create = Object.create, defineProperties = Object.defineProperties , defineProperty = Object.defineProperty, objPrototype = Object.prototype , NativeSymbol, SymbolPolyfill, HiddenSymbol, globalSymbols = create(null) , isNativeSafe; if (typeof Symbol === 'function') { NativeSymbol = Symbol; try { String(NativeSymbol()); isNativeSafe = true; } catch (ignore) {} } var generateName = (function () { var created = create(null); return function (desc) { var postfix = 0, name, ie11BugWorkaround; while (created[desc + (postfix || '')]) ++postfix; desc += (postfix || ''); created[desc] = true; name = '@@' + desc; defineProperty(objPrototype, name, d.gs(null, function (value) { // For IE11 issue see: // https://connect.microsoft.com/IE/feedbackdetail/view/1928508/ // ie11-broken-getters-on-dom-objects // https://github.com/medikoo/es6-symbol/issues/12 if (ie11BugWorkaround) return; ie11BugWorkaround = true; defineProperty(this, name, d(value)); ie11BugWorkaround = false; })); return name; }; }()); // Internal constructor (not one exposed) for creating Symbol instances. // This one is used to ensure that `someSymbol instanceof Symbol` always return false HiddenSymbol = function Symbol(description) { if (this instanceof HiddenSymbol) throw new TypeError('Symbol is not a constructor'); return SymbolPolyfill(description); }; // Exposed `Symbol` constructor // (returns instances of HiddenSymbol) module.exports = SymbolPolyfill = function Symbol(description) { var symbol; if (this instanceof Symbol) throw new TypeError('Symbol is not a constructor'); if (isNativeSafe) return NativeSymbol(description); symbol = create(HiddenSymbol.prototype); description = (description === undefined ? '' : String(description)); return defineProperties(symbol, { __description__: d('', description), __name__: d('', generateName(description)) }); }; defineProperties(SymbolPolyfill, { for: d(function (key) { if (globalSymbols[key]) return globalSymbols[key]; return (globalSymbols[key] = SymbolPolyfill(String(key))); }), keyFor: d(function (s) { var key; validateSymbol(s); for (key in globalSymbols) if (globalSymbols[key] === s) return key; }), // To ensure proper interoperability with other native functions (e.g. Array.from) // fallback to eventual native implementation of given symbol hasInstance: d('', (NativeSymbol && NativeSymbol.hasInstance) || SymbolPolyfill('hasInstance')), isConcatSpreadable: d('', (NativeSymbol && NativeSymbol.isConcatSpreadable) || SymbolPolyfill('isConcatSpreadable')), iterator: d('', (NativeSymbol && NativeSymbol.iterator) || SymbolPolyfill('iterator')), match: d('', (NativeSymbol && NativeSymbol.match) || SymbolPolyfill('match')), replace: d('', (NativeSymbol && NativeSymbol.replace) || SymbolPolyfill('replace')), search: d('', (NativeSymbol && NativeSymbol.search) || SymbolPolyfill('search')), species: d('', (NativeSymbol && NativeSymbol.species) || SymbolPolyfill('species')), split: d('', (NativeSymbol && NativeSymbol.split) || SymbolPolyfill('split')), toPrimitive: d('', (NativeSymbol && NativeSymbol.toPrimitive) || SymbolPolyfill('toPrimitive')), toStringTag: d('', (NativeSymbol && NativeSymbol.toStringTag) || SymbolPolyfill('toStringTag')), unscopables: d('', (NativeSymbol && NativeSymbol.unscopables) || SymbolPolyfill('unscopables')) }); // Internal tweaks for real symbol producer defineProperties(HiddenSymbol.prototype, { constructor: d(SymbolPolyfill), toString: d('', function () { return this.__name__; }) }); // Proper implementation of methods exposed on Symbol.prototype // They won't be accessible on produced symbol instances as they derive from HiddenSymbol.prototype defineProperties(SymbolPolyfill.prototype, { toString: d(function () { return 'Symbol (' + validateSymbol(this).__description__ + ')'; }), valueOf: d(function () { return validateSymbol(this); }) }); defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toPrimitive, d('', function () { var symbol = validateSymbol(this); if (typeof symbol === 'symbol') return symbol; return symbol.toString(); })); defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toStringTag, d('c', 'Symbol')); // Proper implementaton of toPrimitive and toStringTag for returned symbol instances defineProperty(HiddenSymbol.prototype, SymbolPolyfill.toStringTag, d('c', SymbolPolyfill.prototype[SymbolPolyfill.toStringTag])); // Note: It's important to define `toPrimitive` as last one, as some implementations // implement `toPrimitive` natively without implementing `toStringTag` (or other specified symbols) // And that may invoke error in definition flow: // See: https://github.com/medikoo/es6-symbol/issues/13#issuecomment-164146149 defineProperty(HiddenSymbol.prototype, SymbolPolyfill.toPrimitive, d('c', SymbolPolyfill.prototype[SymbolPolyfill.toPrimitive]));