in Sources/SwiftDocC/Infrastructure/DocumentationCurator.swift [57:128]
mutating func referenceFromLink(link: Link, resolved: ResolvedTopicReference, source: URL?) -> ResolvedTopicReference? {
// Try a link to a topic
guard let unresolved = link.destination.flatMap(ValidatedURL.init)?
.requiring(scheme: ResolvedTopicReference.urlScheme)
.map(UnresolvedTopicReference.init(topicURL:)) else {
// Emit a warning regarding the invalid link found in a task group.
problems.append(Problem(diagnostic: Diagnostic(source: source, severity: .warning, range: link.range, identifier: "org.swift.docc.InvalidDocumentationLink", summary: "The link \((link.destination ?? "").singleQuoted) isn't valid", explanation: "Expected a well-formed URL that uses the \(ResolvedTopicReference.urlScheme.singleQuoted) scheme. You can only curate external links in a 'See Also' section."), possibleSolutions: []))
return nil
}
let maybeResolved = context.resolve(.unresolved(unresolved), in: resolved)
if case let .success(resolved) = maybeResolved {
// The link resolves to a known topic.
if let node = context.topicGraph.nodeWithReference(resolved) {
// Make sure to remove any articles that have been registered in the topic graph
// from the context's uncurated articles
if node.kind == .article, context.uncuratedArticles.keys.contains(resolved) {
context.uncuratedArticles.removeValue(forKey: resolved)
}
return resolved
}
// The link resolves to a known content section, emit a warning.
if resolved.fragment != nil, context.nodeAnchorSections.keys.contains(resolved) {
problems.append(Problem(diagnostic: Diagnostic(source: source, severity: .warning, range: link.range, identifier: "org.swift.docc.SectionCuration", summary: "The content section link \((link.destination ?? "").singleQuoted) isn't allowed in a Topics link group", explanation: "Content sections cannot participate in the documentation hierarchy."), possibleSolutions: []))
return resolved
}
}
// Check if the link has been externally resolved already.
if let bundleID = unresolved.topicURL.components.host,
context.externalReferenceResolvers[bundleID] != nil || context.fallbackReferenceResolvers[bundleID] != nil {
if case .success(let resolvedExternalReference) = context.externallyResolvedLinks[unresolved.topicURL] {
return resolvedExternalReference
} else {
return nil // This link has already failed to resolve.
}
}
// Try extracting an article from the cache
let articleFilename = unresolved.topicURL.components.path.components(separatedBy: "/").last!
let sourceArticlePath = NodeURLGenerator.Path.article(bundleName: bundle.displayName, articleName: articleFilename).stringValue
let reference = ResolvedTopicReference(
bundleIdentifier: resolved.bundleIdentifier,
path: sourceArticlePath,
sourceLanguages: resolved.sourceLanguages)
guard let currentArticle = self.context.uncuratedArticles[reference],
let documentationNode = try? DocumentationNode(reference: reference, article: currentArticle.value) else { return nil }
// An article has been found which needs to be extracted from the article cache
// and curated under the current symbol. To do this we need to re-create the reference
// to include the current module, update the file location map, and create a new
// documentation node with the new reference and new semantic article.
// Add reference in the file location map
context.documentLocationMap[currentArticle.source] = reference
// Add the curated node to the topic graph
let node = currentArticle.topicGraphNode
let curatedNode = TopicGraph.Node(reference: reference, kind: node.kind, source: node.source, title: node.title)
context.topicGraph.addNode(curatedNode)
// Move the article from the article cache to the documentation
context.documentationCache[reference] = documentationNode
for anchor in documentationNode.anchorSections {
context.nodeAnchorSections[anchor.reference] = anchor
}
context.uncuratedArticles.removeValue(forKey: reference)
return reference
}