src/objects/deprecated.ts
import { Constructor } from '../types';
export type Logger = (_: string) => void;
/**
* @desc A decorator to mark a class, method or function as deprecated and make it log a warning whenever it is used.
* Please see the tests for examples of usage.
*
* @param {string} message - describes the alternative implementation that should be used instead
* of the deprecated method/function/class
* @param {Logger} log - a function that handles the printing of the message,
* such as {@link console.warn}
*/
export function deprecated(message = '', log: Logger = console.warn): (target: any, propertyKey?: string, descriptor?: any) => any { // tslint:disable-line:no-console
// eslint-disable-next-line unicorn/consistent-function-scoping,no-prototype-builtins
const hasPrototype = (target: { hasOwnProperty(_: string): boolean }): boolean => target.hasOwnProperty('prototype');
return (target: any, propertyKey?: string, descriptor?: any): any => { // tslint:disable-line:ban-types
if (target && propertyKey && descriptor) {
return deprecateMethod(message, target, propertyKey, descriptor, log);
}
else if (hasPrototype(target)) {
return deprecateClass(message, target, log);
}
else {
throw new Error(`Only a class, method or function can be marked as deprecated. ${typeof target} given.`);
}
};
}
function deprecateClass(message: string, target: Constructor<any>, log: (...args: any[]) => void): Constructor<any> {
return class extends target {
constructor(...args: any[]) {
log(`${target.name} has been deprecated. ${ message }`.trim());
super(...args);
}
};
}
function deprecateMethod<T extends object>(message: string, target: T, propertyKey: string, descriptor: any, log: (...args: any[]) => void) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
log(`${target.constructor.name}#${propertyKey} has been deprecated. ${ message }`.trim());
return originalMethod.apply(this, args);
};
return descriptor;
}