Preserve tier sequence operations in source history
This commit is contained in:
76
internal/engine/sequence_history_projection.go
Normal file
76
internal/engine/sequence_history_projection.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package engine
|
||||
|
||||
import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
||||
|
||||
// projectTierHistoryApplications composes each strict source's local projection
|
||||
// with the tier operation. The retained source values stay in authored coordinates.
|
||||
func projectTierHistoryApplications(applications []historyApplication, operations []sequenceHistoryContribution) []historyApplication {
|
||||
mapped := false
|
||||
for _, operation := range operations {
|
||||
mapped = mapped || operation.mode == sequenceHistoryMapped
|
||||
}
|
||||
if !mapped {
|
||||
return applications
|
||||
}
|
||||
projections := indexSequenceHistoryContributions(operations)
|
||||
projected := cloneHistoryApplications(applications)
|
||||
for index, original := range applications {
|
||||
application := &projected[index]
|
||||
if path, found := projectSequenceHistoryPath(original.path, projections); found {
|
||||
application.path = path
|
||||
}
|
||||
for sequenceIndex, source := range original.sequences {
|
||||
container := appendDestination(original.path, source.path)
|
||||
operation, active := projections[container.String()]
|
||||
if !active || operation.mode != sequenceHistoryMapped {
|
||||
continue
|
||||
}
|
||||
value, found := documentAtPath(original.value, source.path)
|
||||
if !found || value.Kind != document.Sequence {
|
||||
continue
|
||||
}
|
||||
sourceIndex := application.sequencesByPath[source.path.String()]
|
||||
contribution := sequenceHistoryContribution{path: source.path.clone(), mode: sequenceHistoryMapped}
|
||||
for inputIndex := range value.Sequence {
|
||||
tierIndex := source.offset + inputIndex
|
||||
if source.mode == sequenceHistoryMapped {
|
||||
tierIndex = sourceIndex.outputForInput(inputIndex)
|
||||
}
|
||||
outputIndex, present := operation.projection.outputForInput(tierIndex)
|
||||
if !present {
|
||||
continue
|
||||
}
|
||||
contribution.items = append(contribution.items, sequenceItemProjection{inputIndex: inputIndex, outputIndex: outputIndex})
|
||||
if _, replaced := operation.replacedOutputs[outputIndex]; replaced {
|
||||
// Upsert replacements retain their lower-list position.
|
||||
contribution.replacements = append(contribution.replacements, sequenceItemReplacement{
|
||||
lowerIndex: outputIndex, higherIndex: inputIndex, outputIndex: outputIndex,
|
||||
})
|
||||
}
|
||||
}
|
||||
application.sequences[sequenceIndex] = contribution
|
||||
}
|
||||
application.sequencesByPath = indexSequenceHistoryContributions(application.sequences)
|
||||
}
|
||||
return projected
|
||||
}
|
||||
|
||||
func projectSequenceHistoryPath(path Path, projections map[string]sequenceHistoryContributionIndex) (Path, bool) {
|
||||
projected := path.clone()
|
||||
for index, segment := range path.segments {
|
||||
if segment.kind != pathSegmentIndex {
|
||||
continue
|
||||
}
|
||||
prefix := Path{segments: path.segments[:index]}
|
||||
operation, found := projections[prefix.String()]
|
||||
if !found || operation.mode != sequenceHistoryMapped {
|
||||
continue
|
||||
}
|
||||
outputIndex, found := operation.projection.outputForInput(segment.index)
|
||||
if !found {
|
||||
return Path{}, false
|
||||
}
|
||||
projected.segments[index].index = outputIndex
|
||||
}
|
||||
return projected, true
|
||||
}
|
||||
Reference in New Issue
Block a user