import Foundation enum RDAILocatorBuilder { static func makeLocator( document: RDAIDocumentDescriptor, snapshot: RDAIResourceSnapshot, range: RDAITextRange ) -> RDAILocator? { let matchingRuns = snapshot.locatorRuns.filter { $0.textRange.intersects(range) } guard let first = matchingRuns.first else { return nil } let anchor = mergedAnchor(matchingRuns) ?? first.anchor return RDAILocator( documentIdentifier: document.identifier, resourceIdentifier: snapshot.descriptor.identifier, textRange: range, anchor: anchor, sourceHash: snapshot.sourceHash ) } private static func mergedAnchor(_ runs: [RDAILocatorRun]) -> RDAIAnchor? { guard !runs.isEmpty else { return nil } let anchors = runs.compactMap { run -> RDAIPDFAnchor? in if case .pdf(let anchor) = run.anchor { return anchor } return nil } guard anchors.count == runs.count, let first = anchors.first, anchors.allSatisfy({ $0.pageIndex == first.pageIndex && $0.textSource == first.textSource }) else { return nil } var rects: [RDAINormalizedRect] = [] for rect in anchors.flatMap(\.rects) where !rects.contains(rect) { rects.append(rect) } let readingOrder = anchors.compactMap(\.readingOrder).min() return .pdf(RDAIPDFAnchor( pageIndex: first.pageIndex, rects: rects, textSource: first.textSource, readingOrder: readingOrder )) } }