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 "./utils"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { AbstractClass, Class, UnionToIntersection } from "type-fest"
|
||||
import { copyClassProperties, flattenClass } from "./class"
|
||||
import { StaticMembers } from "./utils"
|
||||
import { StaticMembers, copyClassProperties, flattenClass } from "./util/class"
|
||||
|
||||
|
||||
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