UNPKG

@typescript-package/wrapped-descriptor

Version:

A lightweight TypeScript library for wrapped property descriptor.

472 lines (462 loc) 17.4 kB
import { CommonDescriptor } from '@typescript-package/descriptor'; // Abstract. /** * @description The abstract class for wrapped descriptors. * @export * @abstract * @class WrappedDescriptorCore * @template [O=any] The type of the object to define the descriptor on. * @template {keyof O} [K=keyof O] The key of the object to define the descriptor on. * @template {K extends keyof O ? O[K] : any} [V=K extends keyof O ? O[K] : any] The value type of the key in the object. * @template {boolean} [A=boolean] The type of active. * @template {boolean} [N=boolean] The type of enabled. * @template {boolean} [C=boolean] The type of configurable. * @template {boolean} [E=boolean] The type of enumerable. * @template {WrappedDescriptorCore<O, K, V, A, N, C, E, D> | PropertyDescriptor} [D=WrappedDescriptorCore<O, K, V, A, N, C, E, any>] * @extends {CommonDescriptor<C, E>} * @implements {WrappedPropertyDescriptor<O, K, V, A, N, C, E, D>} */ class WrappedDescriptorCore extends CommonDescriptor { /** * @description The defaults for instance `active` property. * @public * @static * @type {boolean} */ static active = true; /** * @description The defaults for instance `enabled` property. * @public * @static * @type {boolean} */ static enabled = true; /** * @description The prefix for the private key. * @public * @static * @type {string} */ static prefix = '_'; /** * @description Wraps the property with the descriptor. * @protected * @param {Partial<WrappedPropertyDescriptor<O, K, V, A, N, C, E, D>>} param0 The wrapped property `set` and `get` descriptor. * @returns {(Pick<WrappedPropertyDescriptor<O, K, V, A, N, C, E, D>, 'get' | 'set'>)} */ wrap({ get, set }) { // Use descriptor instance. const descriptor = this; // Return the wrapped property. return { get: get ? (function () { return get?.call(this, descriptor); }) : (function () { const o = this; // Check if the descriptor is active. const active = typeof descriptor.active === 'object' ? descriptor.active.onGet : descriptor.active; // Check if the descriptor is enabled. const enabled = typeof descriptor.enabled === 'boolean' ? descriptor.enabled : WrappedDescriptorCore.enabled; // Perform previous descriptor `get`. Handle the data descriptor as first. let previousValue = descriptor.previousDescriptor && descriptor.previousDescriptor.enabled !== false ? 'value' in descriptor.previousDescriptor ? descriptor.previousDescriptor.value : descriptor.previousDescriptor?.get ? descriptor.previousDescriptor.get.call(o, descriptor.previousDescriptor) : undefined : undefined; // Returns. // If descriptor is enabled, return the value from the `privateKey` also by using `onGet` hook on `active` set to `true`. if (enabled === true) { return descriptor.onGet && active === true ? descriptor.onGet.call(o, descriptor.key, previousValue, o[descriptor.privateKey], o) : o[descriptor.privateKey]; } return void (0); }), set: set ? function (value) { set?.call(this, value, descriptor); } : function (value) { // Set the this as the target object. const o = this; // Check if the descriptor is active. const active = typeof descriptor.active === 'object' ? descriptor.active.onSet : descriptor.active; // Check if the descriptor is enabled. const enabled = typeof descriptor.enabled === 'boolean' ? descriptor.enabled : WrappedDescriptorCore.enabled; // Initialize `previousValue`. let previousValue = undefined; // Get the previous value from previous descriptor or current value. if (enabled === true) { previousValue = descriptor.previousDescriptor && descriptor.previousDescriptor.enabled !== false ? 'value' in descriptor.previousDescriptor ? descriptor.previousDescriptor.value : descriptor.previousDescriptor.privateKey ? o[descriptor.previousDescriptor.privateKey] : o[descriptor.privateKey] : o[descriptor.privateKey]; } // Perform previous descriptor. descriptor.previousDescriptor?.set && descriptor.previousDescriptor.enabled !== false && descriptor.previousDescriptor.set.call(o, value, descriptor.previousDescriptor); if (enabled === true) { // Set the value under the `privateKey`. o[descriptor.privateKey] = descriptor.onSet && active === true ? descriptor.onSet.call(o, value, previousValue, descriptor.key, o) : value; } } }; } } // Abstract. /** * @description The base abstraction class for plain wrapped descriptors. * @export * @abstract * @class PlainWrappedDescriptorBase * @template [O=any] The type of the object to define the descriptor on. * @template {keyof O} [K=keyof O] The key of the object to define the descriptor on. * @template {K extends keyof O ? O[K] : any} [V=K extends keyof O ? O[K] : any] The value type of the key in the object. * @template {boolean} [A=boolean] The type of active. * @template {boolean} [N=boolean] The type of enabled. * @template {boolean} [C=boolean] The type of configurable. * @template {boolean} [E=boolean] The type of enumerable. * @template {PlainWrappedDescriptorBase<O, K, V, A, N, C, E, D> | PropertyDescriptor} [D=PlainWrappedDescriptorBase<O, K, V, A, N, C, E, any>] * @extends {WrappedDescriptorCore<O, K, V, A, N, C, E, D>} */ class PlainWrappedDescriptorBase extends WrappedDescriptorCore { /** * @description The active state of the descriptor. * @public * @type {(A | { onGet?: boolean; onSet?: boolean })} */ active; /** * @description The enabled state of the descriptor. * @public * @type {N} */ enabled; /** * @description The index of the descriptor in the chain. * @public * @type {?number} */ index; /** * @description The optional `get` method for the descriptor. * @public * @type {(this: O, descriptor?: D) => V} */ get; /** * @description The key of the descriptor. * @public * @type {K} */ key; /** * @description The on get hook function for the descriptor. * @public * @type {?GetterCallback<O, K>} */ onGet; /** * @description The on set hook function for the descriptor. * @public * @type {?SetterCallback<O, K>} */ onSet; /** * @description The previous descriptor. * @public * @type {D} */ previousDescriptor; /** * @description The private key for the descriptor. * @public * @type {PropertyKey} */ privateKey; /** * @description The optional `set` method for the descriptor. * @public * @type {(this: O, value: V, descriptor?: D) => void} */ set; /** * Creates an instance of `WrappedDescriptorBase` child class. * @constructor * @param {O} object The object to define the descriptor on. * @param {K} key The key of the object to define the descriptor on. * @param {Partial<WrappedPropertyDescriptor<O, K, V, A, N, C, E, D>>} attributes The property descriptor to wrap. */ constructor(object, key, attributes) { super(attributes); delete this.index; delete this.onGet; delete this.onSet; // delete this.previousDescriptor; // Assign the properties. // Required. this.active = typeof attributes.active === 'boolean' || typeof attributes.active === 'object' ? attributes.active : PlainWrappedDescriptorBase.active; this.enabled = typeof attributes.enabled === 'boolean' || typeof attributes.enabled === 'object' ? attributes.enabled : PlainWrappedDescriptorBase.enabled; this.key = key; this.previousDescriptor = (attributes.previousDescriptor || Object.getOwnPropertyDescriptor(object, key)); this.privateKey = attributes.privateKey || `_${String(key)}`; // Optional. attributes.index && (this.index = attributes.index); attributes.onGet && (this.onGet = attributes.onGet); attributes.onSet && (this.onSet = attributes.onSet); // Wraps the `get` getter and `set` setter of the descriptor. const { get, set } = super.wrap(attributes); // Assigns the wrapped `get` getter and `set` setter to the descriptor. this.get = get; this.set = set; } } // Abstract. /** * @description The base abstraction class for wrapped descriptors. * @export * @abstract * @class WrappedDescriptorBase * @template [O=any] The type of the object to define the descriptor on. * @template {keyof O} [K=keyof O] The key of the object to define the descriptor on. * @template {K extends keyof O ? O[K] : any} [V=K extends keyof O ? O[K] : any] The value type of the key in the object. * @template {boolean} [A=boolean] The type of active. * @template {boolean} [N=boolean] The type of enabled. * @template {boolean} [C=boolean] The type of configurable. * @template {boolean} [E=boolean] The type of enumerable. * @template {WrappedDescriptorBase<O, K, V, A, N, C, E, D> | PropertyDescriptor} [D=WrappedDescriptorBase<O, K, V, A, N, C, E, any>] * @extends {WrappedDescriptorCore<O, K, V, A, N, C, E, D>} */ class WrappedDescriptorBase extends WrappedDescriptorCore { /** * @inheritdoc */ get active() { return this.#active; } /** * @inheritdoc */ get enabled() { return this.#enabled; } /** * @inheritdoc */ get index() { return this.#index; } /** * @inheritdoc */ get key() { return this.#key; } /** * @inheritdoc */ get onGet() { return this.#onGet; } /** * @inheritdoc */ get onSet() { return this.#onSet; } /** * @inheritdoc */ get previousDescriptor() { return this.#previous; } /** * @inheritdoc */ get privateKey() { return this.#privateKey; } /** * @description The active state of the descriptor. * @type {(A | {onGet?: boolean | undefined; onSet?: boolean | undefined;})} */ #active; /** * @description The enabled state of the descriptor. * @type {N} */ #enabled; /** * @description The index of the descriptor in the chain. * @type {?number} */ #index; /** * @description The key of the descriptor. * @type {K} */ #key; /** * @description The on get hook function for the descriptor. * @type {?GetterCallback<O, K>} */ #onGet; /** * @description The on set hook function for the descriptor. * @type {?SetterCallback<O, K>} */ #onSet; /** * @description The previous descriptor in the chain. * @type {?D} */ #previous; /** * @description The private key for the descriptor. * @type {PropertyKey} */ #privateKey; /** * Creates an instance of `WrappedDescriptorBase` child class. * @constructor * @param {O} object The object to define the descriptor on. * @param {K} key The key of the object to define the descriptor on. * @param {Partial<WrappedPropertyDescriptor<O, K, V, A, N, C, E, D>>} [attributes={}] The property descriptor attributes. */ constructor(object, key, attributes = {}) { super(attributes); // Assign the properties. // Required. this.#active = typeof attributes.active === 'boolean' || typeof attributes.active === 'object' ? attributes.active : WrappedDescriptorBase.active; this.#enabled = typeof attributes.enabled === 'boolean' || typeof attributes.enabled === 'object' ? attributes.enabled : WrappedDescriptorBase.enabled; this.#privateKey = attributes.privateKey || `${WrappedDescriptorBase.prefix}${String(key)}`; // Optional. this.#index = attributes.index; this.#key = key; this.#onGet = attributes.onGet; this.#onSet = attributes.onSet; this.#previous = attributes.previousDescriptor; } /** * @inheritdoc * @public * @returns {WrappedPropertyDescriptor<O, K, V, A, N, C, E, D>} */ valueOf() { return { active: this.active, configurable: this.configurable, enabled: this.enabled, enumerable: this.enumerable, get: this.get, index: this.index, onGet: this.onGet, onSet: this.onSet, previousDescriptor: this.previousDescriptor, privateKey: this.privateKey, set: this.set, }; } } // Abstract. /** * @description The plain wrapped descriptor class. * @export * @class PlainWrappedDescriptor * @template [O=any] The type of the object to define the descriptor on. * @template {keyof O} [K=keyof O] The key of the object to define the descriptor on. * @template {K extends keyof O ? O[K] : any} [V=K extends keyof O ? O[K] : any] The value type of the key in the object. * @template {boolean} [A=boolean] The type of active. * @template {boolean} [N=boolean] The type of enabled. * @template {boolean} [C=boolean] The type of configurable. * @template {boolean} [E=boolean] The type of enumerable. * @template {PlainWrappedDescriptorBase<O, K, V, A, N, C, E, D> | PropertyDescriptor} [D=PlainWrappedDescriptorBase<O, K, V, A, N, C, E, any>] */ class PlainWrappedDescriptor extends PlainWrappedDescriptorBase { constructor(object, key, descriptor) { super(object, key, descriptor); } } // Abstract. /** * @description The concrete implementation of wrapped property descriptor. * @export * @class WrappedDescriptor * @template [O=any] The type of the object to define the descriptor on. * @template {keyof O} [K=keyof O] The key of the object to define the descriptor on. * @template {K extends keyof O ? O[K] : any} [V=K extends keyof O ? O[K] : any] The value type of the key in the object. * @template {boolean} [A=boolean] The type of active. * @template {boolean} [N=boolean] The type of enabled. * @template {boolean} [C=boolean] The type of configurable. * @template {boolean} [E=boolean] The type of enumerable. * @template {WrappedDescriptor<O, K, V, A, N, C, E, D> | PropertyDescriptor} [D=WrappedDescriptor<O, K, V, A, N, C, E, any>] The type of the previous descriptor. * @extends {WrappedDescriptorBase<O, K, V, A, N, C, E, D>} */ class WrappedDescriptor extends WrappedDescriptorBase { /** * @description The string tag for the descriptor. * @public * @readonly * @type {string} */ get [Symbol.toStringTag]() { return 'WrappedDescriptor'; } /** * @inheritdoc */ get get() { return this.#get; } /** * @inheritdoc */ get set() { return this.#set; } /** * @description The `get` method for the descriptor. * @type {(this: O, descriptor?: D | undefined) => V} */ #get; /** * @description The `set` method for the descriptor. * @type {(this: O, value: V, descriptor?: D | undefined) => void} */ #set; /** * Creates an instance of `WrappedDescriptor`. * @constructor * @param {O} object The object to define the descriptor on. * @param {K} key The key of the object to define the descriptor on. * @param {Partial<WrappedPropertyDescriptor<O, K, V, A, N, C, E, D>>} attributes */ constructor(object, key, attributes = {}) { super(object, key, attributes); // Wrap the property `get` and `set`. const { get, set } = this.wrap({ get: attributes.get, set: attributes.set }); // Assign the wrapped `get` and `set` methods. this.#get = get; this.#set = set; } } // Abstract. /* * Public API Surface of wrapped-descriptor */ /** * Generated bundle index. Do not edit. */ export { PlainWrappedDescriptor, PlainWrappedDescriptorBase, WrappedDescriptor, WrappedDescriptorBase, WrappedDescriptorCore }; //# sourceMappingURL=typescript-package-wrapped-descriptor.mjs.map