export const s_constructor = Symbol("constructor");
export class Inheritor {
constructor(...inheritables) {
inheritables = inheritables.map((inheritable) => {
let args = [ ];
if (Array.isArray(inheritable))
[ inheritable, args = [ ] ] = inheritable;
Reflect.apply(inheritable.prototype[s_constructor], this, Array.isArray(args) ? args : [ args ]);
return inheritable;
});
return new Proxy(this, {
has(target, propertyKey) {
if (Reflect.has(target, propertyKey))
return true;
for (let inheritable of inheritables) {
if (Reflect.has(inheritable.prototype, propertyKey))
return true;
}
return false;
},
get(target, propertyKey) {
if (!Reflect.has(target, propertyKey)) {
for (let inheritable of inheritables) {
if (Reflect.has(inheritable.prototype, propertyKey))
return Reflect.get(inheritable.prototype, propertyKey, target);
}
}
return Reflect.get(target, propertyKey);
},
getPrototypeOf(target) {
return null;
},
set(target, propertyKey, value) {
if (!Reflect.has(target, propertyKey)) {
for (let inheritable of inheritables) {
if (Reflect.has(inheritable.prototype, propertyKey))
return Reflect.set(inheritable.prototype, propertyKey, value, target);
}
}
return Reflect.set(target, propertyKey, value);
},
});
}
static [Symbol.hasInstance](instance) {
return this !== Inheritor && Function.prototype[Symbol.hasInstance].call(this, instance);
}
}
export function Inheritable(name) {
let brand = Symbol(name);
return class {
constructor(...args) {
Reflect.apply(inheritable.prototype[s_constructor], this, args);
}
[s_constructor]() {
Reflect.set(this, brand, true, this);
}
static [Symbol.hasInstance](instance) {
return Reflect.get(instance, brand);
}
};
}
class Example extends Inheritable("Example") {
constructor() {
super();
// Put specific logic only for `new Example`.
}
[s_constructor](a) {
super[s_constructor]();
// Put common logic shared between `new Example` and `new Inheritor(Example)`.
}
}