UNPKG

mix-classes

Version:

Seamlessly combine class inheritance with composition, guaranteed to work with any class

222 lines (181 loc) 6.58 kB
'use strict'; function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 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); } /** * Gets a specific mixin's `this` * @param instance The this object to search on * @param MixinClass The mixin you want to find */ var getMixin = function getMixin(instance, MixinClass) { if (instance && instance[INSTANCE_THIS]) { return instance[INSTANCE_THIS].get(MixinClass); } return undefined; }; var INSTANCE_THIS = /*#__PURE__*/ Symbol('instanceThis'); var MIXIN_CLASSES = /*#__PURE__*/ Symbol('mixinClasses'); var extend = function extend(base, extension) { return new Proxy(base, { get: function get(_, prop) { var target = prop in extension ? extension : base; return target[prop]; }, set: function set(_, prop, value) { var target = prop in extension ? extension : base; target[prop] = value; return true; } }); }; var extractConstructable = function extractConstructable(Mixable) { return 'prototype' in Mixable ? Mixable : Mixable.Class; }; var createMixinClass = function createMixinClass(Mixables) { var _a, _b, _c; var Classes = Mixables.map(extractConstructable); var MixinClass = (_c = function MixinClass() { var _this = this; for (var _len = arguments.length, classesArgs = new Array(_len), _key = 0; _key < _len; _key++) { classesArgs[_key] = arguments[_key]; } // Stores the `this` proxies for each class this[_b] = new WeakMap(); Classes.forEach(function (Class, i) { var instance = _construct(Class, classesArgs[i] || []); var instanceThis = extend(_this, instance); _this[INSTANCE_THIS].set(Class, instanceThis); // Copy over getters to instance values Object.keys(instance).forEach(function (key) { Object.defineProperty(_this, key, { configurable: true, enumerable: true, get: function get() { return instance[key]; }, set: function set(value) { return instance[key] = value; } }); }); }); }, _a = MIXIN_CLASSES, _b = INSTANCE_THIS, _c[_a] = Classes, _c); Classes.forEach(function (Class) { var restoreThisInsideFunction = function restoreThisInsideFunction(fn) { return function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return fn.apply(getMixin(this, Class), args); }; }; // Copy over prototype methods var recursePrototype = function recursePrototype(prototype) { // Add instanceof support var hasInstance = prototype.constructor[Symbol.hasInstance]; Object.defineProperty(prototype.constructor, Symbol.hasInstance, { configurable: true, value: function value(possibleMixin) { // Retain original instanceof for prototype if (prototype.isPrototypeOf(possibleMixin)) return true; if (possibleMixin && possibleMixin.constructor) { var isInMixins = function isInMixins(mixin) { var classes = mixin[MIXIN_CLASSES]; if (!classes) return false; for (var _iterator = classes, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { var _ref; if (_isArray) { if (_i >= _iterator.length) break; _ref = _iterator[_i++]; } else { _i = _iterator.next(); if (_i.done) break; _ref = _i.value; } var cls = _ref; if (cls === Class) return true; var isChildMixin = isInMixins(cls); if (isChildMixin) return true; } return false; }; if (this && this !== prototype.constructor) { // not used as mixin, `class [this] extends [prototype.constructor] {}` return prototype.constructor.isPrototypeOf(possibleMixin.constructor); } if (isInMixins(possibleMixin.constructor)) return true; if (!this) return false; } return hasInstance(possibleMixin); } }); Object.getOwnPropertyNames(prototype).forEach(function (name) { if (name === 'constructor') return; var descriptor = Object.getOwnPropertyDescriptor(prototype, name); if (descriptor.get) { descriptor.get = restoreThisInsideFunction(descriptor.get); } if (descriptor.set) { descriptor.set = restoreThisInsideFunction(descriptor.set); } if (typeof descriptor.value === 'function') { descriptor.value = restoreThisInsideFunction(descriptor.value); } if (!MixinClass.prototype.hasOwnProperty(name)) { Object.defineProperty(MixinClass.prototype, name, descriptor); } }); var parent = Object.getPrototypeOf(prototype); if (parent && parent !== Object.prototype) recursePrototype(parent); }; recursePrototype(Class.prototype); }); return MixinClass; }; var Mix = function Mix() { for (var _len = arguments.length, Mixables = new Array(_len), _key = 0; _key < _len; _key++) { Mixables[_key] = arguments[_key]; } return createMixinClass(Mixables); }; var Generic = function Generic(Class) { return { Class: Class }; }; exports.Generic = Generic; exports.Mix = Mix; exports.getMixin = getMixin; //# sourceMappingURL=mix-classes.cjs.development.js.map