UNPKG

knockout-es5

Version:
270 lines (222 loc) 8.53 kB
/*! WeakMap shim * (The MIT License) * * Copyright (c) 2012 Brandon Benvie <http://bbenvie.com> * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * associated documentation files (the 'Software'), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included with all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Original WeakMap implementation by Gozala @ https://gist.github.com/1269991 // Updated and bugfixed by Raynos @ https://gist.github.com/1638059 // Expanded by Benvie @ https://github.com/Benvie/harmony-collections // This is the version used by knockout-es5. Modified by Steve Sanderson as follows: // [1] Deleted weakmap.min.js (it's not useful as it would be out of sync with weakmap.js now I'm editing it) // [2] Since UglifyJS strips inline function names (and you can't disable that without disabling name mangling // entirely), insert code that re-adds function names void function(global, undefined_, undefined){ var getProps = Object.getOwnPropertyNames, cachedWindowNames = typeof window === 'object' ? Object.getOwnPropertyNames(window) : [], defProp = Object.defineProperty, toSource = Function.prototype.toString, create = Object.create, hasOwn = Object.prototype.hasOwnProperty, funcName = /^\n?function\s?(\w*)?_?\(/; function define(object, key, value){ if (typeof key === 'function') { value = key; key = nameOf(value).replace(/_$/, ''); } return defProp(object, key, { configurable: true, writable: true, value: value }); } function nameOf(func){ return typeof func !== 'function' ? '' : '_name' in func ? func._name : 'name' in func ? func.name : toSource.call(func).match(funcName)[1]; } function namedFunction(name, func) { // Undo the name-stripping that UglifyJS does func._name = name; return func; } // ############ // ### Data ### // ############ var Data = (function(){ var dataDesc = { value: { writable: true, value: undefined } }, uids = create(null), createUID = function(){ var key = Math.random().toString(36).slice(2); return key in uids ? createUID() : uids[key] = key; }, globalID = createUID(), storage = function(obj){ if (hasOwn.call(obj, globalID)) return obj[globalID]; if (!Object.isExtensible(obj)) throw new TypeError("Object must be extensible"); var store = create(null); defProp(obj, globalID, { value: store }); return store; }; // common per-object storage area made visible by patching getOwnPropertyNames' define(Object, namedFunction('getOwnPropertyNames', function getOwnPropertyNames(obj){ // gh-43 var coercedObj = Object(obj), props; // Fixes for debuggers: // 1) Some objects lack .toString(), calling it on them make Chrome // debugger fail when inspecting variables. // 2) Window.prototype methods and properties are private in IE11 and // throw 'Invalid calling object'. if (coercedObj !== Window.prototype && 'toString' in coercedObj && coercedObj.toString() === '[object Window]') { try { props = getProps(obj); } catch (e) { props = cachedWindowNames; } } else { props = getProps(obj); } if (hasOwn.call(obj, globalID)) props.splice(props.indexOf(globalID), 1); return props; })); function Data(){ var puid = createUID(), secret = {}; this.unlock = function(obj){ var store = storage(obj); if (hasOwn.call(store, puid)) return store[puid](secret); var data = create(null, dataDesc); defProp(store, puid, { value: function(key){ if (key === secret) return data; } }); return data; } } define(Data.prototype, namedFunction('get', function get(o){ return this.unlock(o).value })); define(Data.prototype, namedFunction('set', function set(o, v){ this.unlock(o).value = v })); return Data; }()); var WM = (function(data){ var validate = function(key){ if (key == null || typeof key !== 'object' && typeof key !== 'function') throw new TypeError("Invalid WeakMap key"); } var wrap = function(collection, value){ var store = data.unlock(collection); if (store.value) throw new TypeError("Object is already a WeakMap"); store.value = value; } var unwrap = function(collection){ var storage = data.unlock(collection).value; if (!storage) throw new TypeError("WeakMap is not generic"); return storage; } var initialize = function(weakmap, iterable){ if (iterable !== null && typeof iterable === 'object' && typeof iterable.forEach === 'function') { iterable.forEach(function(item, i){ if (item instanceof Array && item.length === 2) set.call(weakmap, iterable[i][0], iterable[i][1]); }); } } function WeakMap(iterable){ if (this === global || this == null || this === WeakMap.prototype) return new WeakMap(iterable); wrap(this, new Data); initialize(this, iterable); } function get(key){ validate(key); var value = unwrap(this).get(key); return value === undefined_ ? undefined : value; } function set(key, value){ validate(key); // store a token for explicit undefined so that "has" works correctly unwrap(this).set(key, value === undefined ? undefined_ : value); } function has(key){ validate(key); return unwrap(this).get(key) !== undefined; } function delete_(key){ validate(key); var data = unwrap(this), had = data.get(key) !== undefined; data.set(key, undefined); return had; } function toString(){ unwrap(this); return '[object WeakMap]'; } // Undo the function-name stripping that UglifyJS does get._name = 'get'; set._name = 'set'; has._name = 'has'; toString._name = 'toString'; var src = (''+Object).split('Object'); var stringifier = namedFunction('toString', function toString(){ return src[0] + nameOf(this) + src[1]; }); define(stringifier, stringifier); var prep = { __proto__: [] } instanceof Array ? function(f){ f.__proto__ = stringifier } : function(f){ define(f, stringifier) }; prep(WeakMap); [toString, get, set, has, delete_].forEach(function(method){ define(WeakMap.prototype, method); prep(method); }); return WeakMap; }(new Data)); var defaultCreator = Object.create ? function(){ return Object.create(null) } : function(){ return {} }; function createStorage(creator){ var weakmap = new WM; creator || (creator = defaultCreator); function storage(object, value){ if (value || arguments.length === 2) { weakmap.set(object, value); } else { value = weakmap.get(object); if (value === undefined) { value = creator(object); weakmap.set(object, value); } } return value; } return storage; } if (typeof module !== 'undefined') { module.exports = WM; } else if (typeof exports !== 'undefined') { exports.WeakMap = WM; } else if (!('WeakMap' in global)) { global.WeakMap = WM; } WM.createStorage = createStorage; if (global.WeakMap) global.WeakMap.createStorage = createStorage; }(function(){ return this }());