UNPKG

ixfx

Version:

Bundle of ixfx libraries

1,585 lines (1,584 loc) 166 kB
import { t as IsEqual } from "./is-equal-BE9SbPVX.js"; import { f as ToString, i as Interval, r as IWithEntries } from "./types-1oz6G7XR.js"; import { A as transformMap, D as sortByValueProperty, E as sortByValue, O as toArray$1, S as mapToObjectTransform, T as some, _ as getOrGenerate, a as addValue$1, b as hasKeyValue, c as deleteByValueCompareMutate, d as findEntryByPredicate, f as findEntryByValue, g as getClosestIntegerKey, h as fromObject, i as addObjectEntriesMutate, j as zipKeyValue, k as toObject, l as filterValues, m as fromIterable, n as GetOrGenerateSync, o as addValueMutate, p as findValue, r as MergeReconcile, s as addValueMutator, t as GetOrGenerate, u as findBySomeKey, v as getOrGenerateSync, w as mergeByKey, x as mapToArray, y as hasAnyValue } from "./maps-DmzuqIRI.js"; import { H as Result } from "./index-DldIQ_ah.js"; import { n as Comparer } from "./comparers-Pedv6tO4.js"; import { n as SimpleEventEmitter } from "./index-DzASKzet.js"; //#region ../packages/collections/src/circular-array.d.ts interface ICircularArray<V> extends Array<V> { /** * Returns true if the array has filled to capacity and is now * recycling array indexes. */ get isFull(): boolean; /** * Returns a new Circular with item added * * Items are added at `pointer` position, which automatically cycles through available array indexes. * * @param value Thing to add * @returns Circular with item added */ add(value: V): ICircularArray<V>; get length(): number; /** * Returns the current add position of array. */ get pointer(): number; } /** * A circular array keeps a maximum number of values, overwriting older values as needed. Immutable. * * `CircularArray` extends the regular JS array. Only use `add` to change the array if you want * to keep the `CircularArray` behaviour. * * @example Basic functions * ```js * let a = new CircularArray(10); * a = a.add(`hello`); // Because it's immutable, capture the return result of `add` * a.isFull; // True if circular array is full * a.pointer; // The current position in array it will write to * ``` * * Since it extends the regular JS array, you can access items as usual: * @example Accessing * ```js * let a = new CircularArray(10); * ... add some stuff .. * a.forEach(item => // do something with item); * ``` * @param capacity Maximum capacity before recycling array entries * @return Circular array */ declare class CircularArray<V> extends Array { #private; constructor(capacity?: number); /** * Add to array * @param value Thing to add * @returns */ add(value: V): CircularArray<V>; get pointer(): number; get isFull(): boolean; } //#endregion //#region ../packages/collections/src/events/types.d.ts type EventItem = Readonly<{ /** * Start point, inclusive */ start: number; /** * End point, exclusive */ end: number; }>; type EventItemAsDuration = Readonly<{ start: number; duration: number; }>; type IdEventItem = EventItem & Readonly<{ id: string; }>; type SplitOptionsRelative = { percentage: number; }; type SplitOptionsAbsolute = { start: number; }; type SplitOptions = (SplitOptionsRelative | SplitOptionsAbsolute); type IndexedEventItem = Readonly<{ event: EventItem; index: number; }>; type EventInterval = Readonly<{ a: EventItem; b: EventItem; /** * Interval between start points (B - A) */ startInterval: number; /** * Interval between end points (B - A) */ endInterval: number; /** * Interval between end of `a` and start of `b` (B.start - A.end) * Note, this might be negative if a and b overlap */ betweenInterval: number; indexA: number; indexB: number; }>; type DefragmentOptions = Readonly<{ gap: number; startAt: number; }>; //#endregion //#region ../packages/collections/src/events/events-fns.d.ts /** * Sorts by start, such that 'start' values are ascending. * * Returns: * 0 if A and B are have same start & end. * positive if B is before A. * negative if B is after A. * * If A and B have the same start point, they are secondarily sorted based on end time, with earlier end time considered "before" later end time. * * Use {@link CompareByStartOnly} to ignore end time and consider events equal if they share a `start`. * @param a * @param b */ declare const CompareByStart: Comparer<EventItem>; declare const CompareByStartOnly: Comparer<EventItem>; /** * Sorts by end, such that 'end' values are ascending. * * Returns: * 0 if A and B are have same start & end. * Returns positive if B is before A. * Returns negative if B is after A. * * If A and B share the same end, shorter items will come first (ie. those with higher start) * @param a * @param b */ declare const CompareByEnd: Comparer<EventItem>; declare const CompareByEndOnly: Comparer<EventItem>; /** * Returns a new array of events ordered by their start time (ascending) * @param events * @returns Events ordered by start time */ declare function sortByStart(events: EventItem[]): EventItem[]; /** * Returns a new array of events ordered by their end time (ascending) * @param events * @returns Events ordered by end time */ declare function sortByEnd(events: EventItem[]): EventItem[]; /** * Yields every item in `sortedEvents` that has the specified `start` value * * Return item is a wrapped object consisting of the event as well as its index. * ```js * const events = [ { start: 1, end: 2}, { start: 5, end: 10 }, { start: 10, end: 12 }]; * const matched = [...itemsWithStart(events, 5)]; * // matched is [{ event: { start: 5, end: 10 }, index: 1 }] * ``` * @param sortedEvents Sorted events * @param start Start position */ declare function itemsWithStart(sortedEvents: EventItem[], start: number): Generator<IndexedEventItem>; /** * Yields every item in `eventsByEnd` that has the specified `end` value. * Return item is a wrapped object consisting of the event as well as its index. * * The function expects that the input array has been sorted using {@link sortByEnd}, and therefore * sorted by ascending end value. * * ```js * const events = [ { start: 1, end: 2}, { start: 5, end: 10 }, { start: 10, end: 12 }]; * const matched = [...itemsWithEnd(events, 10)]; * // matched is [{ event: { start: 5, end: 10 }, index: 1 }] * ``` * @param eventsByEnd Events sorted with {@link sortByEnd} * @param end End position */ declare function itemsWithEnd(eventsByEnd: EventItem[], end: number): Generator<IndexedEventItem>; /** * Converts a collection of `IndexedEventItem` back into an array of `EventItem`, placing items at their original index. * * ```js * // Get all items that start at position 5 * const itemsAtPosition = [...itemsWithStart(sortedEvents, 5)]; * * // Make this into an array: * const items = arrayFromItems(itemsAtPosition); * ``` * * By default, the `index` field is used to construct the array. If `ignoreIndexes` is set to _true_, * the the returned array is constructed in the order of the input items, ignoring the `index` field. This can be useful if you just want to extract the events from a generator without caring about their original position. * @param items * @returns EventItems */ declare function arrayFromItems(items: Iterable<IndexedEventItem>, ignoreIndexes?: boolean): EventItem[]; /** * Yields all events that overlap with `point`. * By default event end is considered exclusive, meaning that if `point == event.end`, it is not considered overlapping. * If `endInclusive` is true, event end is considered inclusive, and the aforementioned would be considered ovlerapping. * * By default start is inclusive. * * @param sortedEvents * @param point * @param endInclusive Whether event end is considered inclusive for determining overlap (default:false) * @param startInclusive Whether event start is considered inclusive for determining overlap (default:true) */ declare function overlapping<T extends EventItem>(sortedEvents: T[], point: number, endInclusive?: boolean, startInclusive?: boolean): Generator<IndexedEventItem>; /** * Inserts space within `sortedEvents`. It does this by shifting events forward. * * If `start` overlaps with existing item(s), `overlappingPolicy` is used: * - 'ignore': Event duration is not changed * - 'stretch': Events that overlap are stretched by `length`. * * When considering overlap, both end is exclusive and start are considered exclusive. * * Eg, if we have the event `{ start: 5, end: 10 }`. * - insertSpace(data, 5, 1, `ignore`); // Would not be considered overlapping, but event would be shifted to { start: 6, end: 11 } * - insertSpace(data, 10, 1, `ignore`); // Would not be considered overlapping, event would remain { start: 5, end: 10 } * - insertSpace(data, 5, 1, `stretch`); // Would be considered overlapping, event shifted to { start: 6, end: 11 } * - insertSpace(data, 6, 1, `stretch`); // Would be considered overlapping, event would be stretched to { start: 5, end: 11 } * @param sortedEvents * @param start * @param length * @param overlappingPolicy */ declare function insertSpace<T extends EventItem>(sortedEvents: T[], start: number, length: number, overlappingPolicy: `ignore` | `stretch`): T[]; /** * Punches a hole in `sortedEvents` which overlap `hole`. * It does this by splitting/trimming events, or removing an event entirely it is fully covered by the hole. * * This will never shift events in time. * @param sortedEvents * @param hole */ declare function holepunch<T extends EventItem>(sortedEvents: T[], hole: EventItem): T[]; /** * Returns _true_ if `item` has zero duration (start and end are the same), _false_ otherwise. * ```js * isEmpty({ start: 1, end: 1 }); // true * isEmpty({ start: 1, end: 2 }); // false * ``` * @param item * @returns _true_ if `item` is empty. */ declare function isEmpty$2(item: EventItem): boolean; /** * Creates an `EventItem` from an `EventItemAsDuration` by calculating the end as start + duration. * ```js * fromDuration({ start: 1, duration: 2 }); // { start: 1, end: 3 } * ``` * * Copies additional properties to the return result. * @param item * @returns EventItem */ declare function fromDuration(item: EventItemAsDuration): EventItem; /** * Creats an `EventItemAsDuration` from an `EventItem` by calculating the duration as end - start. * ```js * toDuration({ start: 1, end: 3 }); // { start: 1, duration: 2 } * ``` * * Copies additional properties to the return result. * @param item * @returns EventItemAsDuration */ declare function toDuration(item: EventItem): EventItemAsDuration; /** * Returns the intervals between pairs of events. * * If `sortedEvents` has less than two events, yields nothing * @param sortedEvents */ declare function intervals(sortedEvents: EventItem[]): Generator<EventInterval>; declare function isValid(item: unknown): Result<EventItem, string>; declare function isEventItem(item: unknown): item is EventItem; /** * Removes `toRemove` from `sortedEvents`. * * Consider {@link holepunch} if you want to create an empty hole in the events and maintain overall length of event series. * * After removing: * - 'nothing': Gap is left, other items not affected * - 'shuffle-following': Events after 'toRemove' are shifted back by duration of `toRemove`, maintaining their spacing after that * - 'shuffle-leading': Events before 'toRemove' are shifted forward by duration of `toRemove`, maintaining their spacing before that * - 'slice-following': Events after 'toRemove' are shifted back to start at `toRemoved.start`, maintaining their spacing after that * - 'slice-leading': Events before 'toRemove' are shifted forward to end at `toRemoved.end`, maintaining their spacing before that * @param sortedEvents * @param toRemove */ declare function remove$2(sortedEvents: EventItem[], toRemove: EventItem, andThen: `nothing` | `shuffle-following` | `shuffle-leading` | `slice-following` | `slice-leading`): EventItem[]; /** * Splits `event` into two events by either a percentange of duration or by a specific start position. * * If `options` has a `percentage` field, the split point is calculated as `event.start + (event.end - event.start) * percentage`. * If `options` has a `start` field, the split point is simply that value. * * ```js * splitEvent({ start: 0, end: 10 }, { percentage: 0.5 }); // [{ start: 0, end: 5 }, { start: 5, end: 10 }] * splitEvent({ start: 0, end: 10 }, { start: 3 }); // [{ start: 0, end: 3 }, { start: 3, end: 10 }] * ``` * * Any other properties on `event` are copied to split events. * @param event Input event * @param options How to split * @returns Split event */ declare function splitEvent(event: EventItem, options: SplitOptions): [a: EventItem, b: EventItem]; /** * Applies `fn` to both `start` and `end` fields, returning a new event. * * Existing data on `event` is maintained. * * ```js * applyToPosition( { start:1.2, end:2.4 }, v => Math.round(v)); // { start:1, end:2 } * applyToPosition( { start:1, end:2 }, v => v*2); // { start:2, end:4 } * ``` * * Use {@link translate} if you just want to add an amount to start and end, instead of applying a custom function. * @param event Input event * @param fn Function to run over start and end * @returns New event with `fn` applied to start and end */ declare function applyToPositions(event: EventItem, fn: (v: number) => number): EventItem; /** * Translates an event by adding `amount` to both `start` and `end`, returning a new event. * ```js * translate( { start:1, end:2 }, 3); // { start:4, end:5 } * translate( { start:1, end:2 }, -1); // { start:0, end:1 } * ``` * * Existing data on `event` is maintained. * * Use {@link applyToPositions} if you want to apply a custom function to the start and end, instead of just adding an amount. * @param event * @param amount * @returns New EventItem */ declare function translate<T extends EventItem>(event: T, amount: number): T; /** * Returns how `b` overlaps with `a`. * * Returns: * - `none` if `b` does not overlap with `a` * - `equal` if `b` has the same start and end as `a` * - `full` if `b` is fully contained within `a` and `a` does not share a start/end * - `full-border` if `b` is fully contained within `a` and `a` shares a start/end * - `partial` if `b` overlaps with `a` but is not fully contained within it * * ```js * compareRange({ start:2, end:4 }, { start:0, end:1 }); // 'none' * compareRange({ start:2, end:4 }, { start: 2, end:4 }); // 'equal' * compareRange({ start:2, end:4 }, { start: 3, end: 3 }); // 'full' * compareRange({ start:2, end:4 }, { start: 3, end: 4 }); // 'full-border' * compareRange({ start:2, end:4 }, { start: 1, end: 3 }); // 'partial' * ``` * @param a * @param b */ declare function compareRange<T extends EventItem>(a: T, b: T): `none` | `partial` | `full` | `full-border` | `equal`; /** * Lays out events end-to-end, removing gaps between them and having the first start at 0. * Duration of events is maintained. * @param sortedEvents */ declare function defragment(sortedEvents: EventItem[], options?: Partial<DefragmentOptions>): EventItem[]; declare function createFromStarts(starts: number[], duration: number, idPrefix?: string): IdEventItem[]; /** * Gets the range of `events`: the smallest 'start' and the largest 'end'. * * If there are gaps between events, this is still included in the range. Use {@link sumDuration} * to add up the duration of all events as if they are stacked end-to-end. * @param events * @returns Range of events */ declare function computeRange(events: EventItem[]): { start: number; end: number; }; /** * Returns the total duration of all events. Doesn't take into account * the spacing between events, just sums the duration of each one. * * Use {@link computeRange} if you want to calculate the min and max starting points. * @param events * @returns Duration */ declare function sumDuration(events: EventItem[]): number; //#endregion //#region ../packages/collections/src/types.d.ts /** * Key-value pairs in an array * @see {@link ObjectKeys} */ type ArrayKeys<K, V> = readonly (readonly [key: K, value: V])[]; /** * Key-value pairs in object form * @see {@link ArrayKeys} */ type ObjectKeys<K, V> = readonly { readonly key: K; readonly value: V; }[]; declare function isObjectKeys<K, V>(kvs: EitherKey<K, V>): kvs is ObjectKeys<K, V>; /** * Type that represents key-values in object or array form */ type EitherKey<K, V> = ArrayKeys<K, V> | ObjectKeys<K, V>; /** * A table value or _undefined_ */ type TableValue<V> = V | undefined; /** * A row of table values */ type TableRow<V> = TableValue<V>[]; //#endregion //#region ../packages/collections/src/map/imap-base.d.ts interface IMapBase<K, V> { /** * Gets an item by key * @example * ```js * const item = map.get(`hello`); * ``` * @param key */ get(key: K): V | undefined; /** * Returns _true_ if map contains key * @example * ```js * if (map.has(`hello`)) ... * ``` * @param key */ has(key: K): boolean; /** * Returns _true_ if map is empty */ isEmpty(): boolean; /** * Iterates over entries (consisting of [key,value]) * @example * ```js * for (const [key, value] of map.entries()) { * // Use key, value... * } * ``` */ entries(): IterableIterator<readonly [K, V]>; values(): IterableIterator<V>; } //#endregion //#region ../packages/collections/src/map/map.d.ts /** * An immutable map. Rather than changing the map, functions like `add` and `delete` * return a new map reference which must be captured. * * Immutable data is useful because as it gets passed around your code, it never * changes from underneath you. You have what you have. * * @example * ```js * let m = map(); // Create * let m2 = m.set(`hello`, `samantha`); * // m is still empty, only m2 contains a value. * ``` * * @typeParam K - Type of map keys. Typically `string` * @typeParam V - Type of stored values */ interface IMapImmutable<K, V> extends IMapBase<K, V> { /** * Adds one or more items, returning the changed map. * * Can add items in the form of `[key,value]` or `{key, value}`. * @example These all produce the same result * ```js * map.set(`hello`, `samantha`); * map.add([`hello`, `samantha`]); * map.add({key: `hello`, value: `samantha`}) * ``` * @param itemsToAdd */ add(...itemsToAdd: EitherKey<K, V>): IMapImmutable<K, V>; /** * Deletes an item by key, returning the changed map * @param key */ delete(key: K): IMapImmutable<K, V>; /** * Returns an empty map */ clear(): IMapImmutable<K, V>; /** * Sets `key` to be `value`, overwriting anything existing. * Returns a new map with added key. * @param key * @param value */ set(key: K, value: V): IMapImmutable<K, V>; } /** * Returns an {@link IMapImmutable}. * Use {@link Maps.mutable} as a mutable alternatve. * * @example Basic usage * ```js * // Creating * let m = map(); * // Add * m = m.set("name", "sally"); * // Recall * m.get("name"); * ``` * * @example Enumerating * ```js * for (const [key, value] of map.entries()) { * console.log(`${key} = ${value}`); * } * ``` * * @example Overview * ```js * // Create * let m = map(); * // Add as array or key & value pair * m = m.add(["name" , "sally"]); * m = m.add({ key: "name", value: "sally" }); * // Add using the more typical set * m = m.set("name", "sally"); * m.get("name"); // "sally"; * m.has("age"); // false * m.has("name"); // true * m.isEmpty; // false * m = m.delete("name"); * m.entries(); // Iterator of key value pairs * ``` * * Since it is immutable, `add()`, `delete()` and `clear()` return a new version with change. * * @param dataOrMap Optional initial data in the form of an array of `{ key: value }` or `[ key, value ]` */ declare const immutable$3: <K, V>(dataOrMap?: ReadonlyMap<K, V> | EitherKey<K, V>) => IMapImmutable<K, V>; //#endregion //#region ../packages/collections/src/table.d.ts /** * Stores values in a table of rows (vertical) and columns (horizontal) */ declare class Table<V> { #private; rows: TableRow<V>[]; rowLabels: string[]; colLabels: string[]; /** * Keep track of widest row */ columnMaxLength: number; /** * Gets the label for a given column index, * returning _undefined_ if not found. * * Case-sensitive * @param label Label to seek * @returns Index of column, or _undefined_ if not found */ getColumnLabelIndex(label: string): number | undefined; /** * Gets the label for a given row index, * returning _undefined_ if not found. * * Case-sensitive * @param label Label to seek * @returns Index of row, or _undefined_ if not found */ getRowLabelIndex(label: string): number | undefined; /** * Dumps the values of the table to the console */ print(): void; /** * Return a copy of table as nested array * * ```js * const t = new Table(); * // add stuff * // ... * const m = t.asArray(); * for (const row of m) { * for (const colValue of row) { * // iterate over all column values for this row * } * } * ``` * * Alternative: get value at row Y and column X * ```js * const value = m[y][x]; * ``` * @returns */ asArray(): (V | undefined)[][]; /** * Return the number of rows */ get rowCount(): number; /** * Return the maximum number of columns in any row */ get columnCount(): number; /** * Iterates over the table row-wise, in object format. * @see {@link rowsWithLabelsArray} to get rows in array format */ rowsWithLabelsObject(): Generator<object | undefined, void, unknown>; /** * Iterates over each row, including the labels if available * @see {@link rowsWithLabelsObject} to get rows in object format */ rowsWithLabelsArray(): Generator<[label: string | undefined, value: V | undefined][] | undefined, void, unknown>; /** * Assign labels to columns * @param labels */ labelColumns(...labels: string[]): void; /** * Assign label to a specific column * First column has an index of 0 * @param columnIndex * @param label */ labelColumn(columnIndex: number, label: string): void; /** * Label rows * @param labels Labels */ labelRows(...labels: string[]): void; /** * Assign label to a specific row * First row has an index of 0 * @param rowIndex * @param label */ labelRow(rowIndex: number, label: string): void; /** * Adds a new row * @param data Columns */ appendRow(...data: TableValue<V>[]): TableRow<V>; /** * Gets a row along with labels, as an array * @param rowIndex * @returns */ getRowWithLabelsArray(rowIndex: number): [label: string | undefined, value: V | undefined][] | undefined; /** * Return a row of objects. Keys use the column labels. * * ```js * const row = table.getRowWithLabelsObject(10); * // eg: * // [{ colour: red, size: 10}, { colour: blue, size: 20 }] * ``` * @param rowIndex * @returns */ getRowWithLabelsObject(rowIndex: number): object | undefined; /** * Gets a copy of values at given row, specified by index or label * @param row * @returns Returns row or throws an error if label or index not found */ row(row: number | string): readonly (V | undefined)[] | undefined; /** * Set the value of row,columm. * Row is created if it doesn't exist, with the other column values being _undefined_ * @param row Index or label * @param column Column * @param value Value to set at row,column */ set(row: number | string, column: number | string, value: V | undefined): void; /** * Gets the value at a specified row and column. * Throws an error if coordinates are out of range or missing. * @param row Row index or label * @param column Column index or label * @returns */ get(row: number | string, column: number | string): TableValue<V>; /** * Set all the columns of a row to a specified value. * * By default, sets the number of columns corresponding to * the table's maximum column length. To set an arbitrary * length of the row, use `length` * @param row Index or label of row * @param length How wide the row is. If unset, uses the current maximum width of rows. * @param value Value to set */ setRow(row: number | string, value: V | undefined, length?: number): TableRow<V>; } declare namespace directed_graph_d_exports { export { ConnectOptions$1 as ConnectOptions, DirectedGraph, DistanceCompute, Edge$1 as Edge, Vertex$1 as Vertex, adjacentVertices$1 as adjacentVertices, areAdjacent, bfs, clone, connect$1 as connect, connectTo$1 as connectTo, connectWithEdges$1 as connectWithEdges, createVertex$1 as createVertex, dfs, disconnect, distance, distanceDefault, dumpGraph$1 as dumpGraph, edges, get, getCycles, getOrCreate$1 as getOrCreate, getOrFail, graph$1 as graph, graphFromVertices, hasKey, hasNoOuts, hasOnlyOuts, hasOut, isAcyclic, pathDijkstra, toAdjacencyMatrix$1 as toAdjacencyMatrix, topologicalSort, transitiveReduction, updateGraphVertex$1 as updateGraphVertex, vertexHasOut, vertices }; } type DistanceCompute = (graph: DirectedGraph, edge: Edge$1) => number; /** * Vertex. These are the _nodes_ of the graph. Immutable. * * They keep track of all of their outgoing edges, and * a unique id. * * Ids are used for accessing/updating vertices as well as in the * {@link Edge} type. They must be unique. */ type Vertex$1 = Readonly<{ out: readonly Edge$1[]; id: string; }>; /** * Edge. Immutable. * * Only encodes the destination vertex. The from * is known since edges are stored on the from vertex. */ type Edge$1 = Readonly<{ /** * Vertex id edge connects to (ie. destination) */ id: string; /** * Optional weight of edge */ weight?: number; }>; /** * Create a vertex with given id * @param id * @returns */ declare const createVertex$1: (id: string) => Vertex$1; /** * Options for connecting vertices */ type ConnectOptions$1 = Readonly<{ /** * From, or source of connection */ from: string; /** * To, or destination of connection. Can be multiple vertices for quick use */ to: string | string[]; /** * If true, edges in opposite direction are made as well */ bidi?: boolean; /** * Weight for this connection (optional) */ weight?: number; }>; /** * Directed graph. Immutable. * * Consists of {@link Vertex|vertices}, which all have zero or more outgoing {@link Edge|Edges}. */ type DirectedGraph = Readonly<{ vertices: IMapImmutable<string, Vertex$1>; }>; /** * Returns _true_ if graph contains `key`. * * ```js * // Same as * g.vertices.has(key) * ``` * @param graph * @param key * @returns */ declare function hasKey(graph: DirectedGraph, key: string): boolean; /** * Returns {@link Vertex} under `key`, or _undefined_ * if not found. * * ```js * // Same as * g.vertices.get(key) * ``` * @param graph * @param key * @returns */ declare function get(graph: DirectedGraph, key: string): Vertex$1 | undefined; /** * Returns the graph connections as an adjacency matrix * @param graph * @returns */ declare function toAdjacencyMatrix$1(graph: DirectedGraph): Table<boolean>; /** * Return a string representation of the graph for debug inspection * @param graph * @returns */ declare const dumpGraph$1: (graph: DirectedGraph | Iterable<Vertex$1>) => string; /** * Returns the weight of an edge, or 1 if undefined. * @param graph * @param edge * @returns */ declare const distance: (graph: DirectedGraph, edge: Edge$1) => number; /** * Iterate over all the edges in the graph * @param graph */ declare function edges(graph: DirectedGraph): Generator<Readonly<{ /** * Vertex id edge connects to (ie. destination) */ id: string; /** * Optional weight of edge */ weight?: number; }>, void, unknown>; /** * Iterate over all the vertices of the graph * @param graph */ declare function vertices(graph: DirectedGraph): Generator<Readonly<{ out: readonly Edge$1[]; id: string; }>, void, unknown>; /** * Iterate over all the vertices connected to `context` vertex * @param graph Graph * @param context id or Vertex. * @returns */ declare function adjacentVertices$1(graph: DirectedGraph, context: Vertex$1 | string | undefined): Generator<Readonly<{ out: readonly Edge$1[]; id: string; }>, void, unknown>; /** * Returns _true_ if `vertex` has an outgoing connection to * the supplied id or vertex. * * If `vertex` is undefined, _false_ is returned. * @param vertex From vertex * @param outIdOrVertex To vertex * @returns */ declare const vertexHasOut: (vertex: Vertex$1, outIdOrVertex: string | Vertex$1) => boolean; /** * Returns _true_ if `vertex` has no outgoing connections * @param graph * @param vertex * @returns */ declare const hasNoOuts: (graph: DirectedGraph, vertex: string | Vertex$1) => boolean; /** * Returns _true_ if `vertex` only has the given list of vertices. * Returns _false_ early if the length of the list does not match up with `vertex.out` * @param graph * @param vertex * @param outIdOrVertex * @returns */ declare const hasOnlyOuts: (graph: DirectedGraph, vertex: string | Vertex$1, ...outIdOrVertex: (string | Vertex$1)[]) => boolean; /** * Returns _true_ if `vertex` has an outgoing connection to the given vertex. * @param graph * @param vertex * @param outIdOrVertex * @returns */ declare const hasOut: (graph: DirectedGraph, vertex: string | Vertex$1, outIdOrVertex: string | Vertex$1) => boolean; /** * Gets a vertex by id, creating it if it does not exist. * @param graph * @param id * @returns */ declare const getOrCreate$1: (graph: DirectedGraph, id: string) => Readonly<{ graph: DirectedGraph; vertex: Vertex$1; }>; /** * Gets a vertex by id, throwing an error if it does not exist * @param graph * @param id * @returns */ declare const getOrFail: (graph: DirectedGraph, id: string) => Vertex$1; /** * Updates a vertex by returning a mutated graph * @param graph Graph * @param vertex Newly changed vertex * @returns */ declare const updateGraphVertex$1: (graph: DirectedGraph, vertex: Vertex$1) => DirectedGraph; /** * Default distance computer. Uses `weight` property of edge, or `1` if not found. * @param graph * @param edge * @returns */ declare const distanceDefault: (graph: DirectedGraph, edge: Edge$1) => number; /** * Returns a mutation of `graph`, with a given edge removed. * * If edge was not there, original graph is returned. * @param graph * @param from * @param to * @returns */ declare function disconnect(graph: DirectedGraph, from: string | Vertex$1, to: string | Vertex$1): DirectedGraph; /** * Make a connection between two vertices with a given weight. * It returns the new graph as wll as the created edge. * @param graph * @param from * @param to * @param weight * @returns */ declare function connectTo$1(graph: DirectedGraph, from: string, to: string, weight?: number): { graph: DirectedGraph; edge: Edge$1; }; /** * Connect from -> to. Same as {@link connectWithEdges}, but this version just returns the graph. * * By default unidirectional, meaning a connection is made only from->to. Use `bidi` option to set a bidirection connection, adding also to->from. * * Returns a result of `{ graph, edges }`, where `graph` is the new {@link DirectedGraph} and `edges` * is an array of {@link Edge Edges}. One for unidirectional, or two for bidirectional. * @param graph * @param options * @returns */ declare function connect$1(graph: DirectedGraph, options: ConnectOptions$1): DirectedGraph; /** * Connect from -> to. Same as {@link connect} except you get back the edges as well. * * By default unidirectional, meaning a connection is made only from->to. Use `bidi` option to set a bidirection connection, adding also to->from. * * Returns a result of `{ graph, edges }`, where `graph` is the new {@link DirectedGraph} and `edges` * is an array of {@link Edge Edges}. One for unidirectional, or two for bidirectional. * @param graph * @param options * @returns */ declare function connectWithEdges$1(graph: DirectedGraph, options: ConnectOptions$1): { graph: DirectedGraph; edges: Edge$1[]; }; /** * Returns _true_ if a->b or b->a * @param graph * @param a * @param b * @returns */ declare function areAdjacent(graph: DirectedGraph, a: Vertex$1, b: Vertex$1): true | undefined; /** * Iterates over vertices from a starting vertex in an bread-first-search * @param graph * @param startIdOrVertex * @param targetIdOrVertex * @returns */ declare function bfs(graph: DirectedGraph, startIdOrVertex: string | Vertex$1, targetIdOrVertex?: string | Vertex$1): Generator<Readonly<{ out: readonly Edge$1[]; id: string; }>, void, unknown>; /** * Iterates over vertices from a starting vertex in an depth-first-search * @param graph * @param startIdOrVertex */ declare function dfs(graph: DirectedGraph, startIdOrVertex: string | Vertex$1): Generator<Readonly<{ out: readonly Edge$1[]; id: string; }>, void, unknown>; /** * Compute shortest distance from the source vertex to the rest of the graph. * @param graph * @param sourceOrId * @returns */ declare const pathDijkstra: (graph: DirectedGraph, sourceOrId: Vertex$1 | string) => { distances: Map<string, number>; previous: Map<string, Readonly<{ out: readonly Edge$1[]; id: string; }> | null>; pathTo: (id: string) => Edge$1[]; }; /** * Clones the graph. Uses shallow clone, because it's all immutable * @param graph * @returns */ declare const clone: (graph: DirectedGraph) => DirectedGraph; /** * Create a graph * ```js * let g = graph(); * ``` * * Can optionally provide initial connections: * ```js * let g = graph( * { from: `a`, to: `b` }, * { from: `b`, to: `c` } * ) * ``` * @param initialConnections * @returns */ declare const graph$1: (...initialConnections: ConnectOptions$1[]) => DirectedGraph; /** * Returns _true_ if the graph contains is acyclic - that is, it has no loops * @param graph */ declare function isAcyclic(graph: DirectedGraph): boolean; /** * Topological sort using Kahn's algorithm. * Returns a new graph that is sorted * @param graph */ declare function topologicalSort(graph: DirectedGraph): DirectedGraph; /** * Create a graph from an iterable of vertices * @param vertices * @returns */ declare function graphFromVertices(vertices: Iterable<Vertex$1>): DirectedGraph; /** * Get all the cycles ('strongly-connected-components') within the graph * [Read more](https://en.wikipedia.org/wiki/Strongly_connected_component) * @param graph * @returns */ declare function getCycles(graph: DirectedGraph): Vertex$1[][]; /** * Returns a new graph which is transitively reduced. * That is, redundant edges are removed * @param graph * @returns */ declare function transitiveReduction(graph: DirectedGraph): Readonly<{ vertices: IMapImmutable<string, Vertex$1>; }>; declare namespace undirected_graph_d_exports { export { ConnectOptions, Edge, Graph, Vertex, adjacentVertices, connect, connectTo, connectWithEdges, createVertex, dumpGraph, edgesForVertex, getConnection, getOrCreate, graph, hasConnection, toAdjacencyMatrix, updateGraphVertex }; } type Vertex = Readonly<{ id: string; }>; type Edge = Readonly<{ a: string; b: string; weight?: number; }>; type Graph = Readonly<{ edges: readonly Edge[]; vertices: IMapImmutable<string, Vertex>; }>; type ConnectOptions = Readonly<{ a: string; b: string | string[]; weight?: number; }>; declare const createVertex: (id: string) => Vertex; declare const updateGraphVertex: (graph: Graph, vertex: Vertex) => Graph; declare const getOrCreate: (graph: Graph, id: string) => Readonly<{ graph: Graph; vertex: Vertex; }>; /** * Returns _true/false_ if there is a connection between `a` and `b` in `graph`. * Use {@link getConnection} if you want to the edge. * @param graph Graph to search * @param a * @param b * @returns _true_ if edge exists */ declare const hasConnection: (graph: Graph, a: string | Vertex, b: string | Vertex) => boolean; /** * Gets the connection, if it exists between `a` and `b` in `graph`. * If it doesn't exist, _undefined_ is returned. * Use {@link hasConnection} for a simple true/false if edge exists. * @param graph Graph * @param a * @param b * @returns */ declare const getConnection: (graph: Graph, a: string | Vertex, b: string | Vertex) => Edge | undefined; /** * Connects A with B, returning the changed graph and created edge. * If the connection already exists, the original graph & edge is returned. * @param graph * @param a * @param b * @param weight * @returns */ declare function connectTo(graph: Graph, a: string, b: string, weight?: number): { graph: Graph; edge: Edge; }; /** * Makes a connection between `options.a` and one or more nodes in `options.b`. * Same as {@link connectWithEdges} but only the {@link Graph} is returned. * * ```js * let g = graph(); // Create an empty graph * // Make a connection between `red` and `orange` * g = connect(g, { a: `red`, b: `orange` }); * * // Make a connection between `red` and `orange as well as `red` and `yellow`. * g = connect(g, { a: `red`, b: [`orange`, `yellow`] }) * ``` * @param graph Initial graph * @param options Options */ declare function connect(graph: Graph, options: ConnectOptions): Graph; /** * Makes a connection between `options.a` and one or more nodes in `options.b`. * Same as {@link connect} but graph and edges are returned. * * ```js * let g = graph(); // Create an empty graph * * // Make a connection between `red` and `orange` * result = connectWithEdges(g, { a: `red`, b: `orange` }); * * // Make a connection between `red` and `orange as well as `red` and `yellow`. * result = connectWithEdges(g, { a: `red`, b: [`orange`, `yellow`] }) * ``` * @param graph Initial graph * @param options Options */ declare function connectWithEdges(graph: Graph, options: ConnectOptions): { graph: Graph; edges: Edge[]; }; declare const graph: (...initialConnections: ConnectOptions[]) => Graph; declare function toAdjacencyMatrix(graph: Graph): Table<boolean>; /** * Return a string representation of the graph for debug inspection * @param graph * @returns */ declare const dumpGraph: (graph: Graph) => string; /** * Iterate over all the vertices connectd to `context` vertex * * If `context` is _undefined_, returns nothing * @param graph Graph * @param context id or Vertex * @returns */ declare function adjacentVertices(graph: Graph, context: Vertex | string | undefined): Generator<Readonly<{ id: string; }>, void, unknown>; /** * Get all the edges for a vertex. * * ```js * // Iterate all edges for vertex with id '0' * for (const edge of edgesForVertex(graph, '0')) { * } * ``` * * If the vertex has no edges, no values are returned. If the vertex was not found in the graph, an error is thrown. * @throws Throws an error if `context` was not found, if it's _undefined_ or `graph` is invalid. * @param graph * @param context * @returns */ declare function edgesForVertex(graph: Graph, context: Vertex | string | undefined): Generator<Readonly<{ a: string; b: string; weight?: number; }>, void, unknown>; declare namespace index_d_exports$6 { export { directed_graph_d_exports as Directed, undirected_graph_d_exports as Undirected }; } //#endregion //#region ../packages/collections/src/map/expiring-map.d.ts /** * Expiring map options */ type Opts = { /** * Capacity limit */ readonly capacity?: number; /** * Policy for evicting items if capacity is reached */ readonly evictPolicy?: `none` | `oldestGet` | `oldestSet`; /** * Automatic deletion policy. * none: no automatic deletion (default) * get/set: interval based on last get/set * either: if either interval has elapsed */ readonly autoDeletePolicy?: `none` | `get` | `set` | `either`; /** * Automatic deletion interval */ readonly autoDeleteElapsedMs?: number; }; /** * Event from the ExpiringMap */ type ExpiringMapEvent<K, V> = { readonly key: K; readonly value: V; }; type ExpiringMapEvents<K, V> = { /** * Fires when an item is removed due to eviction * or automatic expiry */ readonly expired: ExpiringMapEvent<K, V>; /** * Fires when a item with a new key is added */ readonly newKey: ExpiringMapEvent<K, V>; /** * Fires when an item is manually removed, * removed due to eviction or automatic expiry */ readonly removed: ExpiringMapEvent<K, V>; }; /** * Create a ExpiringMap instance * @param options Options when creating map * @returns */ declare const create$2: <K, V>(options?: Opts) => ExpiringMap<K, V>; /*** * A map that can have a capacity limit. The elapsed time for each get/set * operation is maintained allowing for items to be automatically removed. * `has()` does not affect the last access time. * * By default, it uses the `none` eviction policy, meaning that when full * an error will be thrown if attempting to add new keys. * * Eviction policies: * `oldestGet` removes the item that hasn't been accessed the longest, * `oldestSet` removes the item that hasn't been updated the longest. * * ```js * const map = new ExpiringMap(); * map.set(`fruit`, `apple`); * * // Remove all entries that were set more than 100ms ago * map.deleteWithElapsed(100, `set`); * // Remove all entries that were last accessed more than 100ms ago * map.deleteWithElapsed(100, `get`); * // Returns the elapsed time since `fruit` was last accessed * map.elapsedGet(`fruit`); * // Returns the elapsed time since `fruit` was last set * map.elapsedSet(`fruit`); * ``` * * Last set/get time for a key can be manually reset using {@link touch}. * * * Events: * * 'expired': when an item is automatically removed. * * 'removed': when an item is manually or automatically removed due to expiry. Note: does not fire when .clear() is called * * 'newKey': when a new key is added * * ```js * map.addEventListener(`expired`, evt => { * const { key, value } = evt; * }); * ``` * The map can automatically remove items based on elapsed intervals. * * @example * Automatically delete items that haven't been accessed for one second * ```js * const map = new ExpiringMap({ * autoDeleteElapsed: 1000, * autoDeletePolicy: `get` * }); * ``` * * @example * Automatically delete the oldest item if we reach a capacity limit * ```js * const map = new ExpiringMap({ * capacity: 5, * evictPolicy: `oldestSet` * }); * ``` * @typeParam K - Type of keys * @typeParam V - Type of values */ declare class ExpiringMap<K, V> extends SimpleEventEmitter<ExpiringMapEvents<K, V>> { #private; private capacity; private store; private evictPolicy; private autoDeleteElapsedMs; private autoDeletePolicy; private autoDeleteTimer; private disposed; constructor(opts?: Opts); dispose(): void; /** * Returns the number of keys being stored. */ get keyLength(): number; entries(): IterableIterator<[k: K, v: V]>; values(): IterableIterator<V>; keys(): IterableIterator<K>; /** * Returns the elapsed time since `key` * was set. Returns _undefined_ if `key` * does not exist */ elapsedSet(key: K): number | undefined; /** * Returns the elapsed time since `key` * was accessed. Returns _undefined_ if `key` * does not exist */ elapsedGet(key: K): number | undefined; /** * Returns true if `key` is stored. * Does not affect the key's last access time. * @param key * @returns */ has(key: K): boolean; /** * Gets an item from the map by key, returning * undefined if not present * @param key Key * @returns Value, or undefined */ get(key: K): V | undefined; /** * Deletes the value under `key`, if present. * * Returns _true_ if something was removed. * @param key * @returns */ delete(key: K): boolean; /** * Clears the contents of the map. * Note: does not fire `removed` event */ clear(): void; /** * Updates the lastSet/lastGet time for a value * under `key`. If key was not found, nothing happens. * * Returns _false_ if key was not found * @param key * @returns */ touch(key: K): boolean; private findEvicteeKey; /** * Deletes all values where elapsed time has past * for get/set or either. * ```js * // Delete all keys (and associated values) not accessed for a minute * em.deleteWithElapsed({mins:1}, `get`); * // Delete things that were set 1s ago * em.deleteWithElapsed(1000, `set`); * ``` * * @param interval Interval * @param property Basis for deletion 'get','set' or 'either' * @returns Items removed */ deleteWithElapsed(interval: Interval, property: `get` | `set` | `either`): [k: K, v: V][]; /** * Sets the `key` to be `value`. * * If the key already exists, it is updated. * * If the map is full, according to its capacity, * another value is selected for removal. * @param key * @param value * @returns */ set(key: K, value: V): void; } //#endregion //#region ../packages/collections/src/map/imap-of.d.ts interface IMapOf<V> { /** * Iterates over all keys */ keys(): IterableIterator<string>; /** * Iterates over all values stored under `key` * @param key */ valuesFor(key: string): IterableIterator<V>; /** * Returns a copy of all values under key as an arry * @param key */ /** * Iterates over all values, regardless of key. * Same value may re-appear if it's stored under different keys. */ valuesFlat(): IterableIterator<V>; /** * Iterates over key-value pairs. * Unlike a normal map, the same key may appear several times. */ entriesFlat(): IterableIterator<readonly [key: string, value: V]>; entries(): IterableIterator<[key: string, value: V[]]>; /** * Iteates over all keys and the count of values therein */ keysAndCounts(): IterableIterator<readonly [string, number]>; /** * Returns _true_ if `value` is stored under `key`. * * @param key Key * @param value Value */ hasKeyValue(key: string, value: V, eq?: IsEqual<V>): boolean; /** * Returns _true_ if `key` has any values * @param key */ has(key: string): boolean; /** * Returns _true_ if the map is empty */ get isEmpty(): boolean; /** * Returns the number of values stored under `key`, or _0_ if `key` is not present. * @param key Key */ count(key: string): number; /** * Finds the first key where value is stored. * Note: value could be stored in multiple keys * @param value Value to seek * @returns Key, or undefined if value not found */ firstKeyByValue(value: V, eq?: IsEqual<V>): string | undefined; } //#endregion //#region ../packages/collections/src/map/imap-of-mutable.d.ts interface IMapOfMutable<V> extends IMapOf<V> { /** * Adds several `values` under the same `key`. Duplicate values are permitted, depending on implementation. * ```js * addKeyedValues('colours', 'red', 'green', 'blue') * ``` * @param key * @param values */ addKeyedValues(key: string, ...values: readonly V[]): void; /** * Adds a value, automatically extracting a key via the * `groupBy` function assigned in the constructor options. * @param values Adds several values */ addValue(...values: readonly V[]): void; /** * Clears the map */ clear(): void; /** * Returns the number of keys */ get lengthKeys(): number; /** * Deletes all values under `key` that match `value`. * @param key Key * @param value Value */ deleteKeyValue(key: string, value: V): boolean; /** * Delete all occurrences of `value`, regardless of * key it is stored under. * Returns _true_ if something was deleted. * @param value */ deleteByValue(value: V): boolean; /** * Deletes all values stored under `key`. Returns _true_ if key was found * @param key */ delete(key: string): boolean; } //#endregion //#region ../packages/collections/src/map/map-of-simple-base.d.ts declare class MapOfSimpleBase<V> { protected map: Map<string, readonly V[]>; protected readonly groupBy: (value: V) => string; protected valueEq: IsEqual<V>; /** * Constructor * * ```js * const m = new MapOfSimpleBase(); * m.valuesFor(`apple`); // Iterator over all values stored under key `apple` * ``` * @param groupBy Creates keys for values when using `addValue`. By default uses JSON.stringify * @param valueEq Compare values. By default uses JS logic for equality */ constructor(groupBy?: (value: V) => string, valueEq?: IsEqual<V>, initial?: Map<string, readonly V[]> | Array<[string, readonly V[]]>); /** * Returns the underlying map storage. Do not manipulate. */ get getRawMapUnsafe(): Map<string, readonly V[]>; /** * Returns _true_ if `key` exists * @param key * @returns */ has(key: string): boolean; /** * Returns _true_ if `value` exists under `key`. * @param key Key * @param value Value to seek under `key` * @returns _True_ if `value` exists under `key`. */ hasKeyValue(key: string, value: V): boolean; /** * Debug dump of contents */ debugString(): string; /** * Return number of values stored under `key`. * Returns 0 if `key` is not found. * @param key * @returns */ count(key: string): number; /** * Returns first key that contains `value` * @param value * @param eq * @returns */ firstKeyByValue(value: V, eq?: IsEqual<V>): string | undefined; /** * Iterate over all entries */ entriesFlat(): IterableIterator<[key: string, value: V]>; /** * Iterate over keys and array of values for that ke