77 lines
2.9 KiB
Go
77 lines
2.9 KiB
Go
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
|
|
}
|