package engine import ( "slices" "gitea.maximumdirect.net/eric/ConfigKit/internal/document" ) // Retain source history at original paths. Structural operations are held once // per relationship and projected onto a requested destination path only when // History or Explain is queried. func applyInheritanceMetadata(metadata *Metadata, raw *document.Node, rawOrigins map[string]Origin, overlays []overlayRecord, expansion *inheritanceScope) { if metadata == nil || expansion == nil { return } sourceView := Metadata{ fields: make(map[string]FieldInfo), history: metadata.history, } walkDocument(raw, Path{}, func(path Path, node *document.Node) { origin, found := rawOrigins[path.String()] if !found { origin = Origin{Layer: LayerBase, Locations: []Location{publicLocation(node.Location)}} } sourceView.fields[path.String()] = FieldInfo{Explicit: true, Null: node.Kind == document.Null, Origin: cloneOrigin(origin)} }) applyOverlayMetadata(&sourceView, overlays) metadata.history = sourceView.history } func historyWithInheritance(path Path, stored []Change, operations []inheritanceOperation) []Change { split := len(stored) for index, change := range stored { if change.Origin.Layer == LayerCLI || change.Origin.Layer == LayerResolution { split = index break } } history := cloneChanges(stored[:split]) for _, operation := range operations { for _, change := range projectedInheritanceChanges(path, operation) { if len(history) != 0 { change.Previous = []Origin{cloneOrigin(history[len(history)-1].Origin)} } history = append(history, change) } } for _, change := range stored[split:] { cloned := cloneChange(change) if len(history) != 0 { cloned.Previous = []Origin{cloneOrigin(history[len(history)-1].Origin)} } history = append(history, cloned) } return history } func projectedInheritanceChanges(query Path, operation inheritanceOperation) []Change { return inheritanceChangesForQuery(query, operation) } func transferredOperationOrigin(operation inheritanceOperation, destination Path) (Origin, bool) { if inheritanceOperationIdentity(operation, destination) { return Origin{}, false } relative, ok := relativeHistoryPath(operation.transfer.to, destination) if !ok { return Origin{}, false } source := appendInheritancePath(operation.transfer.from, relative) origin, found := operation.parentOrigins[source.String()] if !found { return Origin{}, false } transferred := transferredInheritanceOrigins(map[string]Origin{source.String(): origin}, operation.transfer.from, operation.transfer.to, *operation.transfer) return transferred[destination.String()], true } func inheritanceOperationIdentity(operation inheritanceOperation, path Path) bool { if operation.transfer == nil || len(operation.identityFields) == 0 { return false } relative, within := relativeHistoryPath(operation.transfer.to, path) return within && len(relative.segments) != 0 && relative.segments[0].kind != pathSegmentIndex && slices.Contains(operation.identityFields, relative.segments[0].key) }