@unblocks/registry
Version:
All-purpose map data structure on steroids. Successor of @encodable/registry
211 lines (204 loc) • 6.36 kB
TypeScript
/** Union types of all values from a map type */
type ValueOf<T> = T[keyof T];
declare const OverwritePolicy: {
readonly ALLOW: "ALLOW";
readonly PROHIBIT: "PROHIBIT";
readonly WARN: "WARN";
};
type OverwritePolicy = ValueOf<typeof OverwritePolicy>;
interface ItemWithValue<V> {
/** item value */
value: V;
}
interface ItemWithLoader<L> {
/** function that returns value */
loader: () => L;
}
interface RegistryState<V, L extends V | Promise<V>> {
/**
* If this is a global registry, it will be defined.
*/
globalId?: string;
/** name of this registry */
name?: string;
/** schema version, can be used to check compatibility */
version: string;
/**
* fallback key to use if `.get()` was called without a key
* This was the initial value when the registry was created.
*/
initialDefaultKey?: string;
/**
* fallback key to use if `.get()` was called without a key
* This is the current default key.
*/
defaultKey?: string;
/** set the first item registered as the default */
setFirstItemAsDefault: boolean;
/** define if registering with an existing key is allowed, prohibited or warned */
overwritePolicy: OverwritePolicy;
/** map to lookup items by key */
items: {
[key: string]: ItemWithValue<V> | ItemWithLoader<L>;
};
/** map to lookup promises by key */
promises: {
[key: string]: Promise<V>;
};
}
interface RegistryConfig {
/**
* Set this value to define a global registry.
* This will make it a true singleton and accessible via this `globalId` from any package.
*/
globalId?: string;
/** schema version, can be used to check compatibility */
version?: string;
/** name of this registry */
name?: string;
/** fallback key to use if `.get()` was called without a key */
defaultKey?: string;
/** set the first item registered as the default */
setFirstItemAsDefault?: boolean;
/** define if registering with an existing key is allowed, prohibited or warned */
overwritePolicy?: OverwritePolicy;
}
/**
* Registry class
*
* Can use generic to specify type of item in the registry
* @type V Type of value
* @type L Type of value returned from loader function when using `registerLoader()`.
* `L` can be either `V`, `Promise<V>` or `V | Promise<V>`
* Set `L=V` when does not support asynchronous loader.
* By default `L` is set to `V | Promise<V>` to support
* both synchronous and asynchronous loaders.
*/
declare class Registry<V, L extends V | Promise<V> = V | Promise<V>> {
readonly state: RegistryState<V, L>;
constructor(config?: RegistryConfig);
/**
* Clear all item in the registry.
* Reset default key to initial default key (if any)
* @returns the registry itself
*/
clear(): this;
/**
* Apply a function to this registry.
* @param func Function that takes this registry as an argument
* @returns the registry itself
*/
apply(func: (registry: this) => void): 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: string): boolean;
/**
* Register key with a value
* @param key
* @param value
* @returns the registry itself
*/
registerValue(key: string, value: V): this;
/**
* Register key with a loader, a function that returns a value.
* @param key
* @param loader
* @returns the registry itself
*/
registerLoader(key: string, loader: () => L): this;
/**
* Get value from the specified key.
* If the item contains a loader, invoke the loader and return its output.
* @param key
*/
get(key?: string): V | L | undefined;
/**
* 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: string): Promise<V>;
/**
* Return the current default key.
* Default key is a fallback key to use if `.get()` was called without a key.
*/
getDefaultKey(): string | undefined;
/**
* 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: string): this;
/**
* Remove default key.
* Default key is a fallback key to use if `.get()` was called without a key.
*/
clearDefaultKey(): this;
/**
* Return a map of all key-values in this registry.
*/
getMap(): {
[key: string]: V | L | undefined;
};
/**
* Same with `.getMap()` but return a `Promise` that resolves when all values are resolved.
*/
getMapAsPromise(): Promise<{
[key: string]: V;
}>;
/**
* Return all keys in this registry.
*/
keys(): string[];
/**
* Return all values in this registry.
* For loaders, they are invoked and their outputs are returned.
*/
values(): (V | L | undefined)[];
/**
* Same with `.values()` but return a `Promise` that resolves when all values are resolved.
*/
valuesAsPromise(): Promise<V[]>;
/**
* Return all key-value entries in this registry.
*/
entries(): {
key: string;
value: V | L | undefined;
}[];
/**
* Same with `.entries()` but return a `Promise` that resolves when all values are resolved.
*/
entriesAsPromise(): Promise<{
key: string;
value: V;
}[]>;
/**
* Remove the item with the specified key.
* Do nothing if an item with the given key does not exist.
* @param key
*/
remove(key: string): this;
/**
* Get number of items in the registry
*/
size(): number;
/**
* Returns true if there is no item in the registry
*/
isEmpty(): boolean;
}
/**
* Synchronous registry
*/
declare class SyncRegistry<V> extends Registry<V, V> {
}
/**
* Helper function for creating a singleton
* @param create factory function
*/
declare function makeSingleton<T>(create: () => T): () => T;
export { OverwritePolicy, Registry, type RegistryConfig, type RegistryState, SyncRegistry, makeSingleton };