UNPKG

class-privacy

Version:

Simple way to define private members on ES6 classes, keep their code clean.

131 lines (102 loc) 5.34 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } function _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } /** * @type {decide} defaults to a function always returning true * @type {revealIsProxy} defaults to false * @type {referenceClass} defaults to false */ var defaultOptions = {}; defaultOptions.decide = function () { return true; }; defaultOptions.revealIsProxy = false; defaultOptions.referenceClass = false; var IS_PROXY = 'isProxy'; var CLASS = 'class'; /** * @private checks for a prototype constructor to match an expected value */ var check = function check(value, expected) { var proto = value && Object.getPrototypeOf(value); var constructor = proto && proto.constructor; if (constructor !== expected) { var constructorName = constructor && constructor.name; var expectedName = expected && expected.name; throw new TypeError("Expected ".concat(expectedName, ", got ").concat(constructorName, ".")); } }; /** * Creates a factory function that produces proxies to instances of a {class} definition, based on * @param ClassDefinition * @param options.decide {function} A function that checks the instance's given {key} and {value} of a property and * returns true, if the property is public or false if private. * @param options.revealIsProxy {boolean} if true it allows external code to ask for {isProxy} which then returns true * @param options.referenceClass {boolean} if true it allows external code to ask for {class} which then returns * the referenced original class definition but never the instance * @returns {function} A factory function to produce proxies to an instance */ var createFactory = function createFactory(ClassDefinition) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOptions; check(ClassDefinition, Function); check(options, Object); // we flat-merge the options with the default options // to ensure that there are no options missing and the factory // doesn't crash at runtime, for example because an options has // been explicitly set to null var factoryOptions = Object.assign({}, defaultOptions, options); var decide = factoryOptions.decide || defaultOptions.decide; var referenceClass = factoryOptions.referenceClass || defaultOptions.referenceClass; var revealIsProxy = factoryOptions.revealIsProxy || defaultOptions.revealIsProxy; /** * Creates an instance of the given ClassDefinition * @param invocationArgs arguments of arbitrary length, determined by ClassDefinition * @return {proxy} */ var factory = function factory() { for (var _len = arguments.length, invocationArgs = new Array(_len), _key = 0; _key < _len; _key++) { invocationArgs[_key] = arguments[_key]; } var instance = _construct(ClassDefinition, invocationArgs); var handler = { get: function get(target, property /*, receiver */ ) { // get proxy by symbol if (revealIsProxy && property === IS_PROXY) { return true; } // get class by symbol if (referenceClass && property === CLASS) { return ClassDefinition; } // skip any request to unowned properties // using 'in' as a good trade-off between validity and performance if (!(property in instance)) { return; } // skip members, that don't pass the test, // let developer decide how to design tests var member = instance[property]; var type = _typeof(member); var includeMember = decide(property, type, ClassDefinition); if (!includeMember) { return; } // bind functions to the instance to avoid unintended // blocking the member function's internals if (type === 'function') { return member.bind(instance); } else { return member; } } }; return new Proxy({}, handler); }; return factory; }; var _default = createFactory; exports["default"] = _default; //# sourceMappingURL=index.js.map