67 lines
1.8 KiB
Go
67 lines
1.8 KiB
Go
package configkit
|
|
|
|
import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
|
|
|
// walkDocument visits value nodes in preorder, preserving stored mapping order
|
|
// and sequence index order. Mapping keys are not separate nodes in this walk.
|
|
// The callback borrows paths and nodes; clone any mutable state it retains.
|
|
// Specialized origin, pruning, and budget traversals retain their own semantics.
|
|
func walkDocument(node *document.Node, path Path, visit func(Path, *document.Node)) {
|
|
if node == nil {
|
|
return
|
|
}
|
|
visit(path, node)
|
|
switch node.Kind {
|
|
case document.Mapping:
|
|
for _, entry := range node.Mapping {
|
|
walkDocument(entry.Value, path.Key(entry.Key), visit)
|
|
}
|
|
case document.Sequence:
|
|
for index, child := range node.Sequence {
|
|
walkDocument(child, path.Index(index), visit)
|
|
}
|
|
}
|
|
}
|
|
|
|
// indexDocument borrows nodes from its caller-owned tree.
|
|
func indexDocument(node *document.Node, path Path, index map[string]*document.Node) {
|
|
walkDocument(node, path, func(path Path, node *document.Node) {
|
|
index[path.String()] = node
|
|
})
|
|
}
|
|
|
|
func documentAtPath(root *document.Node, path Path) (*document.Node, bool) {
|
|
if root == nil || !path.valid() {
|
|
return nil, false
|
|
}
|
|
current := root
|
|
for _, segment := range path.segments {
|
|
switch current.Kind {
|
|
case document.Mapping:
|
|
if segment.kind == pathSegmentIndex {
|
|
return nil, false
|
|
}
|
|
found := false
|
|
for _, entry := range current.Mapping {
|
|
if entry.Key == segment.key {
|
|
current = entry.Value
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return nil, false
|
|
}
|
|
case document.Sequence:
|
|
index, ok := schemaIndex(segment)
|
|
if !ok || index >= len(current.Sequence) {
|
|
return nil, false
|
|
}
|
|
current = current.Sequence[index]
|
|
default:
|
|
return nil, false
|
|
}
|
|
}
|
|
return current, true
|
|
}
|