jasc
Version:
Jasc Another Service Container
75 lines (66 loc) • 3.08 kB
text/typescript
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
}
}
}