fix(mixer): tbh I really hate runtimes

This commit is contained in:
Marcos Susaña 2025-02-26 03:02:10 -04:00
parent b30b3d6051
commit b878cdd19e
No known key found for this signature in database
2 changed files with 19 additions and 69 deletions

View File

@ -1,76 +1,26 @@
/**
* Gets the descriptors of a class.
* @param c The class to get the descriptors of.
* @returns The descriptors of the class.
*/
function getDenoDescriptors(c: TypeClass) {
const protos = [c.prototype];
let v = c;
while ((v = Object.getPrototypeOf(v))) {
if (v.prototype) protos.push(v.prototype);
const IgnoredProps = ['constructor', 'prototype', 'name'];
export function copyProperties(target: InstanceType<TypeClass>, source: TypeClass, ignored?: string[]) {
const keys = Reflect.ownKeys(source);
for (const key of keys) {
if (IgnoredProps.concat(ignored ?? []).includes(key as string)) continue;
if (key in target) continue;
const descriptor = Object.getOwnPropertyDescriptor(source, key);
if (descriptor) {
Object.defineProperty(target, key, descriptor);
}
}
return protos.map(x => Object.getOwnPropertyDescriptors(x));
}
/**
* Gets the descriptors of a class.
* @param c The class to get the descriptors of.
* @returns The descriptors of the class.
*/
function getNodeDescriptors(c: TypeClass) {
let proto = c.prototype;
const result: Record<string, TypedPropertyDescriptor<unknown> | PropertyDescriptor>[] = [];
while (proto) {
const descriptors = Object.getOwnPropertyDescriptors(proto);
// @ts-expect-error this is not a function in all cases
if (descriptors.valueOf.configurable) break;
result.push(descriptors);
proto = Object.getPrototypeOf(proto);
}
return result;
}
function getDescriptors(c: TypeClass) {
//@ts-expect-error
// biome-ignore lint/correctness/noUndeclaredVariables: <explanation>
return typeof Deno === 'undefined' ? getNodeDescriptors(c) : getDenoDescriptors(c);
}
/**
* Mixes a class with other classes.
* @param args The classes to mix.
* @returns The mixed class.
*/
export function Mixin<T, C extends TypeClass[]>(...args: C): C[number] & T {
const Base = args[0];
export function Mixin<T, C extends TypeClass[]>(...mixins: C): C[number] & T {
const Base = mixins[0];
class MixedClass extends Base {
constructor(...constructorArgs: any[]) {
super(...constructorArgs);
for (const mixin of args.slice(1)) {
const descriptors = getDescriptors(mixin).reverse();
for (const desc of descriptors) {
// @ts-expect-error
Object.assign(this, new desc.constructor.value(...constructorArgs));
for (const key in desc) {
if (key === 'constructor') continue;
if (key in MixedClass.prototype) continue;
const descriptor = desc[key];
if (descriptor.value) {
// @ts-expect-error
MixedClass.prototype[key] = descriptor.value;
} else if (descriptor.get || descriptor.set) {
Object.defineProperty(MixedClass.prototype, key, {
get: descriptor.get,
set: descriptor.set,
});
}
}
}
constructor(...args: any[]) {
super(...args);
for (const mixin of mixins.slice(1)) {
// @ts-expect-error
const mixinInstance = new mixin(...args);
copyProperties(this, mixinInstance);
}
}
}

View File

@ -3,7 +3,7 @@ import type { UsingClient } from '../../commands';
import { toCamelCase } from '../../common';
/** */
export abstract class Base {
export class Base {
constructor(client: UsingClient) {
Object.assign(this, { client });
}