UNPKG

@loken/hierarchies

Version:

Library for working with hierarchies of identifiers and identifiable objects.

78 lines (62 loc) 1.77 kB
import { type Some, LinearStack, LinearQueue } from '@loken/utilities'; import { GraphSignal } from './graph-signal.ts'; import type { GraphTraversal, SignalNodes, TraversalType, NextNodes } from './graph.types.ts'; /** * Flatten a graph of nodes by traversing the provided `roots` according to the options. */ export const flattenGraph = <TNode>(options: GraphTraversal<TNode>): TNode[] => { if (options.signal !== undefined) return flattenSignalGraph(options); else return flattenFullGraph(options); }; /** @internalexport */ export const flattenSignalGraph = <TNode>( options: { roots: Some<TNode>, signal: SignalNodes<TNode>, detectCycles?: boolean, type?: TraversalType }, ) => { const result: TNode[] = []; const signal = new GraphSignal<TNode>(options); const signalFn = options.signal; let res = signal.tryGetNext(); while (res[1]) { signalFn(res[0], signal); if (signal.shouldYield()) result.push(res[0]); signal.cleanup(); res = signal.tryGetNext(); } return result; }; /** @internalexport */ export const flattenFullGraph = <TNode>( options: { roots: Some<TNode>, next: NextNodes<TNode>, type?: TraversalType, detectCycles?: boolean, }, ) => { const result: TNode[] = []; const visited = options.detectCycles ? new Set<TNode>() : undefined; const store = options.type === 'depth-first' ? new LinearStack<TNode>() : new LinearQueue<TNode>(); store.attach(options.roots); const nextFn = options.next; while (store.count > 0) { const node = store.detach()!; if (visited?.has(node)) continue; visited?.add(node); result.push(node); const children = nextFn(node); if (children) store.attach(children); } return result; };