foibles
Version:
Composition and mixins and TypeScript classes
76 lines • 2.33 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
// Symbol used to mark if a certain mixin has been applied
var application = Symbol('decorator:application');
/**
* Check if the given prototype has the given mixin applied to itself.
*
* @param object
* @param mixin
*/
function has(object, mixin) {
while (object != null) {
if (object.hasOwnProperty(application) && object[application] === mixin) {
return true;
}
object = Object.getPrototypeOf(object);
}
}
/**
* Turn a function into a fully featured mixin. The mixin function should be
* a function which takes a single argument which is the class to extend and
* the function must return an extended class.
*
* ```javascript
* const ExampleMixin = toMixin(base => class extends base {
* ...
* });
* ```
*
* @param func
*/
function toMixin(func) {
/*
* Define a function that checks if the mixin has already been applied
* to the prototype chain. This allows mixins to use other mixins as needed
* without them being applied twice.
*/
var mixinOnce = function (base) {
if (has(base.prototype, func))
return base;
var result = func(base);
result.prototype[application] = func;
return result;
};
/*
* Define a custom hasInstance symbol so that instanceof can be used if
* the environment supports it.
*/
if (Symbol.hasInstance) {
if (func.hasOwnProperty(Symbol.hasInstance)) {
/*
* Mixin has its own hasInstance, let the outer function delegate
* to it.
*/
Object.defineProperty(mixinOnce, Symbol.hasInstance, {
value: function mixinHasInstance(other) {
return func[Symbol.hasInstance](other);
}
});
}
else {
/*
* The mixin function does not have a custom hasInstance, use our
* own.
*/
Object.defineProperty(mixinOnce, Symbol.hasInstance, {
value: function mixinHasInstance(other) {
return has(other, func);
}
});
}
}
return mixinOnce;
}
exports.toMixin = toMixin;
//# sourceMappingURL=mixin.js.map