Reuse document indexes in D&D normalization

This commit is contained in:
2026-07-25 13:01:31 +00:00
parent 97cdb01357
commit 8199d95dc1
10 changed files with 48 additions and 64 deletions

View File

@@ -110,8 +110,9 @@ func (n *Normalizer) Normalize(ctx context.Context, req contracts.TypedNormalize
if err != nil {
return contracts.TypedNormalizeResult[dnd.CombatTurnList]{}, normalizerErrorf("resolve NPC registry: %w", err)
}
order := shared.NewSourceRefOrder(req.Source)
value, warnings := normalizeList(req.MergeOutput.Value, req.Source, order, npcRegistry)
index := source.NewDocumentIndex(req.Source)
order := shared.NewSourceRefOrderWithIndex(req.Source, index)
value, warnings := normalizeList(req.MergeOutput.Value, index, order, npcRegistry)
return contracts.TypedNormalizeResult[dnd.CombatTurnList]{Value: value, Warnings: warnings}, nil
}
@@ -127,7 +128,7 @@ type actorCanonicalization struct {
to string
}
func normalizeList(input dnd.CombatTurnList, doc *source.SourceDocument, order shared.SourceRefOrder, registry *npcregistry.Registry) (dnd.CombatTurnList, []contracts.Warning) {
func normalizeList(input dnd.CombatTurnList, documentIndex source.DocumentIndex, order shared.SourceRefOrder, registry *npcregistry.Registry) (dnd.CombatTurnList, []contracts.Warning) {
if input.CombatTurns == nil {
return dnd.CombatTurnList{}, nil
}
@@ -182,7 +183,7 @@ func normalizeList(input dnd.CombatTurnList, doc *source.SourceDocument, order s
})
}
output, duplicateWarnings := collapseDuplicates(records, doc)
output, duplicateWarnings := collapseDuplicates(records, documentIndex)
warnings = append(warnings, duplicateWarnings...)
return dnd.CombatTurnList{CombatTurns: output}, warnings
}
@@ -200,8 +201,7 @@ func normalizeTurn(input dnd.CombatTurn, order shared.SourceRefOrder, registry *
actorChange = &actorCanonicalization{from: input.Actor, to: output.Actor}
}
canonicalRefs, _, _ := canonicalizeSourceRefs(order, input.SourceRefs)
output.SourceRefs = canonicalRefs
output.SourceRefs = order.Canonicalize(input.SourceRefs)
refsChanged := !sourceRefsEqual(input.SourceRefs, output.SourceRefs)
return output, actorChange, refsChanged
}
@@ -227,17 +227,12 @@ func sourceRefsEqual(left, right []source.SourceRef) bool {
return true
}
func canonicalizeSourceRefs(order shared.SourceRefOrder, input []source.SourceRef) ([]source.SourceRef, bool, int) {
canonical := order.Canonicalize(input)
return canonical, !sourceRefsEqual(input, canonical), len(input) - len(canonical)
}
type duplicateGroup struct {
retainedIndex int
removed []int
}
func collapseDuplicates(records []normalizedRecord, doc *source.SourceDocument) ([]dnd.CombatTurn, []contracts.Warning) {
func collapseDuplicates(records []normalizedRecord, documentIndex source.DocumentIndex) ([]dnd.CombatTurn, []contracts.Warning) {
if len(records) == 0 {
return make([]dnd.CombatTurn, 0), nil
}
@@ -246,7 +241,7 @@ func collapseDuplicates(records []normalizedRecord, doc *source.SourceDocument)
groups := make([]duplicateGroup, 0)
groupByKey := make(map[string]int)
for index, record := range records {
key, eligible := duplicateKey(record.turn, doc)
key, eligible := duplicateKey(record.turn, documentIndex)
if !eligible {
keep[index] = true
continue
@@ -278,12 +273,12 @@ func collapseDuplicates(records []normalizedRecord, doc *source.SourceDocument)
return output, warnings
}
func duplicateKey(turn dnd.CombatTurn, doc *source.SourceDocument) (string, bool) {
func duplicateKey(turn dnd.CombatTurn, documentIndex source.DocumentIndex) (string, bool) {
if len(turn.SourceRefs) == 0 {
return "", false
}
for _, ref := range turn.SourceRefs {
if source.ValidateRef(doc, ref) != nil {
if documentIndex.ValidateRef(ref) != nil {
return "", false
}
}