UNPKG

@typescript-package/data

Version:

A lightweight TypeScript library for basic data management.

451 lines (441 loc) 12.7 kB
/** * @description Manages the immutability states of `this` current instance. * @export * @abstract * @class Immutability */ class Immutability { /** * @description * @template Type * @param {Type} object * @returns {Readonly<Type>} */ static deepFreeze(object) { if (object && typeof object === "object" && !Object.isFrozen(object)) { Object.getOwnPropertyNames(object).forEach(prop => Immutability.deepFreeze(object[prop])); Object.freeze(object); } return object; } /** * @description Privately stored locked state as `true` if locked, otherwise `false`. * @type {boolean} */ #locked = false; /** * @description Deeply freezes current `this` instance. * @public * @returns {this} Returns current instance. */ deepFreeze() { if (this.isLocked()) { throw new Error('Cannot freeze a locked object.'); } Immutability.deepFreeze(this); return this; } /** * @description "Prevents the modification of existing property attributes and values, and prevents the addition of new properties." * @public * @returns {this} Returns current instance. */ freeze() { if (this.isLocked()) { throw new Error('Cannot freeze a locked object.'); } Object.freeze(this); return this; } /** * @description Checks whether `this` current instance is frozen. * @public * @returns {boolean} */ isFrozen() { return Object.isFrozen(this); } /** * @description Checks whether the current instance is locked. * @public * @returns {boolean} Returns a `boolean` indicating whether current instance is locked. */ isLocked() { return this.#locked === true; } /** * @description Checks whether the object is mutable. * @public * @returns {boolean} True if the object is mutable, otherwise `false`. */ isMutable() { return !this.isSealed() && !this.isFrozen() && !this.isLocked(); } /** * @description Checks whether `this` current instance is sealed. * @public * @returns {boolean} Returns a `boolean` indicating whether current instance is sealed. */ isSealed() { return Object.isSealed(this); } /** * @description Locks the object, means deeply freezes and blocks the `set()`, ensuring deep immutability. * It combines the features of `Object.freeze`, but extends immutability to nested structures (deep immutability). * @public * @returns {this} Returns current instance. */ lock() { Immutability.deepFreeze(this); this.#locked = true; return this; } /** * @description "Prevents the modification of attributes of existing properties, and prevents the addition of new properties." * @public * @returns {this} Returns current instance. */ seal() { if (this.isLocked()) { throw new Error('Cannot seal a locked object.'); } Object.seal(this); return this; } /** * @description Validates the ability to set the value. * @protected * @returns {this} Returns current instance. */ validate() { if (this.isLocked()) { throw new Error('Cannot set when data is locked.'); } return this; } } // Abstract. /** * @description The base abstraction with immutability for handling data-related classes. * @export * @abstract * @class DataCore * @template Type Represents the type of data value. * @extends {Immutability} */ class DataCore extends Immutability { /** * @description Returns the `string` tag representation of the `DataCore` class when used in `Object.prototype.toString.call(instance)`. * @public * @readonly * @type {string} */ get [Symbol.toStringTag]() { return DataCore.name; } /** * @inheritdoc * @public * @returns {this} */ lock() { Immutability.deepFreeze(this.value); super.lock(); return this; } } /** * @description The class to manage the value of generic type variable `Type`. * @export * @class Value * @template Type The type of the privately stored `#value`. */ class Value { /** * @description Returns the `string` tag representation of the `Value` class when used in `Object.prototype.toString.call(instance)`. * The `tag` getter returns the actual class name defined with the `Symbol.toStringTag()` of the child class. * @public * @readonly * @type {string} */ get [Symbol.toStringTag]() { return Value.name; } /** * @description Returns the string tag of the current instance defined by the `Symbol.toStringTag`. * @public * @returns {string | undefined} The extracted class name, such as `'Value'`, or `undefined` if extraction fails. */ get tag() { const tag = Object.prototype.toString.call(this).slice(8, -1); return tag !== 'Object' ? tag : undefined; } /** * @description Returns the privately stored value of generic type variable `Type`. * @public * @readonly * @type {Type} */ get value() { return this.#value; } /** * @description Privately stored value of generic type variable `Type`. * @type {Type} */ #value; /** * Creates an instance of child class. * @constructor * @param {Type} value The value of generic type variable `Type`. */ constructor(value) { this.#value = value; } /** * @description Sets the value of generic type variable `Type`. * @protected * @returns {this} Returns `this` current instance. */ set(value) { this.#value = value; return this; } } // Abstract. /** * @description The `Data` class is a concrete class that wraps a value and provides methods for setting, retrieving, and destroying the value. * @export * @class Data * @template Type * @extends {DataCore<Type>} */ class Data extends DataCore { /** * @description Returns the `string` tag representation of the `Data` class when used in `Object.prototype.toString.call(instance)`. * @public * @readonly * @type {string} */ get [Symbol.toStringTag]() { return Data.name; } /** * @description Returns the privately stored value of generic type variable `Type`. * @public * @readonly * @type {Type} */ get value() { return this.#value.value; } /** * @description Privately stored value of class `Value`. * @type {Value<Type>} */ #value; /** * Creates an instance of `Data` child class. * @constructor * @param {Type} value Initial data value of generic type variable `Type`. */ constructor(value) { super(); this.#value = new Value(value); } /** * @description Destroys the `Value` object by setting it to `null`. * @public * @returns {this} Returns the current instance. */ destroy() { this.#value = null; return this; } /** * @description Sets the data value. * @public * @param {Type} value The data of `Type` to set. * @returns {this} Returns the current instance. */ set(value) { super.validate(); this.#value.set(value); return this; } } // Abstract. /** * @description The `NamedWeakData` class is a concrete class that manages data in a static `Map` where data is associated with a specified name. * @export * @class NamedWeakData * @template [Type=any] * @template {string} [Name='default'] * @extends {DataCore<Type>} */ class NamedWeakData extends DataCore { name; /** * @description Gets the data from another instance. * @public * @static * @template {string} Name * @template Type * @param {NamedWeakData<Name, Type>} instance Another instance from which to get the data. * @param {Name} name The name from which get the data. * @returns {Type} The value of the data stored in the given instance. */ static getFrom(instance, name) { return NamedWeakData.#value.get(name)?.get(instance); } /** * @description Returns the `string` tag representation of the `NamedWeakData` class when used in `Object.prototype.toString.call(instance)`. * @public * @readonly * @type {string} */ get [Symbol.toStringTag]() { return NamedWeakData.name; } /** * @description A private static `Map` stores under specified `string` type name the data value instance in `WeakMap`. * @static * @readonly * @type {Map<string, WeakMap<any, any>>} */ static #value = new Map(); /** * @description Returns the privately stored data value from the specified name of static `Map`. * @public * @readonly * @type {Type} */ get value() { return NamedWeakData.#value.get(this.name)?.get(this); } /** * Creates an instance of `NamedWeakData` child class. * @constructor * @param {Type} value Initial data value of `Type`. * @param {string} [name='default'] The name under which the value is stored, defaults to `default`. */ constructor(value, name = 'default') { super(); this.name = name; NamedWeakData.#value.get(name) === undefined && NamedWeakData.#value.set(name, new WeakMap()); NamedWeakData.#value.get(name).set(this, value); } /** * @description * @public * @returns {this} Returns `this` current instance. */ clear() { NamedWeakData.#value.clear(); return this; } /** * @description * @public * @returns {this} Returns `this` current instance. */ destroy() { NamedWeakData.#value.get(this.name)?.delete(this); this.clear(); return this; } /** * @description Sets the data value. * @public * @param {Type} value The data of `Type` to set. * @returns {this} Returns `this` current instance. */ set(value) { super.validate(); NamedWeakData.#value.get(this.name)?.set(this, value); return this; } } // Abstract. /** * @description The `WeakData` class is a concrete class that stores data in a static `WeakMap`. * @export * @class WeakData * @template Type * @extends {DataCore<Type>} */ class WeakData extends DataCore { /** * @description Gets the data value from another instance. * @public * @static * @template Type * @param {DataStore<Type>} instance Another instance from which to get the data. * @returns {Type} The value of the data stored in the given instance. */ static get(instance) { return WeakData.#value.get(instance); } /** * @description Returns the `string` tag representation of the `WeakData` class when used in `Object.prototype.toString.call(instance)`. * @public * @readonly * @type {string} */ get [Symbol.toStringTag]() { return WeakData.name; } /** * @description A static, privately stored `WeakMap` used for associating each instance with its value. * @readonly * @type {WeakMap} */ static #value = new WeakMap(); /** * @description * @public * @readonly * @type {Type} */ get value() { return WeakData.#value.get(this); } /** * Creates an instance of `WeakData` child class. * @constructor * @param {Type} value Initial data value of `Type`. */ constructor(value) { super(); WeakData.#value.set(this, value); } /** * @description Destroys the value in a static `WeakMap`. * @public * @returns {this} Returns current instance. */ destroy() { WeakData.#value.delete(this); return this; } /** * @description Sets the data value in a static `WeakMap`. * @public * @param {Type} value The data of `Type` to set. * @returns {this} Returns current instance. */ set(value) { super.validate(); WeakData.#value.set(this, value); return this; } } // Abstract class. /* * Public API Surface of data */ /** * Generated bundle index. Do not edit. */ export { Data, DataCore, Immutability, NamedWeakData, Value, WeakData }; //# sourceMappingURL=typescript-package-data.mjs.map