From 7197fb350b436bc2ad8043898602635e7bd05797 Mon Sep 17 00:00:00 2001 From: hkfires <10558748+hkfires@users.noreply.github.com> Date: Sun, 8 Feb 2026 19:05:52 +0800 Subject: [PATCH] fix(config): prune default descendants when merging new yaml nodes --- internal/config/config.go | 44 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 64508ae5..fec58fe5 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1125,10 +1125,12 @@ func mergeMappingPreserve(dst, src *yaml.Node, path ...[]string) { mergeNodePreserve(dv, sv, childPath) } else { // New key: only add if value is non-zero and not a known default - if isKnownDefaultValue(childPath, sv) { + candidate := deepCopyNode(sv) + pruneKnownDefaultsInNewNode(childPath, candidate) + if isKnownDefaultValue(childPath, candidate) { continue } - dst.Content = append(dst.Content, deepCopyNode(sk), deepCopyNode(sv)) + dst.Content = append(dst.Content, deepCopyNode(sk), candidate) } } } @@ -1265,6 +1267,44 @@ func isKnownDefaultValue(path []string, node *yaml.Node) bool { return false } +// pruneKnownDefaultsInNewNode removes default-valued descendants from a new node +// before it is appended into the destination YAML tree. +func pruneKnownDefaultsInNewNode(path []string, node *yaml.Node) { + if node == nil { + return + } + + switch node.Kind { + case yaml.MappingNode: + filtered := make([]*yaml.Node, 0, len(node.Content)) + for i := 0; i+1 < len(node.Content); i += 2 { + keyNode := node.Content[i] + valueNode := node.Content[i+1] + if keyNode == nil || valueNode == nil { + continue + } + + childPath := appendPath(path, keyNode.Value) + if isKnownDefaultValue(childPath, valueNode) { + continue + } + + pruneKnownDefaultsInNewNode(childPath, valueNode) + if (valueNode.Kind == yaml.MappingNode || valueNode.Kind == yaml.SequenceNode) && + len(valueNode.Content) == 0 { + continue + } + + filtered = append(filtered, keyNode, valueNode) + } + node.Content = filtered + case yaml.SequenceNode: + for _, child := range node.Content { + pruneKnownDefaultsInNewNode(path, child) + } + } +} + // isZeroValueNode returns true if the YAML node represents a zero/default value // that should not be written as a new key to preserve config cleanliness. // For mappings and sequences, recursively checks if all children are zero values.