Share recursive mapping merge across configuration assembly
This commit is contained in:
45
internal/engine/recursive_merge.go
Normal file
45
internal/engine/recursive_merge.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package engine
|
||||
|
||||
import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
||||
|
||||
// recursiveMergeHooks lets an assembly owner account for the values changed by
|
||||
// a recursive mapping overlay without making source roles part of the merge.
|
||||
// Hooks run before replacement and receive the still-owned incoming subtree.
|
||||
type recursiveMergeHooks struct {
|
||||
added func(Path, *document.Node)
|
||||
combined func(Path, *document.Node)
|
||||
replaced func(Path, *document.Node, *document.Node)
|
||||
}
|
||||
|
||||
// mergeRecursiveMappings changes an owned mapping and never aliases incoming
|
||||
// values into it. Entry order follows the target, then new incoming entries.
|
||||
func mergeRecursiveMappings(target, incoming *document.Node, current Path, index *mappingIndex, hooks recursiveMergeHooks) {
|
||||
for _, entry := range incoming.Mapping {
|
||||
path := current.Key(entry.Key)
|
||||
position := index.find(target, entry.Key)
|
||||
if position < 0 {
|
||||
cloned := entry
|
||||
cloned.Value = document.Clone(entry.Value)
|
||||
index.append(target, cloned)
|
||||
if hooks.added != nil {
|
||||
hooks.added(path, entry.Value)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
existing := target.Mapping[position].Value
|
||||
if existing.Kind == document.Mapping && entry.Value.Kind == document.Mapping {
|
||||
if hooks.combined != nil {
|
||||
hooks.combined(path, entry.Value)
|
||||
}
|
||||
mergeRecursiveMappings(existing, entry.Value, path, index, hooks)
|
||||
continue
|
||||
}
|
||||
|
||||
if hooks.replaced != nil {
|
||||
hooks.replaced(path, existing, entry.Value)
|
||||
}
|
||||
target.Mapping[position] = entry
|
||||
target.Mapping[position].Value = document.Clone(entry.Value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user