From feaaff0b14a2fcbea4b90af1059dfb529f171076 Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Mon, 7 Dec 2015 09:58:12 -0800 Subject: [PATCH] refactor(SymbolShim): add for polyfill - refactor SymbolShim away from class usage - removes test that might be brittle when testing in browsers without Symbol impl - adds for function polyfill if not present - improves test looking for Set class --- spec/util/SymbolShim-spec.js | 97 ++++++++++++++++++------------------ src/util/SymbolShim.ts | 85 ++++++++++++++++--------------- 2 files changed, 90 insertions(+), 92 deletions(-) diff --git a/spec/util/SymbolShim-spec.js b/spec/util/SymbolShim-spec.js index 70cde80a65..05dafca76b 100644 --- a/spec/util/SymbolShim-spec.js +++ b/spec/util/SymbolShim-spec.js @@ -1,23 +1,28 @@ /* globals __root__ */ -var SymbolDefinition = require('../../dist/cjs/util/SymbolShim').SymbolDefinition; +var SymbolShim = require('../../dist/cjs/util/SymbolShim'); var Map = require('../../dist/cjs/util/Map').Map; var Rx = require('../../dist/cjs/Rx'); +var polyfillSymbol = SymbolShim.polyfillSymbol; +var ensureIterator = SymbolShim.ensureIterator; -describe('SymbolDefinition', function () { +describe('SymbolShim', function () { it('should setup symbol if root does not have it', function () { var root = {}; - var result = new SymbolDefinition(root); + var result = polyfillSymbol(root); expect(root.Symbol).toBeDefined(); expect(result.observable).toBeDefined(); expect(result.iterator).toBeDefined(); + expect(result.for).toBeDefined(); }); - it('should have observable, iterator symbols', function () { - var result = new SymbolDefinition(__root__); + it('should add a for method', function () { + var root = {}; + var result = polyfillSymbol(root); + expect(typeof result.for).toBe('function'); - expect(typeof result.observable).toBe('symbol'); - expect(typeof result.iterator).toBe('symbol'); + var test = result.for('test'); + expect(test).toBe('@@test'); }); describe('when symbols exists on root', function () { @@ -29,7 +34,7 @@ describe('SymbolDefinition', function () { } }; - var result = new SymbolDefinition(root); + var result = polyfillSymbol(root); expect(result.observable).toBe(root.Symbol.observable); expect(result.iterator).toBe(root.Symbol.iterator); }); @@ -43,60 +48,54 @@ describe('SymbolDefinition', function () { } }; - var result = new SymbolDefinition(root); + var result = polyfillSymbol(root); expect(result.observable).toBe(root.Symbol.for('observable')); }); it('should patch root if for symbol does not exist', function () { var root = {}; - var result = new SymbolDefinition(root); + var result = polyfillSymbol(root); expect(result.observable).toBe('@@observable'); }); }); +}); + +describe('ensureIterator', function () { + it('should patch root using for symbol if exist', function () { + var root = { + Symbol: { + for: function (x) { return x; } + } + }; + ensureIterator(root.Symbol, root); + expect(root.Symbol.iterator).toBe(root.Symbol.for('iterator')); + }); - describe('iterator symbol', function () { - it('should patch root using for symbol if exist', function () { - var root = { - Symbol: { - for: function (x) { return x; } - } - }; - - var result = new SymbolDefinition(root); - expect(result.iterator).toBe(root.Symbol.for('iterator')); - }); - - it('should patch root if for symbol does not exist', function () { - var root = {}; - - var result = new SymbolDefinition(root); - expect(result.iterator).toBe('@@iterator'); - }); + it('should patch using Set for mozilla bug', function () { + function Set() { + } + Set.prototype['@@iterator'] = function () {}; - it('should patch using set for mozilla', function () { - var root = { - Set: function () { - var ret = {}; - ret['@@iterator'] = function () {}; - return ret; - } - }; + var root = { + Set: Set, + Symbol: {} + }; - var result = new SymbolDefinition(root); - expect(result.iterator).toBe('@@iterator'); - }); + ensureIterator(root.Symbol, root); + expect(root.Symbol.iterator).toBe('@@iterator'); + }); - it('should patch using map for es6-shim', function () { - var root = { - Map: Map - }; + it('should patch using map for es6-shim', function () { + var root = { + Map: Map, + Symbol: {} + }; - root.Map.prototype.key = 'iteratorValue'; - root.Map.prototype.entries = 'iteratorValue'; + root.Map.prototype.key = 'iteratorValue'; + root.Map.prototype.entries = 'iteratorValue'; - var result = new SymbolDefinition(root); - expect(result.iterator).toBe('key'); - }); + ensureIterator(root.Symbol, root); + expect(root.Symbol.iterator).toBe('key'); }); -}); \ No newline at end of file +}); diff --git a/src/util/SymbolShim.ts b/src/util/SymbolShim.ts index 4ded435af6..8d152d9939 100644 --- a/src/util/SymbolShim.ts +++ b/src/util/SymbolShim.ts @@ -1,57 +1,56 @@ import {root} from './root'; -export class SymbolDefinition { - observable: symbol = null; - iterator: symbol = null; - - private applyObservable(): symbol { - const root = this.root; - - if (!root.Symbol.observable) { - if (typeof root.Symbol.for === 'function') { - root.Symbol.observable = root.Symbol.for('observable'); - } else { - root.Symbol.observable = '@@observable'; - } - } +export function polyfillSymbol(root) { + const Symbol = ensureSymbol(root); + ensureIterator(Symbol, root); + ensureObservable(Symbol); + return Symbol; +} - return root.Symbol.observable; +export function ensureSymbol(root) { + if (!root.Symbol) { + root.Symbol = { + for: symbolForPolyfill + }; } + return root.Symbol; +} - private applyIterator(): symbol { - const root = this.root; +export function symbolForPolyfill(key) { + return '@@' + key; +} - if (!root.Symbol.iterator) { - if (typeof root.Symbol.for === 'function') { - root.Symbol.iterator = root.Symbol.for('iterator'); - } else if (root.Set && typeof new root.Set()['@@iterator'] === 'function') { - // Bug for mozilla version - root.Symbol.iterator = '@@iterator'; - } else if (root.Map) { - // es6-shim specific logic - let keys = Object.getOwnPropertyNames(root.Map.prototype); - for (let i = 0; i < keys.length; ++i) { - let key = keys[i]; - if (key !== 'entries' && key !== 'size' && root.Map.prototype[key] === root.Map.prototype['entries']) { - root.Symbol.iterator = key; - break; - } +export function ensureIterator(Symbol, root) { + if (!Symbol.iterator) { + if (typeof Symbol.for === 'function') { + Symbol.iterator = Symbol.for('iterator'); + } else if (root.Set && typeof new root.Set()['@@iterator'] === 'function') { + // Bug for mozilla version + Symbol.iterator = '@@iterator'; + } else if (root.Map) { + // es6-shim specific logic + let keys = Object.getOwnPropertyNames(root.Map.prototype); + for (let i = 0; i < keys.length; ++i) { + let key = keys[i]; + if (key !== 'entries' && key !== 'size' && root.Map.prototype[key] === root.Map.prototype['entries']) { + Symbol.iterator = key; + break; } - } else { - root.Symbol.iterator = '@@iterator'; } + } else { + Symbol.iterator = '@@iterator'; } - - return root.Symbol.iterator; } +} - constructor(private root: any) { - if (!root.Symbol) { - root.Symbol = {}; +export function ensureObservable(Symbol) { + if (!Symbol.observable) { + if (typeof Symbol.for === 'function') { + Symbol.observable = Symbol.for('observable'); + } else { + Symbol.observable = '@@observable'; } - - this.observable = this.applyObservable(); - this.iterator = this.applyIterator(); } } -export const SymbolShim = new SymbolDefinition(root); \ No newline at end of file + +export const SymbolShim = polyfillSymbol(root); \ No newline at end of file