1package kong
2
3import (
4	"fmt"
5)
6
7// Next should be called by Visitor to proceed with the walk.
8//
9// The walk will terminate if "err" is non-nil.
10type Next func(err error) error
11
12// Visitor can be used to walk all nodes in the model.
13type Visitor func(node Visitable, next Next) error
14
15// Visit all nodes.
16func Visit(node Visitable, visitor Visitor) error {
17	return visitor(node, func(err error) error {
18		if err != nil {
19			return err
20		}
21		switch node := node.(type) {
22		case *Application:
23			return visitNodeChildren(node.Node, visitor)
24		case *Node:
25			return visitNodeChildren(node, visitor)
26		case *Value:
27		case *Flag:
28			return Visit(node.Value, visitor)
29		default:
30			panic(fmt.Sprintf("unsupported node type %T", node))
31		}
32		return nil
33	})
34}
35
36func visitNodeChildren(node *Node, visitor Visitor) error {
37	if node.Argument != nil {
38		if err := Visit(node.Argument, visitor); err != nil {
39			return err
40		}
41	}
42	for _, flag := range node.Flags {
43		if err := Visit(flag, visitor); err != nil {
44			return err
45		}
46	}
47	for _, pos := range node.Positional {
48		if err := Visit(pos, visitor); err != nil {
49			return err
50		}
51	}
52	for _, child := range node.Children {
53		if err := Visit(child, visitor); err != nil {
54			return err
55		}
56	}
57	return nil
58}
59