mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 12:36:08 +00:00
fix(mixer): rewrite mixins management (#333)
* fix: declared properties * fix: idk mixer * fix(mixer): tbh I really hate runtimes * fix: test * test: change constructor test
This commit is contained in:
parent
7745ec942c
commit
7af24bf043
@ -1,75 +1,30 @@
|
||||
/**
|
||||
* 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) {
|
||||
const keys = Reflect.ownKeys(source);
|
||||
for (const key of keys) {
|
||||
if (IgnoredProps.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) {
|
||||
constructor(...args: any[]) {
|
||||
super(...args);
|
||||
for (const mixin of mixins.slice(1)) {
|
||||
// @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,
|
||||
});
|
||||
}
|
||||
}
|
||||
const mixinInstance = new mixin(...args);
|
||||
copyProperties(this, mixinInstance);
|
||||
let proto = Object.getPrototypeOf(mixinInstance);
|
||||
while (proto && proto !== Object.prototype) {
|
||||
copyProperties(this, proto);
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 });
|
||||
}
|
||||
|
@ -138,7 +138,10 @@ describe('mix decorator', () => {
|
||||
|
||||
it('should handle constructor arguments', () => {
|
||||
class MixinWithConstructor {
|
||||
constructor(public name: string) {}
|
||||
name: string;
|
||||
constructor(name: string) {
|
||||
this.name = name.slice(0, 2);
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name;
|
||||
|
Loading…
x
Reference in New Issue
Block a user