@@ -110,11 +110,8 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
110110 }
111111 }
112112
113- /// A link resolver that resolves references by finding them in path hierarchy.
114- ///
115- /// The link resolver is `nil` until some documentation content is registered with the context.
116- /// It's safe to access the link resolver during symbol registration and at later points in the registration and conversion.
117- var hierarchyBasedLinkResolver : PathHierarchyBasedLinkResolver ! = nil
113+ /// A class that resolves documentation links by orchestrating calls to other link resolver implementations.
114+ public var linkResolver = LinkResolver ( )
118115
119116 /// The provider of documentation bundles for this context.
120117 var dataProvider : DocumentationContextDataProvider
@@ -200,6 +197,8 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
200197 /// A list of non-topic links that can be resolved.
201198 var nodeAnchorSections = [ ResolvedTopicReference: AnchorSection] ( )
202199
200+ var externalCache = [ ResolvedTopicReference: LinkResolver . ExternalEntity] ( )
201+
203202 /// A list of all the problems that was encountered while registering and processing the documentation bundles in this context.
204203 public var problems : [ Problem ] {
205204 return diagnosticEngine. problems
@@ -361,7 +360,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
361360 /// - dataProvider: The provider that removed this bundle.
362361 /// - bundle: The bundle that was removed.
363362 public func dataProvider( _ dataProvider: DocumentationContextDataProvider , didRemoveBundle bundle: DocumentationBundle ) throws {
364- hierarchyBasedLinkResolver ? . unregisterBundle ( identifier: bundle. identifier)
363+ linkResolver . localResolver ? . unregisterBundle ( identifier: bundle. identifier)
365364
366365 // Purge the reference cache for this bundle and disable reference caching for
367366 // this bundle moving forward.
@@ -1153,7 +1152,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
11531152 var moduleReferences = [ String: ResolvedTopicReference] ( )
11541153
11551154 // Build references for all symbols in all of this module's symbol graphs.
1156- let symbolReferences = hierarchyBasedLinkResolver . referencesForSymbols ( in: symbolGraphLoader. unifiedGraphs, bundle: bundle, context: self )
1155+ let symbolReferences = linkResolver . localResolver . referencesForSymbols ( in: symbolGraphLoader. unifiedGraphs, bundle: bundle, context: self )
11571156
11581157 // Set the index and cache storage capacity to avoid ad-hoc storage resizing.
11591158 symbolIndex. reserveCapacity ( symbolReferences. count)
@@ -1270,7 +1269,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
12701269 // Only add the symbol mapping now if the path hierarchy based resolver is the main implementation.
12711270 // If it is only used for mismatch checking then we must wait until the documentation cache code path has traversed and updated all the colliding nodes.
12721271 // Otherwise the mappings will save the unmodified references and the hierarchy based resolver won't find the expected parent nodes when resolving links.
1273- hierarchyBasedLinkResolver . addMappingForSymbols ( symbolIndex: symbolIndex)
1272+ linkResolver . localResolver . addMappingForSymbols ( symbolIndex: symbolIndex)
12741273
12751274 // Track the symbols that have multiple matching documentation extension files for diagnostics.
12761275 var symbolsWithMultipleDocumentationExtensionMatches = [ ResolvedTopicReference : [ SemanticResult < Article > ] ] ( )
@@ -1817,7 +1816,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
18171816 topicGraph. addNode ( graphNode)
18181817 documentationCache [ reference] = documentation
18191818
1820- hierarchyBasedLinkResolver . addRootArticle ( article, anchorSections: documentation. anchorSections)
1819+ linkResolver . localResolver . addRootArticle ( article, anchorSections: documentation. anchorSections)
18211820 for anchor in documentation. anchorSections {
18221821 nodeAnchorSections [ anchor. reference] = anchor
18231822 }
@@ -1873,7 +1872,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
18731872 let graphNode = TopicGraph . Node ( reference: reference, kind: . article, source: . file( url: article. source) , title: title)
18741873 topicGraph. addNode ( graphNode)
18751874
1876- hierarchyBasedLinkResolver . addArticle ( article, anchorSections: documentation. anchorSections)
1875+ linkResolver . localResolver . addArticle ( article, anchorSections: documentation. anchorSections)
18771876 for anchor in documentation. anchorSections {
18781877 nodeAnchorSections [ anchor. reference] = anchor
18791878 }
@@ -2078,6 +2077,17 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
20782077 }
20792078 }
20802079
2080+ discoveryGroup. async ( queue: discoveryQueue) { [ unowned self] in
2081+ do {
2082+ try linkResolver. loadExternalResolvers ( )
2083+ } catch {
2084+ // Pipe the error out of the dispatch queue.
2085+ discoveryError. sync ( {
2086+ if $0 == nil { $0 = error }
2087+ } )
2088+ }
2089+ }
2090+
20812091 discoveryGroup. wait ( )
20822092
20832093 try shouldContinueRegistration ( )
@@ -2128,7 +2138,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
21282138 options = globalOptions. first
21292139 }
21302140
2131- self . hierarchyBasedLinkResolver = hierarchyBasedResolver
2141+ self . linkResolver . localResolver = hierarchyBasedResolver
21322142 hierarchyBasedResolver. addMappingForRoots ( bundle: bundle)
21332143 for tutorial in tutorials {
21342144 hierarchyBasedResolver. addTutorial ( tutorial)
@@ -2187,7 +2197,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
21872197 }
21882198
21892199 try shouldContinueRegistration ( )
2190- var allCuratedReferences = try crawlSymbolCuration ( in: hierarchyBasedLinkResolver . topLevelSymbols ( ) , bundle: bundle)
2200+ var allCuratedReferences = try crawlSymbolCuration ( in: linkResolver . localResolver . topLevelSymbols ( ) , bundle: bundle)
21912201
21922202 // Store the list of manually curated references if doc coverage is on.
21932203 if shouldStoreManuallyCuratedReferences {
@@ -2222,7 +2232,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
22222232 // Emit warnings for any remaining uncurated files.
22232233 emitWarningsForUncuratedTopics ( )
22242234
2225- hierarchyBasedLinkResolver . addAnchorForSymbols ( symbolIndex: symbolIndex, documentationCache: documentationCache)
2235+ linkResolver . localResolver . addAnchorForSymbols ( symbolIndex: symbolIndex, documentationCache: documentationCache)
22262236
22272237 // Fifth, resolve links in nodes that are added solely via curation
22282238 try preResolveExternalLinks ( references: Array ( allCuratedReferences) , bundle: bundle)
@@ -2329,7 +2339,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
23292339 /// - Returns: An ordered list of symbol references that have been added to the topic graph automatically.
23302340 private func autoCurateSymbolsInTopicGraph( engine: DiagnosticEngine ) -> [ ( child: ResolvedTopicReference , parent: ResolvedTopicReference ) ] {
23312341 var automaticallyCuratedSymbols = [ ( ResolvedTopicReference, ResolvedTopicReference) ] ( )
2332- hierarchyBasedLinkResolver . traverseSymbolAndParentPairs { reference, parentReference in
2342+ linkResolver . localResolver . traverseSymbolAndParentPairs { reference, parentReference in
23332343 guard let topicGraphNode = topicGraph. nodeWithReference ( reference) ,
23342344 let topicGraphParentNode = topicGraph. nodeWithReference ( parentReference) ,
23352345 // Check that the node hasn't got any parents from manual curation
@@ -2535,6 +2545,9 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
25352545 let referenceWithoutFragment = reference. withFragment ( nil )
25362546 return try entity ( with: referenceWithoutFragment) . availableSourceLanguages
25372547 } catch ContextError . notFound {
2548+ if let externalEntity = externalCache [ reference] {
2549+ return externalEntity. sourceLanguages
2550+ }
25382551 preconditionFailure ( " Reference does not have an associated documentation node. " )
25392552 } catch {
25402553 fatalError ( " Unexpected error when retrieving source languages: \( error) " )
@@ -2646,7 +2659,8 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
26462659 public func resolve( _ reference: TopicReference , in parent: ResolvedTopicReference , fromSymbolLink isCurrentlyResolvingSymbolLink: Bool = false ) -> TopicReferenceResolutionResult {
26472660 switch reference {
26482661 case . unresolved( let unresolvedReference) :
2649- return hierarchyBasedLinkResolver. resolve ( unresolvedReference, in: parent, fromSymbolLink: isCurrentlyResolvingSymbolLink, context: self )
2662+ return linkResolver. resolve ( unresolvedReference, in: parent, fromSymbolLink: isCurrentlyResolvingSymbolLink, context: self )
2663+
26502664 case . resolved( let resolved) :
26512665 // This reference is already resolved (either as a success or a failure), so don't change anything.
26522666 return resolved
0 commit comments