Class util refactoring
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
68
src/class.ts
68
src/class.ts
@@ -1,68 +0,0 @@
|
|||||||
import { AbstractClass } from "type-fest"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies all own properties and methods (excluding "length" and "prototype") of one class to another class.
|
|
||||||
*
|
|
||||||
* @param from The class whose properties and methods are to be copied.
|
|
||||||
* @param to The class to which the properties and methods are to be copied.
|
|
||||||
*/
|
|
||||||
export function copyClassProperties(
|
|
||||||
from: AbstractClass<any, any>,
|
|
||||||
to: AbstractClass<any, any>,
|
|
||||||
) {
|
|
||||||
Object.getOwnPropertyNames(from).forEach(name => {
|
|
||||||
if (name === "length"
|
|
||||||
|| name === "prototype"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
Object.defineProperty(
|
|
||||||
to,
|
|
||||||
name,
|
|
||||||
Object.getOwnPropertyDescriptor(from, name) || Object.create(null),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
Object.getOwnPropertyNames(from.prototype).forEach(name => {
|
|
||||||
Object.defineProperty(
|
|
||||||
to.prototype,
|
|
||||||
name,
|
|
||||||
Object.getOwnPropertyDescriptor(from.prototype, name) || Object.create(null),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const flattenClass = <
|
|
||||||
C extends AbstractClass<any, any>
|
|
||||||
>(class_: C) =>
|
|
||||||
getInheritanceHierarchy(class_)
|
|
||||||
.reduce((flattened, current) => {
|
|
||||||
copyClassProperties(current, flattened)
|
|
||||||
return flattened
|
|
||||||
}, class {}) as C
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of classes representing the inheritance hierarchy of a given class constructor. The array includes the given class constructor itself and all its parent classes in the order of inheritance.
|
|
||||||
*
|
|
||||||
* @param class_ The class constructor for which to generate the inheritance hierarchy.
|
|
||||||
* @returns An array of class constructors representing the inheritance hierarchy of `Class`.
|
|
||||||
*/
|
|
||||||
export function getInheritanceHierarchy(
|
|
||||||
class_: AbstractClass<any, any>
|
|
||||||
): AbstractClass<any, any>[] {
|
|
||||||
const parent = Object.getPrototypeOf(class_)
|
|
||||||
|
|
||||||
return isClass(parent)
|
|
||||||
? [...getInheritanceHierarchy(parent), class_]
|
|
||||||
: [class_]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether a given value is a class constructor or not by checking if its `toString` method returns a string matching the pattern of a class definition.
|
|
||||||
*
|
|
||||||
* @param el The value to check for class constructor status.
|
|
||||||
* @returns A boolean indicating whether `el` is a class constructor or not.
|
|
||||||
*/
|
|
||||||
export const isClass = (el: { toString: () => string }) =>
|
|
||||||
Boolean(el.toString().match(/^class(?: [.\S]+)?(?: extends [.\S]+)? {[\s\S]*}$/))
|
|
||||||
@@ -1,3 +1 @@
|
|||||||
export * from "./class"
|
|
||||||
export * from "./trait"
|
export * from "./trait"
|
||||||
export * from "./utils"
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { AbstractClass, Class, UnionToIntersection } from "type-fest"
|
import { AbstractClass, Class, UnionToIntersection } from "type-fest"
|
||||||
import { copyClassProperties, flattenClass } from "./class"
|
import { StaticMembers, copyClassProperties, flattenClass } from "./util/class"
|
||||||
import { StaticMembers } from "./utils"
|
|
||||||
|
|
||||||
|
|
||||||
export type Trait<T> =
|
export type Trait<T> =
|
||||||
|
|||||||
90
src/util/class.ts
Normal file
90
src/util/class.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import { AbstractClass } from "type-fest"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the static members of a class.
|
||||||
|
*
|
||||||
|
* @template C - The type of the class for which static members are extracted.
|
||||||
|
* @typeparam The static members of the class.
|
||||||
|
*/
|
||||||
|
export type StaticMembers<C> = Pick<C, keyof C>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies properties from one class to another, including static and prototype properties.
|
||||||
|
*
|
||||||
|
* @param from - The source class to copy properties from.
|
||||||
|
* @param to - The destination class to copy properties to.
|
||||||
|
*/
|
||||||
|
export function copyClassProperties(
|
||||||
|
from: AbstractClass<any, any>,
|
||||||
|
to: AbstractClass<any, any>,
|
||||||
|
) {
|
||||||
|
Object.getOwnPropertyNames(from).forEach(name => {
|
||||||
|
if (name === "length"
|
||||||
|
|| name === "prototype"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
Object.defineProperty(
|
||||||
|
to,
|
||||||
|
name,
|
||||||
|
Object.getOwnPropertyDescriptor(from, name) || Object.create(null),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.getOwnPropertyNames(from.prototype).forEach(name => {
|
||||||
|
Object.defineProperty(
|
||||||
|
to.prototype,
|
||||||
|
name,
|
||||||
|
Object.getOwnPropertyDescriptor(from.prototype, name) || Object.create(null),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flattens the inheritance hierarchy of a given class by copying all properties
|
||||||
|
* from its superclass chain into a single object.
|
||||||
|
*
|
||||||
|
* @template C - The type of the class to be flattened, extending AbstractClass<any, any>.
|
||||||
|
* @param C - The class to be flattened.
|
||||||
|
* @returns A new class with properties flattened from the entire inheritance hierarchy.
|
||||||
|
*/
|
||||||
|
export function flattenClass<
|
||||||
|
C extends AbstractClass<any, any>
|
||||||
|
>(class_: C) {
|
||||||
|
return getInheritanceHierarchy(class_)
|
||||||
|
.reduce((flattened, current) => {
|
||||||
|
copyClassProperties(current, flattened)
|
||||||
|
return flattened
|
||||||
|
}, class {}) as C
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the inheritance hierarchy of a given class, including itself.
|
||||||
|
*
|
||||||
|
* @param class_ - The class for which the inheritance hierarchy is retrieved.
|
||||||
|
* @returns An array representing the inheritance hierarchy.
|
||||||
|
*/
|
||||||
|
export function getInheritanceHierarchy(
|
||||||
|
class_: AbstractClass<any, any>
|
||||||
|
): AbstractClass<any, any>[] {
|
||||||
|
const parent = Object.getPrototypeOf(class_)
|
||||||
|
|
||||||
|
return isClass(parent)
|
||||||
|
? [...getInheritanceHierarchy(parent), class_]
|
||||||
|
: [class_]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given element appears to be a class based on its string representation.
|
||||||
|
*
|
||||||
|
* @param el - The element to check for being a class.
|
||||||
|
* @returns `true` if the element is likely a class; otherwise, `false`.
|
||||||
|
*/
|
||||||
|
export function isClass(el: { toString: () => string }) {
|
||||||
|
return Boolean(el.toString().match(/^class(?: [.\S]+)?(?: extends [.\S]+)? {[\s\S]*}$/))
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
export type StaticMembers<C> = Pick<C, keyof C>
|
|
||||||
Reference in New Issue
Block a user