thorish
Version:
This is a library of useful JS concepts and data structures for Node and the browser. It it, unashamedly, a dumping ground for code needed by [@samthor](https://twitter.com/samthor)'s projects.
93 lines (92 loc) • 3.59 kB
TypeScript
import { ConditionListener, ConditionOptions } from './cond.js';
import { DeepObjectPartial } from './object-utils.js';
import type { AbortSignalArgs } from './types.js';
export { matchAny } from './object-utils.js';
/**
* Used to express a filter for {@link Matcher}.
*/
export type Filter<T> = DeepObjectPartial<T>;
/**
* This can be added to a {@link Matcher} to recieve updates based on a filter.
*/
export interface MatcherSub<K> {
add(k: K): any;
delete(k: K): any;
}
/**
* Matcher that allows us to observe groups of keyed objects as they transition through state.
*
* These objects must be cloneable via {@link structuredClone}.
*
* An `undefined` state is equivalent to blank/deleted: it does not exist.
*/
export declare class Matcher<K, T> {
private objects;
private groups;
get(id: K): T | undefined;
/**
* Sets this value into the {@link Matcher}. This will trigger group state changes.
*/
set(id: K, value: T | undefined): void;
delete(id: K): boolean;
/**
* Does any object match this filter?
*/
matchAny(filter: Filter<T>): boolean;
/**
* Matches objects immediately, without grouping.
*/
matchAll(filter: Filter<T>): Generator<K, void, void>;
/**
* Returns the intersection of reading the given keys.
*/
read(keys: Iterable<K>): DeepObjectPartial<T> | undefined;
/**
* Attaches a subscripton to this {@link Matcher} based on the given {@link Filter}. The filter
* will be frozen before use, so you cannot change it later.
*
* This will add all initially matching objects to the {@link MatcherSub}. However, the current
* matching set will not be cleared when the passed signal is aborted.
*/
sub(filter: Filter<T>, g: MatcherSub<K>, options?: AbortSignalArgs): void;
}
export interface Group {
active(): boolean;
addListener(fn: (state: boolean) => any, options?: ConditionOptions): boolean;
removeListener(fn: (state: boolean) => any): boolean;
}
/**
* Provides a wrapper for a number of {@link Group} instances. By default, this is active when
* all of the passed groups (including zero) are active, an AND filter.
*/
export declare class CombineGroup implements Group {
private groups;
private cond;
private isActive;
static create(groups: Group[], isActive?: (groups: Group[]) => boolean): CombineGroup;
constructor(groups: Group[], isActive?: (groups: Group[]) => boolean);
active(): boolean;
addListener(fn: ConditionListener<boolean>, options?: ConditionOptions): boolean;
removeListener(fn: ConditionListener<boolean>): boolean;
}
/**
* Provides a wrapper to manage a {@link Filter} over a {@link Matcher}, both with matched keys
* as well as a derived "active" state.
*
* By default, the group is active if any item matches the filter, however subclasses can change
* this behavior by overriding {@link MatcherGroupprivate isActive}.
*/
export declare class MatcherGroup<K, T> implements Group {
private filter;
private matcher;
private signal;
private matchingSet;
private cond;
static create<K, T>(filter: Filter<T>, matcher: Matcher<K, T>, options?: AbortSignalArgs): MatcherGroup<K, T>;
constructor(filter: Filter<T>, matcher: Matcher<K, T>, options?: AbortSignalArgs);
protected isActive(matchingKeys: ReadonlySet<K>): boolean;
active(): boolean;
matching(): Iterable<K>;
addListener(fn: ConditionListener<boolean>, options?: AbortSignalArgs): boolean;
removeListener(fn: ConditionListener<boolean>): boolean;
}