194 lines
5.5 KiB
Go
194 lines
5.5 KiB
Go
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]"}
|
|
}
|