UNPKG

jasc

Version:

Jasc Another Service Container

75 lines (66 loc) 3.08 kB
type TraverserCallback = (node: Node, depth?: number) => boolean | void const _traverseChildren = (cb: TraverserCallback, node: Node, depth: number = 0): boolean => { const res = cb(node, depth) return typeof res === 'boolean' && res || [...node.children].some(n => _traverseChildren(cb, n, depth + 1)) } const _traverseParents = (cb: TraverserCallback, node: Node): boolean => { const res = cb(node) return typeof res === 'boolean' && res || [...node.parents].some(p => _traverseParents(cb, p)) } export interface Node<T = unknown> { key: string value?: T parents: Set<Node> children: Set<Node> traverseChildren: (cb: TraverserCallback, depth?: number) => boolean traverseParents: (cb: TraverserCallback) => boolean } export const createNode = <T = unknown>(key: string, parents: Array<Node>, value?: T): Node<T> => { const node = { key, value, parents: new Set(parents), children: new Set(), traverseChildren: function(this: Node<T>, cb: TraverserCallback, depth: number = 0) { return _traverseChildren(cb, this, depth)}, traverseParents: function(this: Node<T>, cb: TraverserCallback){ return [...this.parents].some(parent => _traverseParents(cb, parent))} } as Node<T> parents.forEach(parent => parent.children.add(node)) return node } export interface Tree { add: <T>(key: string, parent: Node | Node[] | null, value?: T) => Node<T> get: <T = unknown>(key: string) => Node<T> has: (key: string) => boolean getRoots: () => Node[] traverseRoots: (cb: TraverserCallback) => boolean dump: () => Tree } export const createTree = (): Tree => { const nodes: {[key: string]: Node} = {} return { get: <T = unknown>(key: string): Node<T> => nodes[key] as Node<T>, has: (key: string): boolean => nodes.hasOwnProperty(key), getRoots: (): Array<Node> => Object.values(nodes).filter((node: Node) => node.parents.size === 0), add: function<T>(this: Tree, key: string, parent: Node | Node[] | null, value?: T): Node<T> { if(this.has(key)) throw new Error(`Can't redefine property ${key}`) parent = parent || [] const parents = Array.isArray(parent) ? parent : [parent] return nodes[key] = createNode(key, parents, value) }, traverseRoots: function(this: Tree, cb: TraverserCallback): boolean { return this .getRoots() .some(root => root.traverseChildren(cb)) }, dump: function(this: Tree): Tree { this.traverseRoots((node, depth) => { if(depth === 0){ console.log(`┌ ${node.key} √ᴿᴼᴼᵀ`) return } console.log(`├${'─'.repeat(depth! > 1 ? depth!-2 : 0)}${depth! > 1 ? '└' : ''}${node.children.size > 0 ? '┬' : '─'} ${node.key}`) }) return this } } }