| // ES2015 Symbol polyfill for environments that do not support it (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); |
| |
| if (typeof Symbol === 'function') NativeSymbol = Symbol; |
| |
| 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('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('TypeError: Symbol is not a constructor'); |
| 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; |
| }), |
| |
| // If there's native implementation of given symbol, let's fallback to it |
| // to ensure proper interoperability with other native functions e.g. Array.from |
| 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 () { return validateSymbol(this); })); |
| 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])); |