package engine import ( "slices" "sort" ) type historySelection struct { path Path phase historyPhase payload historyPayloadRef reportedPath Path role historyRole before bool after bool attribution historyAttribution hasAttribution bool previous []Origin } func (model *historyModel) selectHistory(path Path) []historySelection { if model == nil || !path.valid() || !model.hasObservedShape(path) { return nil } candidateSet := make(map[int]struct{}) for _, observationID := range model.observationsByPointer[path.String()] { candidateSet[observationID] = struct{}{} } model.reportedPathIndex.visitAncestors(path.String(), func(observationID int) { candidateSet[observationID] = struct{}{} }) candidates := make([]int, 0, len(candidateSet)) for observationID := range candidateSet { candidates = append(candidates, observationID) } slices.Sort(candidates) selections := make([]historySelection, 0, len(candidates)) selectionByPayload := make(map[historyPayloadRef]int) for _, observationID := range candidates { observation := model.observations[observationID] if observation.role == historyRoleInventory || !matchesPathShape(path, observation.path) { continue } selectionIndex, found := selectionByPayload[observation.payload] if !found { selectionIndex = len(selections) selectionByPayload[observation.payload] = selectionIndex selection := historySelection{ path: path.clone(), phase: observation.phase, payload: observation.payload, reportedPath: observation.reportedPath.clone(), role: observation.role, } if attribution, ok := model.resolveAttribution(observation.attributionRef); ok { selection.attribution = attribution selection.hasAttribution = true } selections = append(selections, selection) } selection := &selections[selectionIndex] selection.before = selection.before || observation.beforePresent selection.after = selection.after || observation.afterPresent } if len(selections) == 0 { return nil } var previous *Origin for index := range selections { selection := &selections[index] if selection.hasAttribution && metadataHistoryRole(selection.role) { if previous != nil { selection.previous = []Origin{cloneOrigin(*previous)} } origin := cloneOrigin(selection.attribution.origin) previous = &origin } } return selections } func (model *historyModel) hasObservedShape(path Path) bool { if model == nil || !path.valid() { return false } for _, candidate := range model.shapesByPointer[path.String()] { if matchesPathShape(path, candidate) { return true } } return false } func (model *historyModel) concreteShapes(pointer string) []Path { if model == nil { return nil } shapes := model.shapesByPointer[pointer] cloned := make([]Path, len(shapes)) for index, path := range shapes { cloned[index] = path.clone() } return cloned } func (model *historyModel) observedPaths() []Path { if model == nil { return nil } paths := make([]Path, len(model.shapeOrder)) for index, path := range model.shapeOrder { paths[index] = path.clone() } return paths } func (model *historyModel) historicalPaths() []Path { if model == nil { return nil } pointers := make([]string, 0, len(model.shapesByPointer)) for pointer := range model.shapesByPointer { pointers = append(pointers, pointer) } sort.Strings(pointers) paths := make([]Path, 0, len(pointers)) for _, pointer := range pointers { path, err := ParsePath(pointer) if err == nil { paths = append(paths, path) } } return paths } func (model *historyModel) resolveAttribution(ref historyAttributionRef) (historyAttribution, bool) { if model == nil || ref < 0 || int(ref) >= len(model.attributions) { return historyAttribution{}, false } attribution := model.attributions[ref] return historyAttribution{ origin: cloneOrigin(attribution.origin), reasons: append([]string(nil), attribution.reasons...), dependencies: clonePaths(attribution.dependencies), }, true } func metadataHistoryRole(role historyRole) bool { switch role { case historyRoleDefinition, historyRoleCompositeDefinition, historyRoleOperation, historyRoleControl: return true default: return false } }