UNPKG

fast-tree-builder

Version:

Easily construct highly customizable bi-directional tree structures from iterable data.

124 lines (123 loc) 5.63 kB
type TreeNode<TValue, TValueKey extends PropertyKey | false, TParentKey extends PropertyKey | false, TChildrenKey extends PropertyKey, TDepthKey extends PropertyKey | false, TIncludeEmptyChildrenArray extends boolean> = (TValueKey extends false ? Omit<TValue, Exclude<TParentKey, false> | TChildrenKey | Exclude<TDepthKey, false>> : { [k in Exclude<TValueKey, false>]: TValue; }) & (TParentKey extends false ? {} : { [k in Exclude<TParentKey, false>]?: TreeNode<TValue, TValueKey, TParentKey, TChildrenKey, TDepthKey, TIncludeEmptyChildrenArray>; }) & (TIncludeEmptyChildrenArray extends true ? { [k in TChildrenKey]: TreeNode<TValue, TValueKey, TParentKey, TChildrenKey, TDepthKey, TIncludeEmptyChildrenArray>[]; } : { [k in TChildrenKey]?: TreeNode<TValue, TValueKey, TParentKey, TChildrenKey, TDepthKey, TIncludeEmptyChildrenArray>[]; }) & (TDepthKey extends false ? {} : { [k in Exclude<TDepthKey, false>]: number; }); type AccessorReturnType<O, P extends (keyof O) | ((item: O) => any)> = P extends ((item: O) => infer R) ? R : P extends (keyof O) ? O[P] : never; type ObjectKeysOfIterableProperties<T> = 0 extends (1 & T) ? PropertyKey : { [K in keyof T]: T[K] extends (Iterable<unknown> & object) | null | undefined ? K : never; }[keyof T]; declare function buildTree<TIdAccessor extends NoInfer<keyof TInputValue> | ((item: NoInfer<TInputValue>) => unknown), TValueKey extends PropertyKey | false = 'value', TParentKey extends PropertyKey | false = 'parent', TChildrenKey extends PropertyKey = 'children', TDepthKey extends PropertyKey | false = false, TInputValue extends (TValueKey extends false ? object : TIdAccessor extends PropertyKey ? object : unknown) = any, TResolvedValue extends (TValueKey extends false ? object : unknown) = TInputValue, TIncludeEmptyChildrenArray extends boolean = false>(items: Iterable<TInputValue>, options: { /** * A string key or function used to get the item's unique identifier. */ id: TIdAccessor; /** * Function to transform an item to a custom value stored in the node. */ valueResolver?: { (item: NoInfer<TInputValue>): TResolvedValue; }; /** * Key where the item is stored in the output node. * * Set to `false` to merge the item's properties directly into the node (shallow copy). * * Defaults to `'value'`. */ valueKey?: TValueKey; /** * Key where the node's parent reference is stored in the output node. * * Set to `false` to omit parent links. * * Defaults to `'parent'`. */ parentKey?: TParentKey; /** * Key where the node's children are stored in the output node. * * Defaults to `'children'`. */ childrenKey?: TChildrenKey; /** * Key where the node's depth is stored in the output node. * Root nodes have a depth of 0. * * Set to `false` to omit depth values. * * Setting this enables validateTree implicitly, as depth calculation requires full tree validation. * Both operations share the same traversal logic so the additional tree validation is not an overhead. * * Defaults to `false`. */ depthKey?: TDepthKey; /** * Leaf nodes will include an empty children array when this is set to `true`. * Otherwise they are left as `undefined`. * * This ensures you can loop over every node child list without checking its existence. * * Defaults to `false`. */ includeEmptyChildrenArray?: TIncludeEmptyChildrenArray; /** * Validates that the final structure forms a tree. * * Ensures: * - No cycles * - No node reachable through multiple paths * * Throws if the structure is not a proper tree. * * Defaults to `false`. */ validateTree?: boolean; /** * When true, verifies all parentId or childIds resolve to real items. * Only `null` and `undefined` are acceptable as parent id for root nodes in parentId mode. * Every item in the children list must resolve to a real item in childIds mode. * * Errors are thrown on invalid references. * * Defaults to `false`. */ validateReferences?: boolean; } & ({ /** * A string key or function used to get the item's parent identifier. * * Either `parentId` or `childIds` must be provided. */ parentId?: never; /** * A string key or function to retrieve a list of child identifiers from an item. * * Either `parentId` or `childIds` must be provided. */ childIds: NoInfer<ObjectKeysOfIterableProperties<TInputValue>> | ((item: NoInfer<TInputValue>) => (Iterable<unknown> & object) | null | undefined); } | { /** * A string key or function used to get the item's parent identifier. * * Either `parentId` or `childIds` must be provided. */ parentId: NoInfer<keyof TInputValue> | ((item: NoInfer<TInputValue>) => unknown); /** * A string key or function to retrieve a list of child identifiers from an item. * * Either `parentId` or `childIds` must be provided. */ childIds?: never; })): { roots: TreeNode<TResolvedValue extends undefined ? TInputValue : TResolvedValue, TValueKey, TParentKey, TChildrenKey, TDepthKey, TIncludeEmptyChildrenArray>[]; nodes: Map<AccessorReturnType<TInputValue, TIdAccessor>, TreeNode<TResolvedValue extends undefined ? TInputValue : TResolvedValue, TValueKey, TParentKey, TChildrenKey, TDepthKey, TIncludeEmptyChildrenArray>>; }; declare const _default: { default: typeof buildTree }; export = _default;