-
Notifications
You must be signed in to change notification settings - Fork 0
/
_internal.ts
96 lines (78 loc) · 3.42 KB
/
_internal.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
abstract class PrivateConstructClass {
protected constructor(..._args: any[]) { }
}
type _PrivateConstruct = typeof PrivateConstructClass
export interface PrivateConstruct extends _PrivateConstruct { }
export type AbstractClass<T = any, Args extends any[] = any[]> = abstract new (...args: Args) => T
export interface Class<T = any> extends PrivateConstruct { readonly prototype: T }
export type CanMixinFrom<M> = object & { readonly [K in keyof M]?: M[K] }
interface ProtoCanMixin<M extends { prototype: any }> extends AbstractClass {
readonly prototype: CanMixinFrom<M['prototype']>
}
export type CanMixinFromClass<M extends { prototype: any }> = ProtoCanMixin<M> & CanMixinFrom<Omit<M, 'prototype'>>
export type MixedIn<T extends CanMixinFrom<M>, M> = T & Omit<M, keyof T>
export function mixinObject<T extends CanMixinFrom<M>, M extends object>(target: T, rhs: M): asserts target is MixedIn<T, M> {
const descriptors: PropertyDescriptorMap = {}
for (let src: object | null = rhs; src != null; src = Object.getPrototypeOf(src)) {
[...Object.getOwnPropertyNames(src), ...Object.getOwnPropertySymbols(src)].forEach(p => {
descriptors[p] ??= { get: () => (rhs as any)[p] }
})
}
const newProto = Object.defineProperties(Object.create(Object.getPrototypeOf(target)), descriptors)
Object.setPrototypeOf(target, newProto)
}
export function mixin<T extends CanMixinFrom<M>, M extends object, Args extends any[]>(target: T, rhs: abstract new (...args: Args) => M, ...args: Args): asserts target is MixedIn<T, M> {
mixinObject(target, new class extends rhs { }(...args))
}
export function asMixin<T extends CanMixinFrom<M>, M extends object, Args extends any[]>(target: T, rhs: abstract new (...args: Args) => M, ...args: Args): MixedIn<T, M> {
mixin(target, rhs, ...args)
return target
}
export interface Initializer<T, Arg = void> {
(arg: Arg): Initializer.Out<T>
}
export namespace Initializer {
export interface Sync<T, Arg = void> extends Initializer<T, Arg> {
(arg: Arg): Initializer.Ref<T>
}
export interface Ref<T> { readonly value: T }
export type Out<T> = Ref<T> | Promise<Ref<T>>
export function flatMap<T, U, Arg = void>(
init: Initializer<T, Arg>,
transform: (value: T) => Initializer<U>,
): Initializer<U, Arg> {
return (arg: Arg) => {
const ref = init(arg)
if ('value' in ref) { return transform(ref.value)() }
return ref.then(({ value }) => transform(value)())
}
}
export function chain<T, U, Arg = void>(
init: Initializer<T, Arg>,
transform: Initializer<U, T>
): Initializer<U, Arg> {
return (arg: Arg) => {
const ref = init(arg)
if ('value' in ref) { return transform(ref.value) }
return ref.then(({ value }) => transform(value))
}
}
}
export function isObject(x: unknown): x is object {
return x !== null && (typeof x == 'object' || typeof x == 'function')
}
export function nullable<T>(x: T): T | null {
return x
}
export function nameFunction<F extends (...any: any[]) => any>(f: F, name: string): F {
if (f.name == name) return f
if (!f.name) {
try {
Object.defineProperty(f, 'name', { value: name })
return f
} catch { /* ignore */ }
}
return { [name]: ((...args) => f(...args)) as F }[name]
}
/* eslint */
export type Extending<_Sup, Sub> = Sub