Index mappings while assembling configuration reports

This commit is contained in:
2026-10-12 00:14:20 +00:00
parent 7bf89e9b56
commit 98c9c3f00d
3 changed files with 49 additions and 17 deletions

View File

@@ -56,7 +56,13 @@ func decodeJSONPointer(pointer string) ([]string, error) {
return parts, nil
}
func placeYAMLValue(category *yaml.Node, path []string, value *yaml.Node) (*yaml.Node, error) {
// yamlValuePlacer indexes each mapping once while assembling one report.
// Content remains the ordered representation used by the YAML encoder.
type yamlValuePlacer struct {
keys map[*yaml.Node]map[string]int
}
func (placer *yamlValuePlacer) placeValue(category *yaml.Node, path []string, value *yaml.Node) (*yaml.Node, error) {
if value == nil {
return nil, fmt.Errorf("place YAML value: value node is nil")
}
@@ -69,18 +75,21 @@ func placeYAMLValue(category *yaml.Node, path []string, value *yaml.Node) (*yaml
current := category
for index, token := range path {
keyIndex := mappingKeyIndex(current, token)
keys := placer.mappingKeys(current)
keyIndex, exists := keys[token]
if index == len(path)-1 {
if keyIndex >= 0 {
if exists {
current.Content[keyIndex+1] = value
} else {
keys[token] = len(current.Content)
current.Content = append(current.Content, stringKey(token), value)
}
return category, nil
}
if keyIndex < 0 {
if !exists {
child := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
keys[token] = len(current.Content)
current.Content = append(current.Content, stringKey(token), child)
current = child
continue
@@ -95,14 +104,24 @@ func placeYAMLValue(category *yaml.Node, path []string, value *yaml.Node) (*yaml
return category, nil
}
func mappingKeyIndex(mapping *yaml.Node, key string) int {
func (placer *yamlValuePlacer) mappingKeys(mapping *yaml.Node) map[string]int {
if keys, exists := placer.keys[mapping]; exists {
return keys
}
if placer.keys == nil {
placer.keys = make(map[*yaml.Node]map[string]int)
}
keys := make(map[string]int, len(mapping.Content)/2)
for index := 0; index+1 < len(mapping.Content); index += 2 {
candidate := mapping.Content[index]
if candidate.Kind == yaml.ScalarNode && candidate.Tag == "!!str" && candidate.Value == key {
return index
if candidate.Kind == yaml.ScalarNode && candidate.Tag == "!!str" {
if _, exists := keys[candidate.Value]; !exists {
keys[candidate.Value] = index
}
}
}
return -1
placer.keys[mapping] = keys
return keys
}
func stringKey(value string) *yaml.Node {
@@ -122,6 +141,7 @@ func pointerFromTokens(tokens []string) string {
}
func renderDiffReport(differences []configkit.Difference) ([]byte, error) {
var placer yamlValuePlacer
additions := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
changes := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
deletions := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
@@ -138,7 +158,7 @@ func renderDiffReport(differences []configkit.Difference) ([]byte, error) {
if err != nil {
return nil, fmt.Errorf("render addition at %q: %w", path, err)
}
additions, err = placeYAMLValue(additions, tokens, value)
additions, err = placer.placeValue(additions, tokens, value)
if err != nil {
return nil, fmt.Errorf("render addition at %q: %w", path, err)
}
@@ -151,7 +171,7 @@ func renderDiffReport(differences []configkit.Difference) ([]byte, error) {
if err != nil {
return nil, fmt.Errorf("render change at %q: %w", path, err)
}
changes, err = placeYAMLValue(changes, tokens, value)
changes, err = placer.placeValue(changes, tokens, value)
if err != nil {
return nil, fmt.Errorf("render change at %q: %w", path, err)
}