Harden D&D scene description extraction
This commit is contained in:
@@ -78,6 +78,10 @@ func normalizeList(input dnd.SceneDescriptionList, doc *source.SourceDocument) (
|
||||
return dnd.SceneDescriptionList{}, fmt.Errorf("scenes must not be empty")
|
||||
}
|
||||
|
||||
unitPositions := make(map[int]int, len(doc.Units))
|
||||
for index, unit := range doc.Units {
|
||||
unitPositions[unit.ID] = index
|
||||
}
|
||||
output := dnd.SceneDescriptionList{Scenes: make([]dnd.SceneDescription, len(input.Scenes))}
|
||||
for index, scene := range input.Scenes {
|
||||
scene.Title = strings.TrimSpace(scene.Title)
|
||||
@@ -92,8 +96,8 @@ func normalizeList(input dnd.SceneDescriptionList, doc *source.SourceDocument) (
|
||||
}
|
||||
|
||||
sort.SliceStable(output.Scenes, func(left, right int) bool {
|
||||
leftStart, _ := source.UnitIndex(doc, output.Scenes[left].SourceRef.StartUnitID)
|
||||
rightStart, _ := source.UnitIndex(doc, output.Scenes[right].SourceRef.StartUnitID)
|
||||
leftStart := unitPositions[output.Scenes[left].SourceRef.StartUnitID]
|
||||
rightStart := unitPositions[output.Scenes[right].SourceRef.StartUnitID]
|
||||
if leftStart != rightStart {
|
||||
return leftStart < rightStart
|
||||
}
|
||||
@@ -103,6 +107,7 @@ func normalizeList(input dnd.SceneDescriptionList, doc *source.SourceDocument) (
|
||||
unique := make([]dnd.SceneDescription, 0, len(output.Scenes))
|
||||
byID := make(map[string]dnd.SceneDescription, len(output.Scenes))
|
||||
byRange := make(map[source.SourceRef]dnd.SceneDescription, len(output.Scenes))
|
||||
seen := make(map[dnd.SceneDescription]struct{}, len(output.Scenes))
|
||||
for _, scene := range output.Scenes {
|
||||
if previous, ok := byID[scene.ID]; ok && !identical(previous, scene) {
|
||||
return dnd.SceneDescriptionList{}, fmt.Errorf("scene ID %s has conflicting records", diagnostics.Quote(scene.ID))
|
||||
@@ -110,11 +115,12 @@ func normalizeList(input dnd.SceneDescriptionList, doc *source.SourceDocument) (
|
||||
if previous, ok := byRange[scene.SourceRef]; ok && !sameModelContent(previous, scene) {
|
||||
return dnd.SceneDescriptionList{}, fmt.Errorf("source range %s has conflicting records", sourceRefLabel(scene.SourceRef))
|
||||
}
|
||||
if containsIdentical(unique, scene) {
|
||||
if _, ok := seen[scene]; ok {
|
||||
continue
|
||||
}
|
||||
byID[scene.ID] = scene
|
||||
byRange[scene.SourceRef] = scene
|
||||
seen[scene] = struct{}{}
|
||||
unique = append(unique, scene)
|
||||
}
|
||||
output.Scenes = unique
|
||||
@@ -129,15 +135,6 @@ func sameModelContent(left, right dnd.SceneDescription) bool {
|
||||
return left.Kind == right.Kind && left.Title == right.Title && left.Summary == right.Summary
|
||||
}
|
||||
|
||||
func containsIdentical(scenes []dnd.SceneDescription, target dnd.SceneDescription) bool {
|
||||
for _, scene := range scenes {
|
||||
if identical(scene, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func sourceRefLabel(ref source.SourceRef) string {
|
||||
return fmt.Sprintf("%s:%d-%d", diagnostics.Quote(ref.SourceID), ref.StartUnitID, ref.EndUnitID)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user