2024-09-24 18:32:50 +02:00
|
|
|
export enum WalkAction {
|
|
|
|
|
// Continue walking the tree. Default behavior.
|
|
|
|
|
Continue,
|
|
|
|
|
|
|
|
|
|
// Skip walking into the current node.
|
|
|
|
|
Skip,
|
|
|
|
|
|
|
|
|
|
// Stop walking the tree entirely.
|
|
|
|
|
Stop,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface Walkable<T> {
|
|
|
|
|
each(cb: (node: T, index: number) => void): void
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Custom walk implementation where we can skip going into nodes when we don't
|
|
|
|
|
// need to process them.
|
2024-11-07 13:04:52 +01:00
|
|
|
export function walk<T>(
|
|
|
|
|
rule: Walkable<T>,
|
|
|
|
|
cb: (rule: T, idx: number, parent: Walkable<T>) => void | WalkAction,
|
|
|
|
|
): undefined | false {
|
2024-09-24 18:32:50 +02:00
|
|
|
let result: undefined | false = undefined
|
|
|
|
|
|
2024-11-07 13:04:52 +01:00
|
|
|
rule.each?.((node, idx) => {
|
|
|
|
|
let action = cb(node, idx, rule) ?? WalkAction.Continue
|
2024-09-24 18:32:50 +02:00
|
|
|
if (action === WalkAction.Stop) {
|
|
|
|
|
result = false
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
if (action !== WalkAction.Skip) {
|
|
|
|
|
result = walk(node as Walkable<T>, cb)
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Depth first walk reversal implementation.
|
|
|
|
|
export function walkDepth<T>(rule: Walkable<T>, cb: (rule: T) => void) {
|
|
|
|
|
rule?.each?.((node) => {
|
|
|
|
|
walkDepth(node as Walkable<T>, cb)
|
|
|
|
|
cb(node)
|
|
|
|
|
})
|
|
|
|
|
}
|