UNPKG

@unblocks/registry

Version:

All-purpose map data structure on steroids. Successor of @encodable/registry

319 lines (311 loc) 8.84 kB
'use client' "use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { OverwritePolicy: () => OverwritePolicy_default, Registry: () => Registry, SyncRegistry: () => SyncRegistry, makeSingleton: () => makeSingleton }); module.exports = __toCommonJS(index_exports); // src/models/Registry.ts var import_global_box = require("global-box"); // src/models/OverwritePolicy.ts var OverwritePolicy = { ALLOW: "ALLOW", PROHIBIT: "PROHIBIT", WARN: "WARN" }; var OverwritePolicy_default = OverwritePolicy; // src/models/createRegistryState.ts function createRegistryState({ globalId, name, version = "0.x.x", defaultKey, setFirstItemAsDefault = false, overwritePolicy = OverwritePolicy_default.ALLOW }) { return { globalId, name, version, defaultKey, initialDefaultKey: defaultKey, setFirstItemAsDefault, overwritePolicy, items: {}, promises: {} }; } // src/models/Registry.ts var Registry = class { constructor(config = {}) { if (typeof config.globalId === "undefined") { this.state = createRegistryState(config); } else { this.state = (0, import_global_box.globalBox)().getOrCreate(config.globalId, () => createRegistryState(config)); } } /** * Clear all item in the registry. * Reset default key to initial default key (if any) * @returns the registry itself */ clear() { this.state.items = {}; this.state.promises = {}; this.state.defaultKey = this.state.initialDefaultKey; return this; } /** * Apply a function to this registry. * @param func Function that takes this registry as an argument * @returns the registry itself */ apply(func) { func(this); return this; } /** * Check if item with the given key exists * @param key the key to look for * @returns true if the item exists, false otherwise */ has(key) { const item = this.state.items[key]; return item !== null && item !== void 0; } /** * Register key with a value * @param key * @param value * @returns the registry itself */ registerValue(key, value) { const item = this.state.items[key]; const willOverwrite = this.has(key) && ("value" in item && item.value !== value || "loader" in item); if (willOverwrite) { if (this.state.overwritePolicy === OverwritePolicy_default.WARN) { console.warn(`Item with key "${key}" already exists. You are assigning a new value.`); } else if (this.state.overwritePolicy === OverwritePolicy_default.PROHIBIT) { throw new Error(`Item with key "${key}" already exists. Cannot overwrite.`); } } if (!item || willOverwrite) { this.state.items[key] = { value }; delete this.state.promises[key]; } if (this.state.setFirstItemAsDefault && !this.state.defaultKey) { this.state.defaultKey = key; } return this; } /** * Register key with a loader, a function that returns a value. * @param key * @param loader * @returns the registry itself */ registerLoader(key, loader) { const item = this.state.items[key]; const willOverwrite = this.has(key) && ("loader" in item && item.loader !== loader || "value" in item); if (willOverwrite) { if (this.state.overwritePolicy === OverwritePolicy_default.WARN) { console.warn(`Item with key "${key}" already exists. You are assigning a new value.`); } else if (this.state.overwritePolicy === OverwritePolicy_default.PROHIBIT) { throw new Error(`Item with key "${key}" already exists. Cannot overwrite.`); } } if (!item || willOverwrite) { this.state.items[key] = { loader }; delete this.state.promises[key]; } if (this.state.setFirstItemAsDefault && !this.state.defaultKey) { this.state.defaultKey = key; } return this; } /** * Get value from the specified key. * If the item contains a loader, invoke the loader and return its output. * @param key */ get(key) { const targetKey = key != null ? key : this.state.defaultKey; if (typeof targetKey === "undefined") return void 0; const item = this.state.items[targetKey]; if (item !== void 0) { if ("loader" in item) { return item.loader && item.loader(); } return item.value; } return void 0; } /** * Similar to `.get()` but wrap results in a `Promise`. * This is useful when some items are async loaders to provide uniform output. * @param key */ getAsPromise(key) { const promise = this.state.promises[key]; if (typeof promise !== "undefined") { return promise; } const item = this.get(key); if (item !== void 0) { const newPromise = Promise.resolve(item); this.state.promises[key] = newPromise; return newPromise; } return Promise.reject(new Error(`Item with key "${key}" is not registered.`)); } /** * Return the current default key. * Default key is a fallback key to use if `.get()` was called without a key. */ getDefaultKey() { return this.state.defaultKey; } /** * Set default key to the specified key * Default key is a fallback key to use if `.get()` was called without a key. * @param key */ setDefaultKey(key) { this.state.defaultKey = key; return this; } /** * Remove default key. * Default key is a fallback key to use if `.get()` was called without a key. */ clearDefaultKey() { this.state.defaultKey = void 0; return this; } /** * Return a map of all key-values in this registry. */ getMap() { return this.keys().reduce((prev, key) => { const map = prev; map[key] = this.get(key); return map; }, {}); } /** * Same with `.getMap()` but return a `Promise` that resolves when all values are resolved. */ getMapAsPromise() { const keys = this.keys(); return Promise.all(keys.map((key) => this.getAsPromise(key))).then( (values) => values.reduce((prev, value, i) => { const map = prev; map[keys[i]] = value; return map; }, {}) ); } /** * Return all keys in this registry. */ keys() { return Object.keys(this.state.items); } /** * Return all values in this registry. * For loaders, they are invoked and their outputs are returned. */ values() { return this.keys().map((key) => this.get(key)); } /** * Same with `.values()` but return a `Promise` that resolves when all values are resolved. */ valuesAsPromise() { return Promise.all(this.keys().map((key) => this.getAsPromise(key))); } /** * Return all key-value entries in this registry. */ entries() { return this.keys().map((key) => ({ key, value: this.get(key) })); } /** * Same with `.entries()` but return a `Promise` that resolves when all values are resolved. */ entriesAsPromise() { const keys = this.keys(); return Promise.all(keys.map((key) => this.getAsPromise(key))).then( (values) => values.map((value, i) => ({ key: keys[i], value })) ); } /** * Remove the item with the specified key. * Do nothing if an item with the given key does not exist. * @param key */ remove(key) { delete this.state.items[key]; delete this.state.promises[key]; return this; } /** * Get number of items in the registry */ size() { return this.keys().length; } /** * Returns true if there is no item in the registry */ isEmpty() { return this.size() === 0; } }; // src/models/SyncRegistry.ts var SyncRegistry = class extends Registry { }; // src/utils/makeSingleton.ts function makeSingleton(create) { let singleton; return function getInstance() { if (typeof singleton === "undefined") { singleton = create(); } return singleton; }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { OverwritePolicy, Registry, SyncRegistry, makeSingleton });