UNPKG

@exadel/esl

Version:

Exadel Smart Library (ESL) is the lightweight custom elements library that provide a set of super-flexible components

49 lines (48 loc) 2.43 kB
import { getPropertyDescriptor } from '../misc/object/utils'; /** * `@decorate` decorator: adapts a higher-order function `(fn) => wrappedFn` into a lazy method decorator. * - Applies only to class (prototype or static) methods (value descriptors) * - First instance access: binds original to `this`, passes it to `decorator(...args)`, caches wrapped fn on the instance * - Prototype (or super) access returns the original unwrapped function * - Reassignment replaces accessor with a normal writable value (no further wrapping) * - Copy of original own enumerable properties is assigned to the wrapped function * * @param decorator - higher‑order function receiving the bound original method * @param args - extra arguments forwarded to `decorator` after the original function * @throws TypeError when applied to a non-method (accessor / field) */ export function decorate(decorator, ...args) { return function (target, propertyKey, descriptor) { if (!descriptor || typeof descriptor.value !== 'function') { throw new TypeError('Only class methods can be decorated'); } const originalFn = descriptor.value; return descriptor = { enumerable: descriptor.enumerable, configurable: true, get: function getBound() { // Skip own properties const proto = Object.getPrototypeOf(this); // Find the closest descriptor for property const desc = getPropertyDescriptor(proto, propertyKey); // Return original function in case of prototype or super call if (!desc || desc.get !== getBound) return originalFn; // Create a new decorated instance of function (original first bound to instance) const decoratedFn = decorator(originalFn.bind(this), ...args); // Copy original function own keys Object.assign(decoratedFn, originalFn); // Defines own property with the decorated instance return this[propertyKey] = decoratedFn; }, set(value) { Object.defineProperty(this, propertyKey, { value, writable: true, configurable: true, enumerable: descriptor.enumerable }); } }; }; }