UNPKG

@fimbul-works/observable

Version:

A lightweight, strongly-typed TypeScript library for reactive programming patterns, providing observable collections, values, and event handling.

136 lines (135 loc) 5.24 kB
import { ObservableMap } from "./map"; /** * A strict key-value registry that enforces unique registration and required existence. * Extends ObservableMap to provide change notifications while adding stricter guarantees. * * @template K The type of keys in the registry * @template V The type of values in the registry * @extends {ObservableMap<K, V>} */ export class ObservableRegistry extends ObservableMap { /** * Registers a new key-value pair in the registry. * Throws an error if the key is already registered. * * @param key - The key to register * @param value - The value to associate with the key * @returns {this} The registry instance for method chaining * @throws {Error} If the key is already registered */ register(key, value) { if (this.has(key)) { throw new Error(`Already registered: ${String(key)}`); } return this.set(key, value); } /** * Registers a new key-value pair and waits for all change handlers to complete. * @param key - The key to register * @param value - The value to associate with the key * @returns {Promise<this>} Promise resolving to the registry instance for method chaining * @throws {Error} If the key is already registered */ async registerAsync(key, value) { if (this.has(key)) { throw new Error(`Already registered: ${String(key)}`); } return this.setAsync(key, value); } /** * Removes a registered key-value pair from the registry. * * @param key - The key to unregister * @returns {boolean} True if the key was unregistered, false if it wasn't registered */ unregister(key) { return this.delete(key); } /** * Removes a registered key-value pair and waits for all change handlers to complete. * @param key - The key to unregister * @returns {Promise<boolean>} Promise resolving to true if the key was unregistered, false otherwise */ async unregisterAsync(key) { return this.deleteAsync(key); } /** * Retrieves a value from the registry by its key. * Unlike the parent ObservableMap, this method throws if the key doesn't exist. * @param key - The key to look up * @param throwErrorOnMissing - Throws error when a key is registered if true * @returns {V} The value associated with the key * @throws {Error} If the key is not registered * @override */ get(key, throwErrorOnMissing = true) { const value = super.get(key); if (value === undefined && throwErrorOnMissing) { throw new Error(`Not registered: ${String(key)}`); } return value; } /** * Updates a registered value if it exists. * Unlike set(), this method throws if the key doesn't exist. * @param key - The key to update * @param value - The new value to associate with the key * @returns {this} The registry instance for method chaining * @throws {Error} If the key is not registered */ update(key, value) { if (!this.has(key)) { throw new Error(`Cannot update: ${String(key)} is not registered`); } return this.set(key, value); } /** * Updates a registered value and waits for all change handlers to complete. * @param key - The key to update * @param value - The new value to associate with the key * @returns {Promise<this>} Promise resolving to the registry instance for method chaining * @throws {Error} If the key is not registered */ async updateAsync(key, value) { if (!this.has(key)) { throw new Error(`Cannot update: ${String(key)} is not registered`); } return this.setAsync(key, value); } /** * Updates a registered value using a transformation function. * Throws if the key doesn't exist. * @param key - The key to update * @param updateFn - Function that receives the current value and returns the new value * @returns {this} The registry instance for method chaining * @throws {Error} If the key is not registered */ updateWith(key, updateFn) { const currentValue = this.get(key); return this.set(key, updateFn(currentValue)); } /** * Updates a registered value using a transformation function and waits for all change handlers to complete. * @param key - The key to update * @param updateFn - Function that receives the current value and returns the new value * @returns {Promise<this>} Promise resolving to the registry instance for method chaining * @throws {Error} If the key is not registered */ async updateWithAsync(key, updateFn) { const currentValue = this.get(key); return this.setAsync(key, updateFn(currentValue)); } /** * Checks if all provided keys are registered. * @param keys - The keys to check * @returns {boolean} True if all keys are registered, false otherwise */ hasAll(keys) { for (const key of keys) { if (!this.has(key)) { return false; } } return true; } }