Move item occurrences to canonical namespace
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Package itemevents normalizes merged D&D item-event candidates.
|
||||
package itemevents
|
||||
// Package itemoccurrences normalizes merged D&D item-occurrence candidates.
|
||||
package itemoccurrences
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -10,15 +10,15 @@ import (
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
|
||||
itemeventmodel "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/itemevents"
|
||||
itemoccurrencemodel "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/itemoccurrences"
|
||||
itemregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/items/registry"
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared"
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
|
||||
)
|
||||
|
||||
const (
|
||||
Key = "dnd/item-events"
|
||||
normalizationPolicy = "dnd.item_events.normalize.v1"
|
||||
Key = "dnd/item-occurrences"
|
||||
normalizationPolicy = "dnd.item_occurrences.normalize.v1"
|
||||
NormalizationPolicy = normalizationPolicy
|
||||
|
||||
ReasonCodeNameCanonicalized = "item_occurrence_name_canonicalized"
|
||||
@@ -111,7 +111,7 @@ func (n *Normalizer) Normalize(ctx context.Context, req contracts.TypedNormalize
|
||||
}
|
||||
|
||||
type normalizedRecord struct {
|
||||
event dnd.ItemOccurrence
|
||||
occurrence dnd.ItemOccurrence
|
||||
inputIndex int
|
||||
}
|
||||
|
||||
@@ -122,44 +122,44 @@ func normalizeList(input dnd.ItemOccurrenceList, index source.DocumentIndex, ord
|
||||
|
||||
records := make([]normalizedRecord, len(input.Occurrences))
|
||||
warnings := make([]contracts.Warning, 0)
|
||||
for index, inputEvent := range input.Occurrences {
|
||||
event, changedFields, found, refsChanged := normalizeEvent(inputEvent, order, registry)
|
||||
records[index] = normalizedRecord{event: event, inputIndex: index}
|
||||
for index, inputOccurrence := range input.Occurrences {
|
||||
occurrence, changedFields, found, refsChanged := normalizeOccurrence(inputOccurrence, order, registry)
|
||||
records[index] = normalizedRecord{occurrence: occurrence, inputIndex: index}
|
||||
if len(changedFields) != 0 {
|
||||
warnings = append(warnings, contracts.Warning{
|
||||
Scope: eventScope(index),
|
||||
Scope: occurrenceScope(index),
|
||||
ReasonCode: ReasonCodeNameCanonicalized,
|
||||
Message: fmt.Sprintf("input index %d: normalized display whitespace in %s", index,
|
||||
diagnostics.Aggregate("fields", changedFields)),
|
||||
})
|
||||
}
|
||||
if found && inputEvent.Name != event.Name {
|
||||
warnings = append(warnings, contracts.Warning{Scope: eventScope(index), ReasonCode: ReasonCodeNameCanonicalized,
|
||||
Message: fmt.Sprintf("input index %d: item name canonicalized from %s to %s", index, diagnostics.Quote(inputEvent.Name), diagnostics.Quote(event.Name))})
|
||||
if found && inputOccurrence.Name != occurrence.Name {
|
||||
warnings = append(warnings, contracts.Warning{Scope: occurrenceScope(index), ReasonCode: ReasonCodeNameCanonicalized,
|
||||
Message: fmt.Sprintf("input index %d: item name canonicalized from %s to %s", index, diagnostics.Quote(inputOccurrence.Name), diagnostics.Quote(occurrence.Name))})
|
||||
}
|
||||
if !found {
|
||||
warnings = append(warnings, contracts.Warning{Scope: eventScope(index), ReasonCode: ReasonCodeUnknownItemID,
|
||||
Message: fmt.Sprintf("input index %d: item ID %s is not in the supplied registry", index, diagnostics.Quote(inputEvent.ItemID))})
|
||||
warnings = append(warnings, contracts.Warning{Scope: occurrenceScope(index), ReasonCode: ReasonCodeUnknownItemID,
|
||||
Message: fmt.Sprintf("input index %d: item ID %s is not in the supplied registry", index, diagnostics.Quote(inputOccurrence.ItemID))})
|
||||
}
|
||||
if refsChanged {
|
||||
warnings = append(warnings, contracts.Warning{
|
||||
Scope: eventScope(index),
|
||||
Scope: occurrenceScope(index),
|
||||
ReasonCode: ReasonCodeSourceRefsNormalized,
|
||||
Message: fmt.Sprintf("input index %d: source references normalized (original count %d, final count %d)",
|
||||
index, len(inputEvent.SourceRefs), len(event.SourceRefs)),
|
||||
index, len(inputOccurrence.SourceRefs), len(occurrence.SourceRefs)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
sort.SliceStable(records, func(left, right int) bool {
|
||||
return itemeventmodel.Less(order, records[left].event, records[right].event)
|
||||
return itemoccurrencemodel.Less(order, records[left].occurrence, records[right].occurrence)
|
||||
})
|
||||
for position, record := range records {
|
||||
if position == record.inputIndex {
|
||||
continue
|
||||
}
|
||||
warnings = append(warnings, contracts.Warning{
|
||||
Scope: eventScope(record.inputIndex),
|
||||
Scope: occurrenceScope(record.inputIndex),
|
||||
ReasonCode: ReasonCodeOccurrencesReordered,
|
||||
Message: fmt.Sprintf("input index %d moved to normalized position %d", record.inputIndex, position),
|
||||
})
|
||||
@@ -170,8 +170,8 @@ func normalizeList(input dnd.ItemOccurrenceList, index source.DocumentIndex, ord
|
||||
return dnd.ItemOccurrenceList{Occurrences: output}, diagnostics.LimitWarnings(warnings, "item_occurrences", ReasonCodeWarningsOmitted)
|
||||
}
|
||||
|
||||
func normalizeEvent(input dnd.ItemOccurrence, order shared.SourceRefOrder, registry *itemregistry.Registry) (dnd.ItemOccurrence, []string, bool, bool) {
|
||||
output := cloneEvent(input)
|
||||
func normalizeOccurrence(input dnd.ItemOccurrence, order shared.SourceRefOrder, registry *itemregistry.Registry) (dnd.ItemOccurrence, []string, bool, bool) {
|
||||
output := cloneOccurrence(input)
|
||||
canonical, found := registry.LookupID(input.ItemID)
|
||||
if found {
|
||||
output.Name = canonical.Name
|
||||
@@ -184,17 +184,17 @@ func normalizeEvent(input dnd.ItemOccurrence, order shared.SourceRefOrder, regis
|
||||
{name: "from", value: &output.From},
|
||||
{name: "to", value: &output.To},
|
||||
} {
|
||||
trimmed := itemeventmodel.DisplayValue(*field.value)
|
||||
trimmed := itemoccurrencemodel.DisplayValue(*field.value)
|
||||
if *field.value != trimmed {
|
||||
*field.value = trimmed
|
||||
changedFields = append(changedFields, field.name)
|
||||
}
|
||||
}
|
||||
output.SourceRefs = order.Canonicalize(input.SourceRefs)
|
||||
return output, changedFields, found, !itemeventmodel.SourceRefsEqual(input.SourceRefs, output.SourceRefs)
|
||||
return output, changedFields, found, !itemoccurrencemodel.SourceRefsEqual(input.SourceRefs, output.SourceRefs)
|
||||
}
|
||||
|
||||
func cloneEvent(input dnd.ItemOccurrence) dnd.ItemOccurrence {
|
||||
func cloneOccurrence(input dnd.ItemOccurrence) dnd.ItemOccurrence {
|
||||
output := input
|
||||
if input.Quantity != nil {
|
||||
quantity := *input.Quantity
|
||||
@@ -220,11 +220,11 @@ func collapseDuplicates(records []normalizedRecord, index source.DocumentIndex,
|
||||
groups := make([]duplicateGroup, 0)
|
||||
groupByKey := make(map[string]int)
|
||||
for recordIndex, record := range records {
|
||||
if !itemeventmodel.ValidSourceRefs(index, record.event.SourceRefs) {
|
||||
if !itemoccurrencemodel.ValidSourceRefs(index, record.occurrence.SourceRefs) {
|
||||
keep[recordIndex] = true
|
||||
continue
|
||||
}
|
||||
key := itemeventmodel.ExactIdentity(order, record.event)
|
||||
key := itemoccurrencemodel.ExactIdentity(order, record.occurrence)
|
||||
groupIndex, exists := groupByKey[key]
|
||||
if !exists {
|
||||
groupByKey[key] = len(groups)
|
||||
@@ -238,7 +238,7 @@ func collapseDuplicates(records []normalizedRecord, index source.DocumentIndex,
|
||||
output := make([]dnd.ItemOccurrence, 0, len(records))
|
||||
for recordIndex, record := range records {
|
||||
if keep[recordIndex] {
|
||||
output = append(output, cloneEvent(record.event))
|
||||
output = append(output, cloneOccurrence(record.occurrence))
|
||||
}
|
||||
}
|
||||
warnings := make([]contracts.Warning, 0)
|
||||
@@ -256,14 +256,14 @@ func duplicateWarning(retainedIndex int, removed []int) contracts.Warning {
|
||||
issues[index] = fmt.Sprintf("removed input index %d", removedIndex)
|
||||
}
|
||||
return contracts.Warning{
|
||||
Scope: eventScope(retainedIndex),
|
||||
Scope: occurrenceScope(retainedIndex),
|
||||
ReasonCode: ReasonCodeDuplicateCollapsed,
|
||||
Message: diagnostics.Aggregate(
|
||||
fmt.Sprintf("duplicate item occurrence collapsed; retained input index %d", retainedIndex), issues),
|
||||
}
|
||||
}
|
||||
|
||||
func eventScope(index int) string { return fmt.Sprintf("occurrences[%d]", index) }
|
||||
func occurrenceScope(index int) string { return fmt.Sprintf("occurrences[%d]", index) }
|
||||
|
||||
func ModuleSpec() pipeline.ModuleSpec {
|
||||
return pipeline.ModuleSpec{
|
||||
@@ -1,4 +1,4 @@
|
||||
package itemevents
|
||||
package itemoccurrences
|
||||
|
||||
import (
|
||||
"context"
|
||||
Reference in New Issue
Block a user