feat(lib): add @revenge-mod/patcher

This commit is contained in:
PalmDevs 2025-03-30 00:28:06 +07:00
parent 60487ec890
commit 5add60b70f
No known key found for this signature in database
GPG key ID: 6FAE8F8677ACA8BA
9 changed files with 714 additions and 0 deletions

121
lib/patcher/LICENSE Normal file
View file

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

7
lib/patcher/README.md Normal file
View file

@ -0,0 +1,7 @@
# @revenge-mod/patcher
This is a JavaScript library that allows to monkey patch functions in a way that is easy to use and understand.
It is made by [ryan-0324](https://github.com/ryan-0324) [(source uploaded on Discord)](https://discord.com/channels/1205207689832038522/1284131216156655646/1316076586981789709) and licensed under [CC0](./LICENSE).
This source code is adapted to work with the Revenge Modification Project, and we do not claim any rights to this library. You may use it following the license.

16
lib/patcher/package.json Normal file
View file

@ -0,0 +1,16 @@
{
"name": "@revenge-mod/patcher",
"author": {
"name": "ryan-0324",
"email": "77452312+ryan-0324@users.noreply.github.com",
"url": "https://github.com/ryan-0324"
},
"license": "CC0-1.0",
"private": true,
"type": "module",
"exports": {
".": {
"default": "./src/index.ts"
}
}
}

View file

@ -0,0 +1,69 @@
import {
createPatchedFunctionProxy,
patchedFunctionProxyStates,
unproxy,
type HookNode,
type PatchedFunctionProxyState,
} from '../internal'
function unpatchAfter<T extends UnknownFunction>(
state: PatchedFunctionProxyState<PropertyKey, T>,
hookNode: HookNode<BeforeHook<T>>,
) {
if (hookNode.unpatched) return
hookNode.unpatched = true
hookNode.hook = undefined
const { prev, next } = hookNode
if (prev === undefined) {
state.after = next
if (next === undefined) {
if (state.before === undefined && state.instead === undefined) unproxy(state)
return
}
} else {
prev.next = next
hookNode.prev = undefined
if (next === undefined) return
}
next.prev = prev
hookNode.next = undefined
}
export function after<Parent extends Record<Key, UnknownFunction>, Key extends PropertyKey>(
parent: Parent,
key: FiniteDomain<Key>,
hook: AfterHook<Parent[Key]>,
): () => void
export function after<Key extends PropertyKey, Value extends UnknownFunction>(
parent: Record<Key, Value>,
key: FiniteDomain<Key>,
hook: AfterHook<Value>,
) {
const target = parent[key]
let state = patchedFunctionProxyStates.get(target)
let hookNode: HookNode<typeof hook>
if (state !== undefined && state.parent === parent && state.key === key) {
const head = state.after
hookNode = {
unpatched: false,
hook,
prev: undefined,
next: head,
}
if (head !== undefined) head.prev = hookNode
state.after = hookNode
} else {
hookNode = {
unpatched: false,
hook,
prev: undefined,
next: undefined,
}
state = createPatchedFunctionProxy(target, parent, key, undefined, undefined, hookNode)
}
return unpatchAfter.bind(undefined, state, hookNode)
}

View file

@ -0,0 +1,69 @@
import {
createPatchedFunctionProxy,
patchedFunctionProxyStates,
unproxy,
type HookNode,
type PatchedFunctionProxyState,
} from '../internal'
function unpatchBefore<T extends UnknownFunction>(
state: PatchedFunctionProxyState<PropertyKey, T>,
hookNode: HookNode<BeforeHook<T>>,
) {
if (hookNode.unpatched) return
hookNode.unpatched = true
hookNode.hook = undefined
const { prev, next } = hookNode
if (prev === undefined) {
state.before = next
if (next === undefined) {
if (state.instead === undefined && state.after === undefined) unproxy(state)
return
}
} else {
prev.next = next
hookNode.prev = undefined
if (next === undefined) return
}
next.prev = prev
hookNode.next = undefined
}
export function before<Parent extends Record<Key, UnknownFunction>, Key extends PropertyKey>(
parent: Parent,
key: FiniteDomain<Key>,
hook: BeforeHook<Parent[Key]>,
): () => void
export function before<Key extends PropertyKey, Value extends UnknownFunction>(
parent: Record<Key, Value>,
key: FiniteDomain<Key>,
hook: BeforeHook<Value>,
) {
const target = parent[key]
let state = patchedFunctionProxyStates.get(target)
let hookNode: HookNode<typeof hook>
if (state !== undefined && state.parent === parent && state.key === key) {
const head = state.before
hookNode = {
unpatched: false,
hook,
prev: undefined,
next: head,
}
if (head !== undefined) head.prev = hookNode
state.before = hookNode
} else {
hookNode = {
unpatched: false,
hook,
prev: undefined,
next: undefined,
}
state = createPatchedFunctionProxy(target, parent, key, hookNode, undefined, undefined)
}
return unpatchBefore.bind(undefined, state, hookNode)
}

View file

@ -0,0 +1,85 @@
import {
createPatchedFunctionProxy,
patchedFunctionProxyHandler,
patchedFunctionProxyStates,
unproxy,
type FunctionProxyState,
type InsteadHookNode,
type PatchedFunctionProxyState,
} from '../internal'
const insteadHookProxyHandler = {
...patchedFunctionProxyHandler,
apply<T extends Callable>(hookNode: InsteadHookNode<T>, receiver: ThisParameterType<T>, args: Parameters<T>) {
const { next } = hookNode
return Reflect.apply(hookNode.hook, receiver, [args, next === undefined ? hookNode.target : next.proxy])
},
construct<T extends AbstractNewable<never, object>>(
hookNode: InsteadHookNode<T>,
args: ConstructorParameters<T>,
ctor: AbstractNewable,
) {
const { next } = hookNode
return Reflect.construct(hookNode.hook, [args, next === undefined ? hookNode.target : next.proxy], ctor)
},
} as const satisfies Required<ProxyHandler<FunctionProxyState>>
function unpatchInstead<T extends UnknownFunction>(
state: PatchedFunctionProxyState<PropertyKey, T>,
hookNode: InsteadHookNode<T>,
) {
if (hookNode.unpatched) return
hookNode.unpatched = true
const { prev, next } = hookNode
if (prev === undefined) {
state.instead = next
if (next === undefined) {
if (state.before === undefined && state.after === undefined) unproxy(state)
return
}
} else {
prev.next = next
hookNode.prev = undefined
if (next === undefined) return
}
next.prev = prev
hookNode.next = undefined
}
export function instead<Parent extends Record<Key, UnknownFunction>, Key extends PropertyKey>(
parent: Parent,
key: FiniteDomain<Key>,
hook: InsteadHook<Parent[Key]>,
): () => void
export function instead<Key extends PropertyKey, Value extends UnknownFunction>(
parent: Record<Key, Value>,
key: FiniteDomain<Key>,
hook: InsteadHook<Value>,
) {
const target = parent[key]
let state = patchedFunctionProxyStates.get(target)
// biome-ignore lint/complexity/useArrowFunction: We need a function that has a constructor
const hookNode = function () {}
// The handler makes the proxy behave as target.
hookNode.proxy = new Proxy<any>(hookNode, insteadHookProxyHandler) as Value
hookNode.target = target
hookNode.unpatched = false
hookNode.hook = hook
hookNode.prev = undefined
if (state !== undefined && state.parent === parent && state.key === key) {
const head = state.instead
hookNode.next = head
if (head !== undefined) head.prev = hookNode
state.instead = hookNode
} else {
hookNode.next = undefined
state = createPatchedFunctionProxy(target, parent, key, undefined, hookNode, undefined)
}
return unpatchInstead.bind(undefined, state, hookNode)
}

47
lib/patcher/src/index.ts Normal file
View file

@ -0,0 +1,47 @@
import { after as _after } from './hooks/after'
import { before as _before } from './hooks/before'
import { instead as _instead } from './hooks/instead'
export * from './hooks/after'
export * from './hooks/before'
export * from './hooks/instead'
/**
* Creates a new instance of the patcher.
* @see {PatcherInstance}
*/
export function createPatcherInstance(): PatcherInstance {
const up: Array<() => void> = []
return {
after: (p, k, h) => {
const u = _after(p, k, h)
up.push(u)
return u
},
before: (p, k, h) => {
const u = _before(p, k, h)
up.push(u)
return u
},
instead: (p, k, h) => {
const u = _instead(p, k, h)
up.push(u)
return u
},
unpatchAll: () => {
for (const u of up) u()
up.length = 0
},
}
}
/**
* An instance of the patcher that allows reverting all patches on command.
*/
export interface PatcherInstance {
after: typeof _after
before: typeof _before
instead: typeof _instead
unpatchAll: () => void
}

133
lib/patcher/src/internal.ts Normal file
View file

@ -0,0 +1,133 @@
export interface FunctionProxyState<T extends UnknownFunction = UnknownFunction> {
readonly proxy: T
readonly target: T
}
export interface PatchedFunctionProxyState<
Key extends PropertyKey = PropertyKey,
Value extends UnknownFunction = UnknownFunction,
> extends FunctionProxyState<Value> {
/** Must have a function valued property whose key is {@link key}. */
readonly parent: Record<Key, Value>
readonly key: Key
before: HookNode<BeforeHook<Value>> | undefined
instead: InsteadHookNode<Value> | undefined
after: HookNode<AfterHook<Value>> | undefined
}
export interface HookNode<Hook extends UnknownFunction = UnknownFunction> {
/** Checked so that hook node lists are not cleared if an unpatch function is called more than once. */
unpatched: boolean
/** Can be undefined only in instances that are not in a hook node list. */
hook: Hook | undefined
prev: HookNode<Hook> | undefined
next: HookNode<Hook> | undefined
}
export interface InsteadHookNode<T extends UnknownFunction = UnknownFunction>
extends HookNode<InsteadHook<T>>,
FunctionProxyState<T> {
readonly hook: InsteadHook<T>
prev: InsteadHookNode<T> | undefined
next: InsteadHookNode<T> | undefined
}
/** @throws {TypeError} When `hookNode` is defined, its hook and that of all other hook nodes in its list must also be defined. */
function applyHooks<T>(hookNode: HookNode<(arg: T) => T> | undefined, arg: T) {
while (hookNode !== undefined) {
// Save a reference to the next hook node in case the current hook calls unpatch.
const { next, hook } = hookNode
// Indirectly call the hook so as to not give it access to its hook node.
arg = hook!(arg)
hookNode = next
}
return arg
}
export const patchedFunctionProxyHandler = {
apply<T extends Callable>(
state: PatchedFunctionProxyState<PropertyKey, T>,
receiver: ThisParameterType<T>,
args: Parameters<T>,
) {
args = applyHooks(state.before, args)
const { instead } = state
let result: ReturnType<T> = Reflect.apply(instead === undefined ? state.target : instead.proxy, receiver, args)
result = applyHooks(state.after, result)
return result
},
construct<T extends AbstractNewable<never, object>>(
state: PatchedFunctionProxyState<PropertyKey, T>,
args: ConstructorParameters<T>,
ctor: AbstractNewable,
) {
args = applyHooks(state.before, args)
const { instead } = state
let result: InstanceType<T> = Reflect.construct(
instead === undefined ? state.target : instead.proxy,
args,
ctor,
)
result = applyHooks(state.after, result)
return result
},
defineProperty: (state, key, descriptor) => Reflect.defineProperty(state.target, key, descriptor),
deleteProperty: (state, key) => Reflect.deleteProperty(state.target, key),
get: (state, key, receiver: unknown) => Reflect.get(state.target, key, receiver),
getOwnPropertyDescriptor: (state, key) => Reflect.getOwnPropertyDescriptor(state.target, key),
getPrototypeOf: state => Reflect.getPrototypeOf(state.target),
has: (state, key) => Reflect.has(state.target, key),
isExtensible: state => Reflect.isExtensible(state.target),
ownKeys: state => Reflect.ownKeys(state.target),
preventExtensions: state => Reflect.preventExtensions(state.target),
set: (state, key, value: unknown, receiver: unknown) => Reflect.set(state.target, key, value, receiver),
setPrototypeOf: (state, prototype) => Reflect.setPrototypeOf(state.target, prototype),
} as const satisfies Required<ProxyHandler<FunctionProxyState>>
interface PatchedFunctionProxyStateMap extends WeakMap<UnknownFunction, any> {
readonly delete: (key: UnknownFunction) => boolean
readonly get: <K extends UnknownFunction>(key: K) => PatchedFunctionProxyState<PropertyKey, K> | undefined
readonly has: (key: UnknownFunction) => boolean
readonly set: <K extends UnknownFunction>(key: K, value: PatchedFunctionProxyState<PropertyKey, K>) => this
}
/** proxy -> state */
export const patchedFunctionProxyStates: PatchedFunctionProxyStateMap = new WeakMap<UnknownFunction>()
export function createPatchedFunctionProxy<Key extends PropertyKey, Value extends UnknownFunction>(
target: Value,
parent: Record<Key, Value>,
key: FiniteDomain<Key>,
before: HookNode<BeforeHook<Value>> | undefined,
instead: InsteadHookNode<Value> | undefined,
after: HookNode<AfterHook<Value>> | undefined,
): PatchedFunctionProxyState<Key, Value> {
// biome-ignore lint/complexity/useArrowFunction: We need a function that has a constructor
const state = function () {}
// The handler makes the proxy behave as state.target.
const proxy: Value = new Proxy(state, patchedFunctionProxyHandler) as any
state.proxy = proxy
state.target = target
state.parent = parent
state.key = key
state.before = before
state.instead = instead
state.after = after
patchedFunctionProxyStates.set(proxy, state)
parent[key] = proxy
return state
}
export function unproxy(state: PatchedFunctionProxyState) {
const { parent, key } = state
if (parent[key] === state.proxy) parent[key] = state.target
}

167
lib/patcher/src/types.d.ts vendored Normal file
View file

@ -0,0 +1,167 @@
type FiniteDomain<Key extends PropertyKey> = unknown extends (
Key extends unknown
? {} extends Record<Key, unknown>
? unknown
: never
: never
)
? never
: Key
type UnknownFunction = Callable | AbstractNewable
type Callable<This = never, Args extends readonly unknown[] = never, Return = unknown> = (
this: This,
...args: Args
) => Return
type AbstractNewable<Args extends readonly unknown[] = never, Return = unknown> = abstract new (...args: Args) => Return
type ConcreteNewable<Args extends readonly unknown[] = never, Return = unknown> = new (...args: Args) => Return
type UnionToIntersection<Union> = (Union extends unknown ? (arg: Union) => unknown : never) extends (
arg: infer Intersection,
) => unknown
? Intersection & Union
: never
type BeforeHook<T extends UnknownFunction = UnknownFunction> = OverloadUnion<T> extends infer U
? 0 extends 1 & U
? (args: any) => any
: UnionToIntersection<
U extends Callable<never, infer Args>
? (args: Args) => Args
: U extends ConcreteNewable<infer Args>
? (args: Args) => Args
: never
>
: never
type InsteadHook<T extends UnknownFunction = UnknownFunction> = OverloadUnion<T> extends infer U
? 0 extends 1 & U
?
| ((this: any, args: any[], originalFunction: T) => any)
| (abstract new (
args: any[],
originalFunction: T,
) => any)
: UnionToIntersection<
U extends Callable<infer This, infer Args, infer Return>
? (this: This, args: Args, originalFunction: T) => Return
: U extends ConcreteNewable<infer Args, infer Return>
? abstract new (
args: Args,
originalFunction: T,
) => Return
: never
>
: never
type AfterHook<T extends UnknownFunction = UnknownFunction> = OverloadUnion<T> extends infer U
? 0 extends 1 & U
? (result: any) => any
: UnionToIntersection<
U extends Callable<never, never, infer Return>
? (result: Return) => Return
: U extends ConcreteNewable<never, infer Return>
? (result: Return) => Return
: never
>
: never
/** @see {@link https://github.com/microsoft/TypeScript/issues/32164#issuecomment-1146737709} */
type OverloadUnion<Overload extends UnknownFunction, PartialOverload = OmitOverloads<Overload>> = 0 extends 1 & Overload
? any
: Overload extends Callable<infer CThis, infer CArgs, infer CReturn>
? Overload extends AbstractNewable<infer NArgs, infer NReturn>
? OverloadUnionCallableNewable<
Overload,
PartialOverload,
Callable<CThis, CArgs, CReturn>,
ConcreteNewable<NArgs, NReturn>
>
: OverloadUnionCallable<Overload, PartialOverload, Callable<CThis, CArgs, CReturn>>
: Overload extends AbstractNewable<infer NArgs, infer NReturn>
? OverloadUnionNewable<Overload, PartialOverload, ConcreteNewable<NArgs, NReturn>>
: never
type OmitOverloads<T> = { [Key in keyof T]: T[Key] }
type OverloadUnionCallableNewable<
Overload extends Callable & AbstractNewable,
PartialOverload,
CurrentCallable extends Callable,
CurrentNewable extends ConcreteNewable,
> =
| OverloadUnionCallableNewableInner<
CurrentCallable & CurrentNewable & Overload,
CurrentCallable & CurrentNewable & PartialOverload,
CurrentCallable & CurrentNewable
>
| CurrentCallable
| CurrentNewable
type OverloadUnionCallableNewableInner<
Overload extends Callable & AbstractNewable,
PartialOverload,
PreviousOverload extends Callable & ConcreteNewable,
> = PartialOverload extends Overload
? never
: Overload extends Callable<infer CThis, infer CArgs, infer CReturn>
? Overload extends AbstractNewable<infer NArgs, infer NReturn>
? // Detects infinite recursion caused by generic overloads.
Callable<CThis, CArgs, CReturn> & ConcreteNewable<NArgs, NReturn> extends PreviousOverload
? PreviousOverload extends Callable<CThis, CArgs, CReturn> & ConcreteNewable<NArgs, NReturn>
? any
: OverloadUnionCallableNewable<
Overload,
PartialOverload,
Callable<CThis, CArgs, CReturn>,
ConcreteNewable<NArgs, NReturn>
>
: OverloadUnionCallableNewable<
Overload,
PartialOverload,
Callable<CThis, CArgs, CReturn>,
ConcreteNewable<NArgs, NReturn>
>
: never
: never
type OverloadUnionCallable<Overload extends Callable, PartialOverload, CurrentCallable extends Callable> =
| OverloadUnionCallableInner<CurrentCallable & Overload, CurrentCallable & PartialOverload, CurrentCallable>
| CurrentCallable
type OverloadUnionCallableInner<
Overload extends Callable,
PartialOverload,
PreviousOverload extends Callable,
> = PartialOverload extends Overload
? never
: Overload extends Callable<infer This, infer Args, infer Return>
? // Detects infinite recursion caused by generic overloads.
Callable<This, Args, Return> extends PreviousOverload
? PreviousOverload extends Callable<This, Args, Return>
? any
: OverloadUnionCallable<Overload, PartialOverload, Callable<This, Args, Return>>
: OverloadUnionCallable<Overload, PartialOverload, Callable<This, Args, Return>>
: never
type OverloadUnionNewable<Overload extends AbstractNewable, PartialOverload, CurrentNewable extends ConcreteNewable> =
| OverloadUnionNewableInner<CurrentNewable & Overload, CurrentNewable & PartialOverload, CurrentNewable>
| CurrentNewable
type OverloadUnionNewableInner<
Overload extends AbstractNewable,
PartialOverload,
PreviousOverload extends ConcreteNewable,
> = PartialOverload extends Overload
? never
: Overload extends AbstractNewable<infer Args, infer Return>
? // Detects infinite recursion caused by generic overloads.
ConcreteNewable<Args, Return> extends PreviousOverload
? PartialOverload extends ConcreteNewable<Args, Return>
? any
: OverloadUnionNewable<Overload, PartialOverload, ConcreteNewable<Args, Return>>
: OverloadUnionNewable<Overload, PartialOverload, ConcreteNewable<Args, Return>>
: never