UNPKG

@v4fire/core

Version:
225 lines (183 loc) 4.92 kB
/*! * V4Fire Core * https://github.com/V4Fire/Core * * Released under the MIT license * https://github.com/V4Fire/Core/blob/master/LICENSE */ /** * [[include:core/functools/warning/README.md]] * @packageDocumentation */ import { consoleCache } from 'core/functools/warning/const'; import type { WarnOptions, InlineWarnOptions, WarnedFn } from 'core/functools/warning/interface'; export * from 'core/functools/warning/interface'; /** * Marks a function with the specified warning * * @param opts - additional options * @param fn - function to wrap */ export function warn<T extends Function>( opts: WarnOptions, fn: T ): T extends ((...args: infer A) => infer R) ? WarnedFn<A, R> : T; /** * Emits a warning with the specified parameters * @param opts - additional options */ export function warn(opts: InlineWarnOptions): void; /** * Marks a function as non-recommended to use * @param fn - function to wrap */ export function warn<T extends Function>(fn: T): T extends ((...args: infer A) => infer R) ? WarnedFn<A, R> : T; export function warn<T extends Function>( fnOrParams: WarnOptions | InlineWarnOptions | T, fn?: T ): T | undefined { let p: WarnOptions; if (Object.isSimpleFunction(fnOrParams)) { fn = fnOrParams; p = {}; } else { p = fnOrParams; } if (!fn) { wrapper(); return; } wrapper[p.context ?? 'warning'] = p; function wrapper(this: unknown, ...args: unknown[]): unknown { //#unless isProd const name = p.name ?? fn?.name, type = p.type ?? 'function', wasMovedOrRenamed = p.movedTo != null || p.renamedTo != null; const msg: string[] = []; switch (p.context) { case 'deprecated': if (!wasMovedOrRenamed) { msg.push(`The ${type} "${name}" was deprecated and will be removed from the next major release.`); } break; case 'unimplemented': if (!wasMovedOrRenamed) { msg.push(`The ${type} "${name}" is unimplemented.`); } break; default: if (!wasMovedOrRenamed && p.notice == null) { msg.push(`The ${type} "${name}" is not recommended to use.`); } } if (wasMovedOrRenamed) { if (p.movedTo == null) { msg.push( `The ${type} "${name}" was renamed to "${p.renamedTo}".`, 'Please use the renamed version instead of the current, because it will be removed from the next major release.' ); } else if (p.renamedTo == null) { msg.push( `The ${type} "${name}" was moved to a new location "${p.movedTo}".`, 'Please use the moved version instead of the current, because it will be removed from the next major release.' ); } else { msg.push( `The ${type} "${name}" was renamed to "${p.renamedTo}" and moved to a new location "${p.movedTo}".`, 'Please use the new version instead of the current, because it will be removed from the next major release.' ); } } if (p.alternative != null) { if (Object.isString(p.alternative)) { msg.push(`Please use "${p.alternative}" instead.`); } else if (p.alternative.source != null) { msg.push(`Please use "${p.alternative.name}" from "${p.alternative.source}" instead.`); } else { msg.push(`Please use "${p.alternative.name}" instead.`); } } if (p.notice != null) { msg.push(p.notice); } const str = msg.join(' '); if (p.context === 'unimplemented') { throw new Error(str); } else if (consoleCache[str] == null) { console.warn(str); consoleCache[str] = true; } //#endunless return fn?.apply(this, args); } return Object.cast(wrapper); } /** * Decorator for `warn` * * @decorator * @see [[warn]] * * @example * ```js * class Foo { * @warned() * bar() { * * } * } * ``` */ export function warned(target: object, key: string | symbol, descriptor: PropertyDescriptor): void; /** * Decorator for `warn`. * This overload adds a feature to provide additional options. * * @see [[warn]] * @param [opts] - additional options * * @example * ```js * class Foo { * @warned({alternative: 'baz'}}) * bar() { * * } * } * ``` */ export function warned(opts?: WarnOptions): Function; export function warned( opts?: WarnOptions | object, key?: string | symbol, descriptor?: PropertyDescriptor ): Function | undefined { const f = (name, descriptor, opts?) => { const {get, set, value: method} = descriptor; if (get != null) { descriptor.get = warn({type: 'accessor', ...opts, name}, get); } if (set != null) { descriptor.set = warn({type: 'accessor', ...opts, name}, set); } if (get != null || set != null) { return; } if (!Object.isFunction(method)) { throw new TypeError(`descriptor.value is not a function: ${method}`); } descriptor.value = warn({type: 'method', ...opts, name}, method); }; if (arguments.length > 1) { f(key, descriptor); return; } return (target, key, descriptor) => f(key, descriptor, opts); }