package engine import ( "sort" "gitea.maximumdirect.net/eric/ConfigKit/internal/document" ) type pairedDiffSnapshot struct { left *document.Node right *document.Node leftRedacted bool rightRedacted bool requiresFallback bool } func preparePairedDiffSnapshot(left, right *document.Node, path Path, sensitivity *diffSensitivity) (pairedDiffSnapshot, bool) { paired, supported := preparePairedDiffNodes(left, right, path, sensitivity) if !supported || !paired.requiresFallback { return paired, supported } return pairedDiffSnapshot{ left: redactedDiffNode(left), right: redactedDiffNode(right), leftRedacted: left != nil, rightRedacted: right != nil, }, true } func preparePairedDiffNodes(left, right *document.Node, path Path, sensitivity *diffSensitivity) (pairedDiffSnapshot, bool) { if left == nil && right == nil { return pairedDiffSnapshot{}, true } if sensitivity.isSensitiveAtOrAbove(path.String()) { return pairedDiffSnapshot{ left: redactedDiffNode(left), right: redactedDiffNode(right), leftRedacted: left != nil, rightRedacted: right != nil, }, true } if left != nil && right != nil && left.Kind != right.Kind { if sensitivity.hasStrictDescendant(path.String()) { return pairedDiffSnapshot{requiresFallback: true}, true } return pairedDiffSnapshot{left: left, right: right}, true } kind := document.Null if left != nil { kind = left.Kind } else if right != nil { kind = right.Kind } switch kind { case document.Mapping: return preparePairedDiffMapping(left, right, path, sensitivity) case document.Sequence: return preparePairedDiffSequence(left, right, path, sensitivity) default: if sensitivity.hasStrictDescendant(path.String()) { return pairedDiffSnapshot{requiresFallback: true}, true } return pairedDiffSnapshot{left: left, right: right}, true } } func preparePairedDiffMapping(left, right *document.Node, path Path, sensitivity *diffSensitivity) (pairedDiffSnapshot, bool) { leftEntries := diffMappingEntries(left) rightEntries := diffMappingEntries(right) keys := make([]string, 0, len(leftEntries)+len(rightEntries)) seen := make(map[string]struct{}, len(leftEntries)+len(rightEntries)) for key := range leftEntries { seen[key] = struct{}{} keys = append(keys, key) } for key := range rightEntries { if _, found := seen[key]; found { continue } keys = append(keys, key) } sort.Strings(keys) var leftCopy, rightCopy *document.Node if left != nil { copy := *left copy.Mapping = make([]document.Entry, 0, len(left.Mapping)) leftCopy = © } if right != nil { copy := *right copy.Mapping = make([]document.Entry, 0, len(right.Mapping)) rightCopy = © } redacted := pairedDiffSnapshot{} for _, key := range keys { leftEntry, leftPresent := leftEntries[key] rightEntry, rightPresent := rightEntries[key] var leftChild, rightChild *document.Node if leftPresent { leftChild = leftEntry.Value } if rightPresent { rightChild = rightEntry.Value } child, supported := preparePairedDiffNodes(leftChild, rightChild, path.Key(key), sensitivity) if !supported { return pairedDiffSnapshot{}, false } if child.requiresFallback { return pairedDiffSnapshot{requiresFallback: true}, true } if leftPresent { leftEntry.Value = child.left leftCopy.Mapping = append(leftCopy.Mapping, leftEntry) } if rightPresent { rightEntry.Value = child.right rightCopy.Mapping = append(rightCopy.Mapping, rightEntry) } redacted.leftRedacted = redacted.leftRedacted || child.leftRedacted redacted.rightRedacted = redacted.rightRedacted || child.rightRedacted } redacted.left = leftCopy redacted.right = rightCopy return redacted, true } func preparePairedDiffSequence(left, right *document.Node, path Path, sensitivity *diffSensitivity) (pairedDiffSnapshot, bool) { var leftCopy, rightCopy *document.Node if left != nil { copy := *left copy.Sequence = make([]*document.Node, len(left.Sequence)) leftCopy = © } if right != nil { copy := *right copy.Sequence = make([]*document.Node, len(right.Sequence)) rightCopy = © } length := 0 if left != nil { length = len(left.Sequence) } if right != nil && len(right.Sequence) > length { length = len(right.Sequence) } result := pairedDiffSnapshot{left: leftCopy, right: rightCopy} for index := 0; index < length; index++ { var leftChild, rightChild *document.Node if left != nil && index < len(left.Sequence) { leftChild = left.Sequence[index] } if right != nil && index < len(right.Sequence) { rightChild = right.Sequence[index] } child, supported := preparePairedDiffNodes(leftChild, rightChild, path.Index(index), sensitivity) if !supported { return pairedDiffSnapshot{}, false } if child.requiresFallback { return pairedDiffSnapshot{requiresFallback: true}, true } if left != nil && index < len(left.Sequence) { leftCopy.Sequence[index] = child.left } if right != nil && index < len(right.Sequence) { rightCopy.Sequence[index] = child.right } result.leftRedacted = result.leftRedacted || child.leftRedacted result.rightRedacted = result.rightRedacted || child.rightRedacted } return result, true } func diffMappingEntries(node *document.Node) map[string]document.Entry { entries := make(map[string]document.Entry) if node == nil { return entries } for _, entry := range node.Mapping { entries[entry.Key] = entry } return entries } func redactedDiffNode(node *document.Node) *document.Node { if node == nil { return nil } return &document.Node{Kind: document.String, Text: "[REDACTED]"} }