import { Comparer, IsEqual } from "@ixfx/core"; import { Result } from "@ixfx/guards"; //#region src/tree/types.d.ts /** * A labelled single value or array of values */ type LabelledValue = LabelledSingleValue | LabelledValues; /** * A value that is labelled * @see {@link LabelledValues} */ type LabelledSingleValue = { label: string; value: TValue | undefined; }; /** * A label for any number of values * @see {@link LabelledValues} */ type LabelledValues = { label: string; values: TValue[]; }; /** * Array-backed tree node. * * Create using: * {@link Trees.Mutable.root}: Imperative building of a tree * {@link Trees.FromObject.create}: Create based on a snapshot of an object * * Use {@link Trees.isTreeNode} to check if an object is this type. * * Convert: * {@link Trees.Mutable.stripParentage}: Create a {@link Trees.SimplifiedNode}, with parentage removed. * {@link Trees.Mutable.wrap}: Create an object-oriented {@link Trees.WrappedNode} based on a node. */ type TreeNode = { /** * Parent node, or _undefined_ if a root */ parent: TreeNode | undefined; /** * Associated value */ value: TValue | undefined; /** * Children of this node */ childrenStore: ReadonlyArray>; }; /** * A simplified node has its parentage stripped. * * To create: * {@link Trees.Mutable.stripParentage}: Create based on a {@link Trees.TreeNode} instance * {@link Trees.FromObject.createSimplified}: Create based on an object */ type SimplifiedNode = { /** * Value of node, or _undefined_ if it has no value */ value: TValue | undefined; /** * Children nodes of this one */ childrenStore: ReadonlyArray>; }; /** * A node with an accompanying label */ type LabelledNode = TreeNode>; /** * Traversable Tree. * * Creatable from: * {@link Trees.FromObject.asDynamicTraversable}: Create based on dynamic reading of an object * {@link Trees.TraversableTree}: Create based on an {@link Trees.TreeNode}, a {@link Trees.TraversableTree} or an object (same as calling asDynamicTraversable). * Use {@link Trees.isTraversable} to check if an object is this type. */ type TraversableTree = { /** * Direct children of node */ children: () => IterableIterator>; /** * Direct parent of node */ getParent: () => TraversableTree | undefined; /** * Value of node */ getValue: () => TValue; /** * Object reference that acts as the identity of the node */ getIdentity: () => any; }; type TraverseObjectEntry = Readonly<{ name: string; sourceValue: any; leafValue: any; _kind: `entry`; }>; type TraverseObjectEntryWithAncestors = Readonly<{ name: string; sourceValue: any; leafValue: any; ancestors: string[]; _kind: `entry-ancestors`; }>; type TraverseObjectEntryStatic = Readonly<{ name: string; sourceValue: any; ancestors: string[]; _kind: `entry-static`; }>; /** * Options for parsing a path */ type TraverseObjectPathOpts = { /** * Separator for path, eg '.' */ readonly separator?: string; }; /** * Wraps a {@link TreeNode} for a more object-oriented means of access. * * Create: * {@link Trees.FromObject.createWrapped}: Create based on an object * {@link Trees.Mutable.wrap}: Create based on a {@link Trees.TreeNode} instance */ type WrappedNode = TraversableTree & { /** * Underlying Node */ wraps: TreeNode; /** * Gets value of node, if defined * @returns Value of Node */ getValue: () => T | undefined; /** * Remove node and its children from tree * @returns */ remove: () => void; /** * Adds a child node * @param child * @returns */ add: (child: WrappedNode | TreeNode) => WrappedNode; /** * Adds a new child node, with `value` as its value * @param value * @returns */ addValue: (value: T) => WrappedNode; /** * Returns _true_ if `child` is an immediate child of this node * @param child * @returns */ hasChild: (child: WrappedNode | TreeNode) => boolean; queryValue: (value: T) => IterableIterator>; /** * Yields all parents of `child` that have a given value. * Use 'findParentsValue' to find the first match only. * @param child * @param value * @param eq * @returns */ queryParentsValue: (child: TreeNode, value: T, eq?: IsEqual) => IterableIterator>; /** * Returns the first parent that has a given value. * @param child * @param value * @param eq * @returns */ findParentsValue: (child: TreeNode, value: T, eq: IsEqual) => WrappedNode | undefined; /** * Yields the node value of each parent of `child`. * _undefined_ values are not returned. * * Use 'queryParentsValue' to search for a particular value * @param child * @returns */ parentsValues: (child: TreeNode) => IterableIterator; /** * Returns _true_ if `child` is contained any any descendant * @param child * @returns */ hasAnyChild: (child: WrappedNode | TreeNode) => boolean; /** * Returns _true_ if `parent` is the immediate parent for this node * @param parent * @returns */ hasParent: (parent: WrappedNode | TreeNode) => boolean; /** * Returns _true_ if `parent` is the immediate or ancestor parent for this node * @param parent * @returns */ hasAnyParent: (parent: WrappedNode | TreeNode) => boolean; }; //#endregion //#region src/tree/compare.d.ts type DiffAnnotation = { /** * In the case of changes, this is old value */ a: TraversableTree; /** * In the case of changes, this is the new value */ b: TraversableTree; /** * If true, this node's value has been modified */ valueChanged: boolean; /** * If true, one of the child values has changed */ childChanged: boolean; /** * List of new children */ added: TraversableTree[]; /** * List of removed children */ removed: TraversableTree[]; }; type DiffNode = TreeNode> & { toString: () => string; }; declare const compare$1: (a: TraversableTree, b: TraversableTree, eq?: IsEqual, parent?: DiffNode) => DiffNode; declare namespace tree_mutable_d_exports { export { add, addValue, asDynamicTraversable$1 as asDynamicTraversable, breadthFirst$2 as breadthFirst, children$2 as children, childrenLength$1 as childrenLength, childrenValues, compare, computeMaxDepth, createNode$1 as createNode, depthFirst$3 as depthFirst, findAnyChildByValue$2 as findAnyChildByValue, findChildByValue$1 as findChildByValue, findParentsValue, followValue$1 as followValue, fromPlainObject, getRoot, hasAnyChild$1 as hasAnyChild, hasAnyParent$1 as hasAnyParent, hasChild$1 as hasChild, hasParent$1 as hasParent, nodeDepth, parents$1 as parents, parentsValues, queryByValue, queryParentsValue, remove$1 as remove, removeValuelessNodesFromChild, root$2 as root, rootWrapped$1 as rootWrapped, setChildren, siblings$2 as siblings, stripParentage, throwTreeTest, toStringDeep$4 as toStringDeep, treeTest, value, wrap$1 as wrap }; } /** * Compares two nodes. * * By default uses `isEqualValueIgnoreOrder` to compare nodes. This means * values of nodes will be compared, ignoring the order of fields. * @param a * @param b * @param eq Comparison function. Uses `isEqualValueIgnoreOrder` by default. * @returns Compare results */ declare function compare(a: TreeNode, b: TreeNode, eq?: IsEqual): DiffNode; /** * Converts {@link Trees.TreeNode} to {@link Trees.SimplifiedNode}, removing the 'parent' fields. * This can be useful because if you have the whole tree, the parent field * is redundant and because it makes circular references can make dumping to console etc more troublesome. * * Recursive: strips parentage of all children and so on too. * @param node */ declare function stripParentage(node: TreeNode): SimplifiedNode; /** * Wraps node `n` for a more object-oriented means of access. * It will wrap child nodes on demand. For this reason, WrappedNode object * identity is not stable * @param n Node to wrap */ declare function wrap$1(n: TreeNode): WrappedNode; /** * Removes `child` from the tree structure it is in. * It removes `child` from its parent. Any sub-children of `child` still remain connected. * @param child */ declare function remove$1(child: TreeNode): boolean; /** * Starting from a child node, work backwards, removing it and ancestors that have no value * * If `child` is an only child, it will recursively call the same function on the parent. * @param child Child to start from */ declare function removeValuelessNodesFromChild(child: TreeNode): boolean; /** * Enumeate all siblings of `child`. This won't include `child` itself. * If `child` is not part of a tree (ie has no parent) no values are yielded. */ declare function siblings$2(child: TreeNode, eq?: IsEqual>): IterableIterator>; /** * Depth-first iteration of the children of `node` * @param node */ declare function depthFirst$3(node: TreeNode): IterableIterator>; /** * Breadth-first iteration of the children of `node` * @param node */ declare function breadthFirst$2(node: TreeNode): IterableIterator>; /** * Validates the tree from `root` downwards. * @param root * @param seen */ declare function treeTest(root: TreeNode, seen?: Array>): [ok: boolean, msg: string, node: TreeNode]; /** * Throws an exception if `root` fails tree validation * @param root */ declare function throwTreeTest(root: TreeNode): void; /** * Iterate over direct children of `root`, yielding {@link TreeNode} instances. * Use {@link childrenValues} to iterate over child values * @param root */ declare function children$2(root: TreeNode): IterableIterator>; /** * Iterate over the value of direct children of `root`. * Use {@link children} if you want to iterate over {@link TreeNode} instances instead. * @param root */ declare function childrenValues(root: TreeNode): IterableIterator; /** * Iterate over all parents of `child`. First result is the immediate parent. * @param child */ declare function parents$1(child: TreeNode): IterableIterator>; /** * Returns the depth of `node`. A root node (ie. with no parents) has a depth of 0. * @param node */ declare function nodeDepth(node: TreeNode): number; /** * Returns _true_ if `child` is an immediate child of `parent`. * @param child * @param parent * @param eq Equality function to compare nodes. Uses `isEqualDefault` by default, which compares by reference. */ declare function hasChild$1(child: TreeNode, parent: TreeNode, eq?: IsEqual>): boolean; /** * Returns the first immediate child of `parent` that matches `value`. * * Use {@link queryByValue} if you want all matching children. * @param value * @param parent * @param eq */ declare function findChildByValue$1(value: T, parent: TreeNode, eq?: IsEqual): TreeNode | undefined; /** * Yield all immediate children of `parent` that match `value`. * * Use {@link findChildByValue} if you only want the first matching child. * @param value * @param parent * @param eq */ declare function queryByValue(value: T, parent: TreeNode, eq?: IsEqual): IterableIterator>; /** * Returns _true_ if `prospectiveChild` is some child node of `parent`, * anywhere in the tree structure. * * Use {@link hasChild} to only check immediate children. * @param prospectiveChild * @param parent */ declare function hasAnyChild$1(prospectiveChild: TreeNode, parent: TreeNode): boolean; /** * Using a breadth-first search, return the first child of `parent` that has `value`. * @param value Value being sought * @param parent Parent node * @param eq Equality function to compare values. Uses `isEqualDefault` by default, which compares by reference. */ declare function findAnyChildByValue$2(value: T, parent: TreeNode, eq?: IsEqual): TreeNode | undefined; /** * Traverses up a node to find the root. * @param node */ declare function getRoot(node: TreeNode): TreeNode; /** * Returns _true_ if `prospectiveParent` is any ancestor * parent of `child`. * * Use {@link hasParent} to only check immediate parent. * @param child * @param prospectiveParent */ declare function hasAnyParent$1(child: TreeNode, prospectiveParent: TreeNode): boolean; /** * Yields the node value of each parent of `child`. * _undefined_ values are not returned. * * Use {@link queryParentsValue} to search for a particular value * @param child */ declare function parentsValues(child: TreeNode): Generator; /** * Yields all parents of `child` that have a given value. * Use {@link findParentsValue} to find the first match only. * @param child * @param value * @param eq */ declare function queryParentsValue(child: TreeNode, value: T, eq?: IsEqual): Generator, boolean, unknown>; /** * Returns the first parent that has a given value. * @param child * @param value * @param eq */ declare function findParentsValue(child: TreeNode, value: T, eq?: IsEqual): TreeNode | undefined; /** * Returns _true_ if `prospectiveParent` is the immediate * parent of `child`. * * Use {@link hasAnyParent} to check for any ancestor parent. * @param child * @param prospectiveParent */ declare function hasParent$1(child: TreeNode, prospectiveParent: TreeNode): boolean; /** * Computes the maximum depth of the tree. * That is, how many steps down from `node` it can go. * If a tree is: root -> childA -> subChildB * ```js * // Yields 2, since there are at max two steps down from root * computeMaxDepth(root); * ``` * @param node */ declare function computeMaxDepth(node: TreeNode): number; /** * Adds a child node to `parent`. * If `child` already has a parent, it is removed from that parent. * @param child * @param parent * @throws Error if adding a child would break tree structure */ declare function add(child: TreeNode, parent: TreeNode): void; /** * Adds a new child node based on a value */ declare function addValue(value: T | undefined, parent: TreeNode): TreeNode; /** * Creates the root for a tree, with an optional `value`. * Use {@link rootWrapped} if you want a more object-oriented mode of access. * @param value */ declare function root$2(value?: T): TreeNode; declare function fromPlainObject(value: Record, label?: string, parent?: TreeNode, seen?: any[]): TreeNode>; /** * Creates a tree, returning it as a {@link WrappedNode} for object-oriented access. * Use {@link Trees.Mutable.root} alternatively. * @param value */ declare function rootWrapped$1(value: T | undefined): WrappedNode; /** * Creates a `TreeNode` instance with a given value and parent. * Parent node, if specified, has its `childrenStore` property changed to include new child. * @param value * @param parent */ declare function createNode$1(value: T | undefined, parent?: TreeNode): TreeNode; declare function childrenLength$1(node: TreeNode): number; declare function value(node: TreeNode): T | undefined; /** * Projects `node` as a dynamic traversable. * Dynamic in the sense that it creates the traversable project for nodes on demand. * A consequence is that node identities are not stable. * @param node */ declare function asDynamicTraversable$1(node: TreeNode): TraversableTree; /** * Sets the children of `parent` to a list of `children`. * * Any previous children are disconnected from this parent. * All new children have their parent set to `parent`. * * There is some validation to ensure that adding the children doesn't break the tree. */ declare function setChildren(parent: TreeNode, children: Array>): void; declare function toStringDeep$4(node: TreeNode, indent?: number): string; declare function followValue$1(root: TreeNode, continuePredicate: (nodeValue: T, depth: number) => boolean, depth?: number): IterableIterator; declare namespace pathed_d_exports { export { PathOpts, Pathed, addValueByPath, children$1 as children, childrenLengthByPath, clearValuesByPath, findAnyChildByValue$1 as findAnyChildByValue, hasValue, parent, parentValues, removeValueByPath, siblings$1 as siblings, siblingsValues, toStringDeep$3 as toStringDeep, valueByPath, valuesByPath }; } /** * Options for parsing a path */ type PathOpts = Readonly<{ /** * If _true_, paths are expeced to start with the separator char. * Default: _false_ * * For a *nix file system, this would be _true_ */ startsWithSeparator: boolean; /** * Separator for path, eg '.' */ separator: string; /** * If two values are stored at same path, what to do? Default: overwrite * overwrite: last-write wins * ignore: first-write wins * allow: allow multiple values */ duplicates: `overwrite` | `allow` | `ignore`; }>; /** * Creates a wrapper for working with 'pathed' trees. * An example is a filesystem. * * ```js * const t = new Pathed(); * // Store a value. Path implies a structure of * // c -> users -> admin * // ...which is automatically created * t.add({x:10}, `c.users.admin`); * * t.add({x:20}, `c.users.guest`); * // Tree will now be: * // c-> users -> admin * // -> guest * * t.getValue(`c.users.guest`); // { x:20 } * ``` * * By default only a single value can be stored at a path. * Set options to allow this: * ```js * const t = new Pathed({ duplicates: `allow` }); * t.add({x:10}, `c.users.admin`); * t.add({x:20}, `c.users.admin`); * t.getValue(`c.users.admin`); // Throws an error because there are multiple values * t.getValues(`c.users.admin`); // [ {x:10}, {x:20 } ] * ``` * @param pathOpts * @returns */ declare class Pathed { #private; /** * Create, using default options * @param pathOpts */ constructor(pathOpts?: Partial); /** * Adds a value at the string path, automatically creating intermediate nodes as needed. * By default, if a value already exists at the path, it will be overwritten. Set options to change this. * @param value Value to associate with path * @param path Path */ add(value: T, path: string): void; validate(path: string): Result; /** * Returns a string representation of tree * @returns Returns a string representation of tree */ prettyPrint(): string; /** * Removes the value at the given path, returning _true_ * if there was a value. This will delete tree nodes if they become empty * @param path * @returns _true_ if value was removed */ remove(path: string): boolean; /** * Returns _true_ if we have a value at `path` * @param path * @returns _true_ if value exists at path */ hasPath(path: string): boolean; /** * Returns a tree node for a given path, or _undefined_ * if path does not exist. * * Use {@link getValue} to get the value at a node instead. * @param path * @returns The tree node for the given path, or _undefined_ if not found */ getNode(path: string): LabelledNode | undefined; /** * Returns the value at the path, or _undefined_ if path is not found. * Use {@link getNode} to get the tree node instead. * @param path * @returns The value at the path, or _undefined_ if path is not found */ getValue(path: string): T | undefined; /** * Gets the containing path to `node`. If _includeNode_ is true, we also include the * node's own label. */ getPath(node: LabelledNode, includeNode: boolean): string; /** * Gets the number of children at a given path. * Returns NaN if path does not exist or has no children. * @param path * @returns The number of children at the path, or NaN if path is not found */ childrenLength(path: string): number; /** * Get all the values stored at a path, if multiple values are allowed. Returns an empty array if path does not exist or has no value. * @param path * @returns An array of values at the path, or an empty array if path is not found */ getValues(path: string): T[] | undefined; /** * Removes all values at the given path, but leaves the structure of the tree intact. Returns _true_ if there was a value to clear. * @param path * @returns _true_ if there was a value to clear at the path */ clearValues(path: string): boolean; /** * Iterate all children of this path */ children(path: string): IterableIterator>; /** * Iterate all siblings of this path */ siblings(path: string): IterableIterator>; /** * Iterate all siblings of this path */ siblingsValues(path: string): IterableIterator>; /** * Returns the parent node of `path`, or _undefined_ if not found or at root. */ parent(path: string): LabelledNode | undefined; get separator(): string; /** * Returns the root tree node. * @returns The root tree node, or _undefined_ if tree is empty */ get root(): TreeNode> | undefined; } /** * Adds a value by a string path, with '.' as a the default delimiter * Automatically generates intermediate nodes. * * ```js * const root = addValueByPath({}, 'c'); * addValueByPath({x:'blah'}, 'c.users.admin', root); * ``` * * Creates the structure: * ``` * c value: { } label: c * + users value: undefined label: users * + admin value: { x: 'blah' } label: admin * ``` * * By default, multiple values under same key are overwritten, with the most recent winning. * @param value Value to add * @param path Path to add at * @param node Node to insert * @param pathOpts Options */ declare function addValueByPath(value: T, path: string, pathOpts: PathOpts, node?: LabelledNode): LabelledNode; declare function removeValueByPath(path: string, root: LabelledNode, pathOpts: PathOpts): boolean; declare function clearValuesByPath(path: string, root: LabelledNode, pathOpts: PathOpts): boolean; /** * Return the length of children of `path`, or NaN if path not found. */ declare function childrenLengthByPath(path: string, searchStart: LabelledNode, pathOpts: PathOpts): number; /** * Iterate over all the children of `path` */ declare function children$1(path: string, searchStart: LabelledNode, pathOpts: PathOpts): IterableIterator>; /** * Iterate over all the siblings of `path`, excluding the node at `path` itself. * Yields LabelledNode instances, which allow you to traverse tree. If all you care about is the values, use {@link siblingsValues} instead. */ declare function siblings$1(path: string, searchStart: LabelledNode, pathOpts: PathOpts): IterableIterator>; /** * Iterate over the values of all the siblings of `path`, excluding the node at `path` itself. If you need to traverse tree, use {@link siblings} instead. * @param path * @param searchStart * @param pathOpts */ declare function siblingsValues(path: string, searchStart: LabelledNode, pathOpts: PathOpts): IterableIterator>; /** * Return the parent node of `path`, or undefined if not found or at root. */ declare function parent(path: string, searchStart: LabelledNode, pathOpts: PathOpts): LabelledNode | undefined; declare function parentValues(start: LabelledNode): IterableIterator>; /** * Searches children, returning the node that has the given `value`. * @param value Value * @param node Node to start search from * @param maxDepth Maximum depth, defaults to full recursion * @param eq Equality function * @returns Child, or _undefined_ if not found */ declare function findAnyChildByValue$1(value: T, node: LabelledNode, maxDepth?: number, eq?: IsEqual): LabelledNode | undefined; declare function hasValue(value: T, node: LabelledNode, eq?: IsEqual): boolean; declare function valueByPath(path: string, node: LabelledNode, pathOpts?: Partial): T | undefined; declare function valuesByPath(path: string, searchStart: LabelledNode, pathOpts?: Partial): T[] | undefined; /** * Returns a string representation of a LabelledNode tree. * Format: `{ label: "x", value: ..., children: [...] }` */ declare function toStringDeep$3(node: LabelledNode): string; declare namespace traverse_object_d_exports { export { ChildrenOptions, CreateOptions, asDynamicTraversable, children, create$1 as create, createSimplified, createWrapped, depthFirst$2 as depthFirst, getByPath, prettyPrint, prettyPrintEntries, toStringDeep$2 as toStringDeep, traceByPath }; } /** * Helper function to get a 'friendly' string representation of an array of {@link TraverseObjectEntry}. * @param entries * @returns */ declare function prettyPrintEntries(entries: readonly TraverseObjectEntry[]): string; /** * Returns a human-friendly debug string for a tree-like structure * ```js * console.log(Trees.prettyPrint(obj)); * ``` * @param indent * @param node * @param options * @returns */ declare const prettyPrint: (node: object, indent?: number, options?: Partial) => string; /** * Returns a debug string representation of the node (recursive) * @param node * @param indent * @returns */ declare const toStringDeep$2: (node: TreeNode, indent?: number) => string; type ChildrenOptions = Readonly<{ /** * If set, only uses leaves or branches. 'none' means there is no filter. */ filter: `none` | `leaves` | `branches`; /** * Default name to use. This is necessary in some cases, eg a root object. */ name: string; }>; /** * Yields the direct (ie. non-recursive) children of a tree-like object as a pairing * of node name and value. Supports basic objects, Maps and arrays. * * To iterate recursively, consider {@link depthFirst} * * Each child is returned in an {@link TraverseObjectEntry} structure: * ```typescript * type Entry = Readonly<{ * // Property name * name: string, * // Value of property, as if you called `object[propertyName]` * sourceValue: any, * // Branch nodes will have _undefined_, leaf nodes will contain the value * leafValue: any * }>; * ``` * * For example, iterating over a flat object: * ```js * const verySimpleObject = { field: `hello`, flag: true } * const kids = [ ...children(verySimpleObject) ]; * // Yields: * // [ { name: "field", sourceValue: `hello`, leafValue: `hello` }, * // { name: "flag", sourceValue: true, leafValue: true } ] * ``` * * For objects containing objects: * ```js * const lessSimpleObject = { field: `hello`, flag: true, colour: { `red`, opacity: 0.5 } } * const kids = [ ...children(verySimpleObject) ]; * // Yields as before, plus: * // { name: "colour", sourceValue: { name: 'red', opacity: 0.5 }, leafValue: undefined } * ``` * * Note that 'sourceValue' always contains the property value, as if you * access it via `object[propName]`. 'leafValue' only contains the value if it's a leaf * node. * * Arrays are assigned a name based on index. * @example Arrays * ```js * const colours = [ { r: 1, g: 0, b: 0 }, { r: 0, g: 1, b: 0 }, { r: 0, g: 0, b: 1 } ]; * // Children: * // [ * // { name: "array[0]", value: {r:1,g:0,b:0} }, * // { name: "array[1]", value: {r:0,g:1,b:0} }, * // { name: "array[2]", value: {r:0,g:0,b:1} }, * // ] * ``` * * Pass in `options.name` (eg 'colours') to have names generated as 'colours[0]', etc. * Options can also be used to filter children. By default all direct children are returned. * @param node * @param options */ declare function children(node: object, options?: Partial): IterableIterator; declare function depthFirst$2(node: object, options?: Partial, ancestors?: string[]): IterableIterator; /** * Returns the closest matching entry, tracing `path` in an array, Map or simple object. * Returns an entry with _undefined_ value at the point where tracing stopped. * Use {@link traceByPath} to step through all the segments. * * ```js * const people = { * jane: { * address: { * postcode: 1000, * street: 'West St', * city: 'Blahville' * }, * colour: 'red' * } * } * Trees.getByPath('jane.address.postcode', people); // '.' default separator * // ['postcode', 1000] * Trees.getByPath('jane.address.country.state', people); * // ['country', undefined] - since full path could not be resolved. * ``` * @param path Path, eg `jane.address.postcode` * @param node Node to look within * @param options Options for parsing path. By default '.' is used as a separator * @returns */ declare function getByPath(path: string, node: object, options?: TraverseObjectPathOpts): TraverseObjectEntryWithAncestors; /** * Enumerates over children of `node` towards the node named in `path`. * This is useful if you want to get the interim steps to the target node. * * Use {@link getByPath} if you don't care about interim steps. * * ```js * const people = { * jane: { * address: { * postcode: 1000, * street: 'West St', * city: 'Blahville' * }, * colour: 'red' * } * } * for (const p of Trees.traceByPath('jane.address.street', people)) { * // { name: "jane", value: { address: { postcode: 1000,street: 'West St', city: 'Blahville' }, colour: 'red'} }, * // { name: "address", value: { postcode: 1000, street: 'West St', city: 'Blahville' } }, * // { name: "street", value: "West St" } } * } * ``` * * Results stop when the path can't be followed any further. * The last entry will have a name of the last sought path segment, and _undefined_ as its value. * * @param path Path to traverse * @param node Starting node * @param options Options for path traversal logic * @returns */ declare function traceByPath(path: string, node: object, options?: TraverseObjectPathOpts): Iterable; /** * Returns a projection of `node` as a dynamic traversable. * This means that the tree structure is dynamically created as last-minute as possible. * * The type when calling `getValue()` is {@link TraverseObjectEntryStatic}: * ```typescript * type EntryStatic = Readonly<{ * name: string, * value: any * ancestors: string[] * }> * ``` * * Note that the object identity of TraversableTree return results is not stable. * This is because they are created on-the-fly by reading fields of `node`. * * ```js * const c1 = [ ...asDynamicTraversable(someObject).children() ]; * const c2 = [ ...asDynamicTraversable(someObject).children() ]; * * // Object identity is not the same * c1[ 0 ] === c1[ 0 ]; // false * * // ...even though its referring to the same value * c1[ 0 ].getValue() === c1[ 0 ].getValue(); // true * ``` * * Instead .getIdentity() to get a stable identity: * ```js * c1[ 0 ].getIdentity() === c2[ 0 ].getIdentity(); // true * ``` * * @example * ```js * const myObj = { name: `Pedro`, size: 45, colour: `orange` }; * const root = Trees.FromObject.asDynamicTraversable(myObj); * for (const v of Trees.Traverse.breadthFirst(root)) { * // v.getValue() yields: * // { name: 'name', sourceValue: 'Pedro' ...}, * // { name: 'size', sourceValue: 45 ... } * // ... * } * ``` * @param node Object to read * @param options Options when creating traversable * @param ancestors Do not use * @param parent Do not use * @returns */ declare const asDynamicTraversable: (node: object, options?: Partial, ancestors?: string[], parent?: TraversableTree) => TraversableTree; /** * Reads all fields and sub-fields of `node`, returning as a 'wrapped' tree structure. * Is a snapshot of `node`, and won't update if it mutates. * @param node * @param options * @returns */ declare const createWrapped: (node: object, options: Partial) => WrappedNode; type CreateOptions = { name: string; /** * If _true_, only leaf nodes have values. This avoids repetition (important * when comparing trees), with semantics being in the tree itself. * * When _false_ (default) values get decomposed down the tree. This * makes it easy to get all the data for a branch of the tree. * * * Eg if storing { person: { address { state: `qld` } } } * When _true_, the tree would be: * ``` * person, value: undefined * + address, value: undefined * + state, value: 'qld' * ``` * But when _false_, the tree would be: * ``` * person, value: { address: { state: `qld } } * + address, value: { state: `qld` } * + state, value: `qld` * ``` */ valuesAtLeaves: boolean; }; /** * Reads all fields and sub-fields of `node`, returning as a basic tree structure. * The structure is a snapshot of the object. If the object changes afterwards, the tree will * remain the same. * * Alternatively, consider {@link asDynamicTraversable} which reads the object dynamically. * @example * ```js * const myObj = { name: `Pedro`, size: 45, colour: `orange` }; * const root = Trees.FromObject.create(myObj); * for (const v of Trees.Traverse.breadthFirst(root)) { * // v.getValue() yields: * // { name: 'name', sourceValue: 'Pedro' ...}, * // { name: 'size', sourceValue: 45 ... } * // ... * } * ``` * @param node * @param options * @returns */ declare const create$1: (node: object, options?: Partial) => TreeNode; /** * Returns a copy of `node` with its (and all its childrens') parent information removed. * * Under the hood: * ```js * TreeArrayBacked.stripParentage(create(node, options)); * ``` * @param node * @param options * @returns */ declare const createSimplified: (node: object, options?: Partial) => SimplifiedNode; declare namespace traversable_tree_d_exports { export { breadthFirst$1 as breadthFirst, childrenLength, couldAddChild, depthFirst$1 as depthFirst, find$2 as find, findAnyChildByValue, findAnyParentByValue, findByValue, findChildByValue, findParentByValue, followValue, hasAnyChild, hasAnyChildValue, hasAnyParent, hasAnyParentValue, hasChild, hasChildValue, hasParent, hasParentValue, parents, siblings, toString, toStringDeep$1 as toStringDeep }; } /** * Returns the number of children of `tree`. * Under the hood is just `[ ...tree.children() ].length` * @param tree * @returns */ declare const childrenLength: (tree: TraversableTree) => number; /** * Returns _true_ if `child` is parented at any level (grand-parented etc) by `possibleParent` * @param child Child being sought * @param possibleParent Possible parent of child * @param eq Equality comparison function {@link isEqualDefault} used by default * @returns */ declare const hasAnyParent: | TreeNode, TV>(child: T, possibleParent: T, eq?: IsEqual) => boolean; /** * Returns _true_ if `child` is parented at any level (grand-parented etc) by a parent with value `possibleParentValue` * @param child Child being sought * @param possibleParentValue Value of possible parent of child * @param eq Equality comparison function {@link isEqualDefault} used by default * @throws TypeError if `child` is undefined * @returns */ declare const hasAnyParentValue: | TreeNode, TV>(child: T, possibleParentValue: TV, eq?: IsEqual) => boolean; /** * Returns any parent of `child` that has value `possibleParentValue`. Returns _undefined_ if not found. * @param child Child being sought * @param possibleParentValue Value of possible parent of child * @param eq Equality comparison function {@link isEqualDefault} used by default * @returns */ declare const findAnyParentByValue: (child: TraversableTree, possibleParentValue: TValue, eq?: IsEqual) => TraversableTree | undefined; /** * Returns _true_ if `child` exists within `possibleParent`. By default it only looks at the immediate * parent (maxDepth: 0). Use Number.MAX_SAFE_INTEGER for searching recursively upwards (or {@link hasAnyParent}) * @param child Child being sought * @param possibleParent Possible parent of child * @param maxDepth Max depth of traversal. Default of 0 only looks for immediate parent. * @param eq Equality comparison function. {@link isEqualDefault} used by default. * @returns */ declare const hasParent: | TreeNode, TV>(child: T, possibleParent: T, eq?: IsEqual, maxDepth?: number) => boolean; /** * Checks if a child node has a parent with a certain value * Note: by default only checks immediate parent. Set maxDepth to a large value to recurse * * Uses `getValue()` on the parent if that function exists. * @param child Node to start looking from * @param possibleParentValue Value to seek * @param eq Equality checker * @param maxDepth Defaults to 0, so it only checks immediate parent * @returns */ declare const hasParentValue: | TreeNode, TV>(child: T, possibleParentValue: TV, eq?: IsEqual, maxDepth?: number) => boolean; /** * Returns any parent of `child` that has value `possibleParentValue`. Returns _undefined_ if not found. * @param child Child being sought * @param possibleParentValue Value of possible parent of child * @param eq Equality comparison function {@link isEqualDefault} used by default * @param maxDepth Maximum depth of traversal. Default of 0 only looks for immediate parent. * @returns */ declare const findParentByValue: | TreeNode, TV>(child: T, possibleParentValue: TV, eq?: IsEqual, maxDepth?: number) => T | undefined; /** * Returns _true_ if `prospectiveChild` can be legally added to `parent`. * _False_ is returned if: * * `parent` and `prospectiveChild` are equal * * `parent` already contains `prospectiveChild` * * `prospectiveChild` has `parent` as its own child * * Throws an error if `parent` or `prospectiveChild` is null/undefined. * @param parent Parent to add to * @param prospectiveChild Prospective child * @param eq Equality function */ declare const couldAddChild: (parent: TraversableTree, prospectiveChild: TraversableTree, eq?: IsEqual>) => void; /** * Returns _true_ if _possibleChild_ is contained within _parent_ tree. * That is, it is any sub-child. * @param parent Parent tree * @param possibleChild Sought child * @param eq Equality function, or {@link isEqualDefault} if undefined. * @returns */ declare const hasAnyChild: | TreeNode, TV>(parent: T, possibleChild: T, eq?: IsEqual) => boolean; /** * Returns _true_ if `parent` has any child with value `possibleChildValue`. It explores * at children at any depth from `parent`. * @param parent * @param possibleChildValue * @param eq * @returns */ declare const hasAnyChildValue: (parent: TraversableTree, possibleChildValue: T, eq?: IsEqual) => boolean; /** * Returns _true_ if _possibleChild_ is contained within _maxDepth_ children * of _parent_ node. By default only looks at immediate children (maxDepth = 0). * * ```js * // Just check parentNode for childNode * Trees.hasChild(parentNode, childNode); * // See if parentNode or parentNode's parents have childNode * Trees.hasChild(parentNode, childNode, 1); * // Use custom equality function, in this case comparing on name field * Trees.hasChild(parentNode, childNode, 0, (a, b) => a.name === b.name); * ``` * @param parent Parent tree * @param possibleChild Sought child * @param maxDepth Maximum depth. 0 for immediate children, Number.MAX_SAFE_INTEGER for boundless * @param eq Equality function, or {@link isEqualDefault} if undefined. * @returns */ declare const hasChild: | TreeNode, TV>(parent: T, possibleChild: T, eq?: IsEqual, maxDepth?: number) => boolean; /** * Returns _true_ if `parent` has any child with value `possibleChildValue`. It explores * at children up to `maxDepth` from `parent`. By default only looks at immediate children (maxDepth = 0). * @param parent * @param possibleValue * @param eq * @param maxDepth * @returns */ declare const hasChildValue: (parent: TraversableTree, possibleValue: T, eq?: IsEqual, maxDepth?: number) => boolean; /** * Iterates over siblings of `node`. * * Other iteration options: * * {@link breadthFirst}: Children, breadth-first * * {@link depthFirst}: Children, depth-first * * {@link parents}: Chain of parents, starting with immediate parent * * {@link siblings}: Nodes with same parent * @param node Node to begin from * @returns */ declare function siblings(node: TraversableTree): IterableIterator>; /** * Iterates over parents of `node`, starting with immediate parent * * Other iteration options: * * {@link breadthFirst}: Children, breadth-first * * {@link depthFirst}: Children, depth-first * * {@link parents}: Chain of parents, starting with immediate parent * * {@link siblings}: Nodes with same parent * @param node Node to begin from * @returns */ declare function parents | TreeNode, TV>(node: T): IterableIterator; /** * Descends `parent`, breadth-first, looking for a particular value. * Returns _undefined_ if not found. * @param parent * @param possibleValue * @param eq * @returns */ declare function findAnyChildByValue | TreeNode, TV>(parent: T, possibleValue: TV, eq?: IsEqual): T | undefined; /** * Searches breadth-first for `possibleValue` under and including `parent`. * `maxDepth` sets he maximum level to which the tree is searched. * @param parent * @param possibleValue * @param eq * @param maxDepth * @returns */ declare function findChildByValue | TreeNode, TV>(parent: T, possibleValue: TV, eq?: IsEqual, maxDepth?: number): T | undefined; /** * Iterates over children of `root`, depth-first. * * Other iteration options: * * {@link breadthFirst}: Children, breadth-first * * {@link depthFirst}: Children, depth-first * * {@link parents}: Chain of parents, starting with immediate parent * * {@link siblings}: Nodes with same parent * @param root Root node * @returns */ declare function depthFirst$1 | TreeNode, TV>(root: T): Generator; /** * Iterates over the children of `root`, breadth-first * * Other iteration options: * * {@link breadthFirst}: Children, breadth-first * * {@link depthFirst}: Children, depth-first * * {@link parents}: Chain of parents, starting with immediate parent * * {@link siblings}: Nodes with same parent * * @example Traversing over a simple object * ```js * const myObj = { name: `Pedro`, size: 45, colour: `orange` }; * const root = Trees.FromObject.asDynamicTraversable(myObj); * for (const v of Trees.Traverse.breadthFirst(root)) { * // v.getValue() yields: * // { name: 'name', sourceValue: 'Pedro' ...}, * // { name: 'size', sourceValue: 45 ... } * // ... * } * ``` * @param root Root node * @param depth How many levels to traverse * @returns */ declare function breadthFirst$1 | TreeNode, TV>(root: T, depth?: number): IterableIterator; /** * Applies `predicate` to `root` and all its child nodes, returning the node where * `predicate` yields _true_. * Use {@link findByValue} to find a node by its value * @param root * @param predicate * @param order Iterate children by breadth or depth. Default 'breadth' * @returns */ declare function find$2(root: TraversableTree, predicate: (node: TraversableTree) => boolean, order?: `breadth` | `depth`): TraversableTree | undefined; /** * Applies `predicate` to `root` and all its child nodes, returning the node value for * `predicate` yields _true_. * Use {@link find} to filter by nodes rather than values * * ```js * const n = findByValue(root, (v) => v.name === 'Bob'); * ``` * @param root * @param predicate * @param order Iterate children by breadth or depth. Default 'breadth' * @returns */ declare function findByValue(root: TraversableTree, predicate: (nodeValue: T) => boolean, order?: `breadth` | `depth`): TraversableTree | undefined; /** * Search through children in a path-like manner. * * It finds the first child of `root` that matches `continuePredicate`. * The function gets passed a depth of 1 to begin with. It recurses, looking for the next sub-child, etc. * * If it can't find a child, it stops. * * This is different to 'find' functions, which exhaustively search all possible child nodes, regardless of position in tree. * * ```js * const path = 'a.aa.aaa'.split('.'); * const pred = (nodeValue, depth) => { * if (nodeValue === path[0]) { * path.shift(); // Remove first element * return true; * } * return false; * } * * // Assuming we have a tree of string values: * // a * // - aa * // - aaa * // - ab * // b * // - ba * for (const c of follow(tree, pred)) { * // Returns nodes: a, aa and then aaa * } * ``` * @param root * @param continuePredicate * @param depth */ declare function followValue(root: TraversableTree, continuePredicate: (nodeValue: T, depth: number) => boolean, depth?: number): IterableIterator; declare function toStringDeep$1(node: TraversableTree, depth?: number): string; declare function toString(...nodes: TraversableTree[]): string; declare namespace binary_tree_d_exports { export { BinaryChildSide, WrappedBinaryNode, addLeft, addRight, balanceFactor, breadthFirst, createNode, depthFirst, find$1 as find, fromArray$1 as fromArray, getLeft, getRight, grandparent, hasLeft, hasRight, height, inOrder$1 as inOrder, isLeaf, isParentLeftChild, isParentRightChild, leftSubtreeHeightFn, parentChildSide, postOrder$1 as postOrder, preOrder$1 as preOrder, removeNode, rightSubtreeHeightFn, root$1 as root, rootWrapped, setLeft, setRight, sibling, toArray, toStringDeep, uncle, wrap }; } type BinaryChildSide = `left` | `right` | `neutral`; type WrappedBinaryNode = { node: TreeNode; get left(): WrappedBinaryNode | undefined; get right(): WrappedBinaryNode | undefined; set left(value: WrappedBinaryNode | undefined); set right(value: WrappedBinaryNode | undefined); get parentChildSide(): BinaryChildSide; get isParentLeftChild(): boolean; get isParentRightChild(): boolean; get isLeaf(): boolean; get sibling(): WrappedBinaryNode | undefined; get uncle(): WrappedBinaryNode | undefined; get grandparent(): WrappedBinaryNode | undefined; get leftSubtreeHeight(): number; get rightSubtreeHeight(): number; get height(): number; get balanceFactor(): number; has(value: T): boolean; addLeft(value: T): WrappedBinaryNode; addRight(value: T): WrappedBinaryNode; setLeft(node: WrappedBinaryNode | TreeNode): void; setRight(node: WrappedBinaryNode | TreeNode): void; remove(): void; }; declare const getLeft: (node: TreeNode) => TreeNode | undefined; declare const getRight: (node: TreeNode) => TreeNode | undefined; declare const hasLeft: (node: TreeNode) => boolean; declare const hasRight: (node: TreeNode) => boolean; declare const isLeaf: (node: TreeNode) => boolean; declare const setLeft: (parent: TreeNode, child: TreeNode | undefined) => void; declare const setRight: (parent: TreeNode, child: TreeNode | undefined) => void; declare const removeNode: (node: TreeNode) => void; declare const sibling: (node: TreeNode) => TreeNode | undefined; declare const uncle: (node: TreeNode) => TreeNode | undefined; declare const grandparent: (node: TreeNode) => TreeNode | undefined; declare const isParentLeftChild: (node: TreeNode) => boolean; declare const isParentRightChild: (node: TreeNode) => boolean; declare const parentChildSide: (node: TreeNode) => BinaryChildSide; declare const height: (node: TreeNode) => number; declare const balanceFactor: (node: TreeNode) => number; declare const leftSubtreeHeightFn: (node: TreeNode) => number; declare const rightSubtreeHeightFn: (node: TreeNode) => number; declare const addLeft: (value: T, parent: TreeNode) => TreeNode; declare const addRight: (value: T, parent: TreeNode) => TreeNode; declare const root$1: (value?: T) => TreeNode; declare const createNode: (value: T | undefined, parent?: TreeNode) => TreeNode; declare const wrap: (node: TreeNode) => WrappedBinaryNode; declare const rootWrapped: (value?: T) => WrappedBinaryNode; declare const find$1: (root: TreeNode, value: T) => TreeNode | undefined; declare function inOrder$1(node: TreeNode): IterableIterator>; declare function preOrder$1(node: TreeNode): IterableIterator>; declare function postOrder$1(node: TreeNode): IterableIterator>; declare function depthFirst(node: TreeNode): IterableIterator>; declare function breadthFirst(node: TreeNode): IterableIterator>; declare const fromArray$1: (array: T[]) => TreeNode | undefined; declare const toArray: (root: TreeNode) => T[]; declare const toStringDeep: (node: TreeNode, indent?: number) => string; declare namespace binary_search_tree_d_exports { export { Bst, BstNode, create, find, fromArray, has, inOrder, insert, max, min, postOrder, preOrder, remove, root, valuesInOrder }; } type BstNode = TreeNode; declare class Bst { root: BstNode; readonly comparer: Comparer; constructor(comparer?: Comparer); insert(value: T): BstNode; has(value: T): boolean; find(value: T): BstNode | undefined; remove(value: T): boolean; min(): BstNode | undefined; max(): BstNode | undefined; inOrder(): IterableIterator>; preOrder(): IterableIterator>; postOrder(): IterableIterator>; valuesInOrder(): IterableIterator; toArrayInOrder(): T[]; } declare const insert: (root: BstNode, value: T, compare?: Comparer) => BstNode; declare const has: (root: BstNode, value: T, compare?: Comparer) => boolean; declare const find: (root: BstNode, value: T, compare?: Comparer) => BstNode | undefined; declare const min: (root: BstNode) => BstNode | undefined; declare const max: (root: BstNode) => BstNode | undefined; declare const remove: (root: BstNode, value: T, compare?: Comparer) => BstNode | undefined; declare function inOrder(node: BstNode): IterableIterator>; declare function preOrder(node: BstNode): IterableIterator>; declare function postOrder(node: BstNode): IterableIterator>; declare function valuesInOrder(node: BstNode): IterableIterator; declare const create: (comparer?: Comparer) => Bst; declare const fromArray: (array: T[], comparer?: Comparer) => Bst; declare const root: () => BstNode; //#endregion //#region src/tree/labelled.d.ts declare function isSingleValue(v: LabelledValue): v is LabelledSingleValue; declare function isMultiValue(v: LabelledValue): v is LabelledValues; declare namespace index_d_exports { export { binary_search_tree_d_exports as BinarySearchTree, binary_tree_d_exports as BinaryTree, DiffAnnotation, DiffNode, traverse_object_d_exports as FromObject, LabelledNode, LabelledSingleValue, LabelledValue, LabelledValues, tree_mutable_d_exports as Mutable, pathed_d_exports as Pathed, SimplifiedNode, TraversableTree, traversable_tree_d_exports as Traverse, TraverseObjectEntry, TraverseObjectEntryStatic, TraverseObjectEntryWithAncestors, TraverseObjectPathOpts, TreeNode, WrappedNode, compare$1 as compare, isMultiValue, isSingleValue, isTraversable, isTreeNode, toTraversable }; } /** * Makes a 'traversable' to move around a {@link TreeNode}, * an existing {@link TraversableTree} or a plain object. * * @param node * @returns */ declare const toTraversable: (node: TreeNode | TraversableTree | object) => TraversableTree; /** * Checks whether `node` is of type {@link TreeNode}. * * Checks for: parent, childrenStore and value defined on `node`. * @param node * @returns */ declare const isTreeNode: (node: any) => node is TreeNode; /** * Checks if `node` is of type {@link TraversableTree}. * * Checks by looking for: children, getParent, getValue and getIdentity defined on `node`. * @param node * @returns */ declare const isTraversable: (node: any) => node is TraversableTree; //#endregion export { TraverseObjectEntryStatic as C, WrappedNode as D, TreeNode as E, TraverseObjectEntry as S, TraverseObjectPathOpts as T, LabelledSingleValue as _, isMultiValue as a, SimplifiedNode as b, binary_tree_d_exports as c, pathed_d_exports as d, tree_mutable_d_exports as f, LabelledNode as g, compare$1 as h, toTraversable as i, traversable_tree_d_exports as l, DiffNode as m, isTraversable as n, isSingleValue as o, DiffAnnotation as p, isTreeNode as r, binary_search_tree_d_exports as s, index_d_exports as t, traverse_object_d_exports as u, LabelledValue as v, TraverseObjectEntryWithAncestors as w, TraversableTree as x, LabelledValues as y };