"use strict"; var originalObject = Object; var originalDefProp = Object.defineProperty; var originalCreate = Object.create; function defProp(obj, name, value) { if (originalDefProp) try { originalDefProp.call(originalObject, obj, name, { value: value }); } catch (definePropertyIsBrokenInIE8) { obj[name] = value; } else { obj[name] = value; } } // For functions that will be invoked using .call or .apply, we need to // define those methods on the function objects themselves, rather than // inheriting them from Function.prototype, so that a malicious or clumsy // third party cannot interfere with the functionality of this module by // redefining Function.prototype.call or .apply. function makeSafeToCall(fun) { if (fun) { defProp(fun, "call", fun.call); defProp(fun, "apply", fun.apply); } return fun; } makeSafeToCall(originalDefProp); makeSafeToCall(originalCreate); var hasOwn = makeSafeToCall(Object.prototype.hasOwnProperty); var numToStr = makeSafeToCall(Number.prototype.toString); var strSlice = makeSafeToCall(String.prototype.slice); var cloner = function(){}; function create(prototype) { if (originalCreate) { return originalCreate.call(originalObject, prototype); } cloner.prototype = prototype || null; return new cloner; } var rand = Math.random; var uniqueKeys = create(null); function makeUniqueKey() { // Collisions are highly unlikely, but this module is in the business of // making guarantees rather than safe bets. do var uniqueKey = internString(strSlice.call(numToStr.call(rand(), 36), 2)); while (hasOwn.call(uniqueKeys, uniqueKey)); return uniqueKeys[uniqueKey] = uniqueKey; } function internString(str) { var obj = {}; obj[str] = true; return Object.keys(obj)[0]; } // External users might find this function useful, but it is not necessary // for the typical use of this module. exports.makeUniqueKey = makeUniqueKey; // Object.getOwnPropertyNames is the only way to enumerate non-enumerable // properties, so if we wrap it to ignore our secret keys, there should be // no way (except guessing) to access those properties. var originalGetOPNs = Object.getOwnPropertyNames; Object.getOwnPropertyNames = function getOwnPropertyNames(object) { for (var names = originalGetOPNs(object), src = 0, dst = 0, len = names.length; src < len; ++src) { if (!hasOwn.call(uniqueKeys, names[src])) { if (src > dst) { names[dst] = names[src]; } ++dst; } } names.length = dst; return names; }; function defaultCreatorFn(object) { return create(null); } function makeAccessor(secretCreatorFn) { var brand = makeUniqueKey(); var passkey = create(null); secretCreatorFn = secretCreatorFn || defaultCreatorFn; function register(object) { var secret; // Created lazily. function vault(key, forget) { // Only code that has access to the passkey can retrieve (or forget) // the secret object. if (key === passkey) { return forget ? secret = null : secret || (secret = secretCreatorFn(object)); } } defProp(object, brand, vault); } function accessor(object) { if (!hasOwn.call(object, brand)) register(object); return object[brand](passkey); } accessor.forget = function(object) { if (hasOwn.call(object, brand)) object[brand](passkey, true); }; return accessor; } exports.makeAccessor = makeAccessor;