An error occurred while loading the file. Please try again.
-
Guillaume Perréal authored0c1b50c5
/**
* Fonctions pour "patcher" les méthodes d'une classe.
*/
type Hookable<K extends string | symbol, M extends (...args: any[]) => any> = {
[X in K]: M
};
function isHookable<
K extends string | symbol,
M extends (...args: any[]) => any
>(what: unknown, key: K): what is Hookable<K, M> {
return (
typeof what === 'object' &&
what !== null &&
key in what &&
typeof (what as any)[key] === 'function'
);
}
/**
* Installe un hook.
*/
function installHook<
T extends Hookable<K, M>,
M extends (this: T, ...args: any[]) => void,
K extends string | symbol
>(target: T, name: K, makeHook: (old: M) => M): void {
if (!isHookable<K, M>(target, name)) {
throw new Error(`cannot hook ${name} on ${target}`);
}
if (name === 'constructor') {
throw new Error('cannot hook constructors');
}
target[name] = <T[K]>makeHook(target[name]);
}
/**
* Modifie une méthode d'un objet pour éxecuter une fonction avant son éxecution normale.
*
* @param {object} target Le prototype à modifier.
* @param {string|symbol} name Le nom de la méthode à surcharger.
* @param {function} hook La fonction à ajouter.
*/
export function hookBefore<
T extends Hookable<K, M>,
M extends (this: T, ...args: any[]) => void,
K extends string | symbol
>(target: Hookable<K, M>, name: K, hook: M): void {
installHook(
target,
name,
oldMethod =>
function(...args: any[]): void {
hook.apply(this, args);
oldMethod.apply(this, args);
}
);
}
/**
* Modifie une méthode d'un objet pour éxecuter une fonction après son éxecution normale.
*
* @param {object} target Le prototype à modifier.
* @param {string|symbol} name Le nom de la méthode à surcharger.
* @param {function} hook La fonction à ajouter.
*/
export function hookAfter<
T extends Hookable<K, M>,
M extends (this: T, ...args: any[]) => void,
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
K extends string | symbol
>(target: T, name: K, hook: M): void {
installHook(
target,
name,
oldMethod =>
function(...args: any[]): void {
oldMethod.apply(this, args);
hook.apply(this, args);
}
);
}
/**
* Modifie une méthode d'un objet pour éxecuter inconditionnellement une fonction après son éxecution normale.
*
* @param {object} target Le prototype à modifier.
* @param {string|symbol} name Le nom de la méthode à surcharger.
* @param {function} hook La fonction à ajouter.
*/
export function hookFinally<
T extends Hookable<K, M>,
M extends (this: T, ...args: any[]) => void,
K extends string | symbol
>(target: T, name: K, hook: M): void {
installHook(
target,
name,
oldMethod =>
function(...args: any[]): void {
try {
oldMethod.apply(this, args);
} finally {
hook.apply(this, args);
}
}
);
}