1010
1111import Foundation
1212import SymbolKit
13+ import Markdown
1314
1415public struct RenderReferenceDependencies {
1516 var topicReferences = [ ResolvedTopicReference] ( )
@@ -57,25 +58,44 @@ public class DocumentationContentRenderer {
5758 }
5859
5960 /// For symbol nodes, returns the fragments mixin if any.
60- func subHeadingFragments( for node: DocumentationNode ) -> [ DeclarationRenderSection . Token ] ? {
61- guard let symbol = ( node. semantic as? Symbol ) ,
62- var fragments = symbol. subHeading?
61+ func subHeadingFragments( for node: DocumentationNode ) -> VariantCollection < [ DeclarationRenderSection . Token ] ? > {
62+ guard let symbol = ( node. semantic as? Symbol ) else {
63+ return . init( defaultValue: nil )
64+ }
65+
66+ return VariantCollection < [ DeclarationRenderSection . Token ] ? > (
67+ from: symbol. subHeadingVariants,
68+ symbol. titleVariants,
69+ symbol. kindVariants
70+ ) { _, subHeading, title, kind in
71+ var fragments = subHeading
6372 . map ( { fragment -> DeclarationRenderSection . Token in
6473 return DeclarationRenderSection . Token ( fragment: fragment, identifier: nil )
65- } ) else { return nil }
66- if fragments. last? . text == " \n " { fragments. removeLast ( ) }
67- return Swift . subHeading ( for: fragments, symbolTitle: symbol. title, symbolKind: symbol. kind. identifier)
74+ } )
75+ if fragments. last? . text == " \n " { fragments. removeLast ( ) }
76+
77+ // TODO: Return an Objective-C subheading for Objective-C symbols (rdar://84195588)
78+ return Swift . subHeading ( for: fragments, symbolTitle: title, symbolKind: kind. identifier)
79+ } ?? . init( defaultValue: nil )
6880 }
6981
7082 /// For symbol nodes, returns the navigator title if any.
71- func navigatorFragments( for node: DocumentationNode ) -> [ DeclarationRenderSection . Token ] ? {
72- guard let symbol = ( node. semantic as? Symbol ) ,
73- var fragments = symbol. navigator?
74- . map ( { fragment -> DeclarationRenderSection . Token in
75- return DeclarationRenderSection . Token ( fragment: fragment, identifier: nil )
76- } ) else { return nil }
77- if fragments. last? . text == " \n " { fragments. removeLast ( ) }
78- return Swift . navigatorTitle ( for: fragments, symbolTitle: symbol. title)
83+ func navigatorFragments( for node: DocumentationNode ) -> VariantCollection < [ DeclarationRenderSection . Token ] ? > {
84+ guard let symbol = ( node. semantic as? Symbol ) else {
85+ return . init( defaultValue: nil )
86+ }
87+
88+ return VariantCollection < [ DeclarationRenderSection . Token ] ? > (
89+ from: symbol. navigatorVariants
90+ ) { _, navigator in
91+ var fragments = navigator. map { fragment -> DeclarationRenderSection . Token in
92+ return DeclarationRenderSection . Token ( fragment: fragment, identifier: nil )
93+ }
94+ if fragments. last? . text == " \n " { fragments. removeLast ( ) }
95+
96+ // TODO: Return an Objective-C navigator title for Objective-C symbols (rdar://84195588)
97+ return Swift . navigatorTitle ( for: fragments, symbolTitle: symbol. title)
98+ } ?? . init( defaultValue: nil )
7999 }
80100
81101 /// Returns the given amount of minutes as a string, for example: "1hr 10min".
@@ -223,21 +243,29 @@ public class DocumentationContentRenderer {
223243 func renderReference( for reference: ResolvedTopicReference , with overridingDocumentationNode: DocumentationNode ? = nil , dependencies: inout RenderReferenceDependencies ) -> TopicRenderReference {
224244 let resolver = LinkTitleResolver ( context: documentationContext, source: reference. url)
225245
226- let title : String
246+ let titleVariants : SymbolDataVariants < String >
227247 let kind : RenderNode . Kind
228248 var referenceRole : String ?
229249 let node = try ? overridingDocumentationNode ?? documentationContext. entity ( with: reference)
250+
230251 if let node = node, let resolvedTitle = resolver. title ( for: node) {
231- title = resolvedTitle
252+ titleVariants = resolvedTitle
232253 } else if let anchorSection = documentationContext. nodeAnchorSections [ reference] {
233254 // No need to continue, return a section topic reference
234- return TopicRenderReference ( identifier: RenderReferenceIdentifier ( reference. absoluteString) , title: anchorSection. title, abstract: [ ] , url: urlGenerator. presentationURLForReference ( reference, requireRelativeURL: true ) . absoluteString, kind: . section, estimatedTime: nil )
255+ return TopicRenderReference (
256+ identifier: RenderReferenceIdentifier ( reference. absoluteString) ,
257+ title: anchorSection. title,
258+ abstract: [ ] ,
259+ url: urlGenerator. presentationURLForReference ( reference, requireRelativeURL: true ) . absoluteString,
260+ kind: . section,
261+ estimatedTime: nil
262+ )
235263 } else if let topicGraphOnlyNode = documentationContext. topicGraph. nodeWithReference ( reference) {
236264 // Some nodes are artificially inserted into the topic graph,
237265 // try resolving that way as a fallback after looking up `documentationCache`.
238- title = topicGraphOnlyNode. title
266+ titleVariants = . init ( defaultVariantValue : topicGraphOnlyNode. title)
239267 } else {
240- title = reference. absoluteString
268+ titleVariants = . init ( defaultVariantValue : reference. absoluteString)
241269 }
242270
243271 switch node? . kind {
@@ -273,7 +301,7 @@ public class DocumentationContentRenderer {
273301 let presentationURL = urlGenerator. presentationURLForReference ( reference, requireRelativeURL: true )
274302
275303 var contentCompiler = RenderContentCompiler ( context: documentationContext, bundle: bundle, identifier: reference)
276- let abstractContent : [ RenderInlineContent ]
304+ let abstractContent : VariantCollection < [ RenderInlineContent ] >
277305
278306 var abstractedNode = node
279307 if kind == . section {
@@ -282,12 +310,28 @@ public class DocumentationContentRenderer {
282310 abstractedNode = try ? documentationContext. entity ( with: containerReference)
283311 }
284312
285- if let abstract = ( abstractedNode? . semantic as? Abstracted ) ? . abstract ?? abstractedNode. map ( { DocumentationMarkup ( markup: $0. markup, parseUpToSection: . abstract) } ) ? . abstractSection? . paragraph,
286- let renderedContent = contentCompiler. visit ( abstract) . first,
287- case let . paragraph( inlines) ? = renderedContent as? RenderBlockContent {
288- abstractContent = inlines
313+ func extractAbstract( from paragraph: Paragraph ? ) -> [ RenderInlineContent ] {
314+ if let abstract = paragraph
315+ ?? abstractedNode. map ( {
316+ DocumentationMarkup ( markup: $0. markup, parseUpToSection: . abstract)
317+ } ) ? . abstractSection? . paragraph,
318+ let renderedContent = contentCompiler. visit ( abstract) . first,
319+ case let . paragraph( inlines) ? = renderedContent as? RenderBlockContent
320+ {
321+ return inlines
322+ } else {
323+ return [ ]
324+ }
325+ }
326+
327+ if let symbol = ( abstractedNode? . semantic as? Symbol ) {
328+ abstractContent = VariantCollection < [ RenderInlineContent ] > (
329+ from: symbol. abstractVariants
330+ ) { _, abstract in
331+ extractAbstract ( from: abstract)
332+ } ?? . init( defaultValue: [ ] )
289333 } else {
290- abstractContent = [ ]
334+ abstractContent = . init ( defaultValue : extractAbstract ( from : ( abstractedNode ? . semantic as? Abstracted ) ? . abstract ) )
291335 }
292336
293337 // Collect the reference dependencies.
@@ -300,8 +344,8 @@ public class DocumentationContentRenderer {
300344
301345 var renderReference = TopicRenderReference (
302346 identifier: . init( referenceURL) ,
303- titleVariants: . init( defaultValue: title ) ,
304- abstract : abstractContent,
347+ titleVariants: VariantCollection < String > ( from : titleVariants ) ?? . init( defaultValue: " " ) ,
348+ abstractVariants : abstractContent,
305349 url: presentationURL. absoluteString,
306350 kind: kind,
307351 required: isRequired,
@@ -310,9 +354,9 @@ public class DocumentationContentRenderer {
310354 )
311355
312356 // Store the symbol's display name if present in the render reference
313- renderReference. fragments = node. flatMap ( subHeadingFragments)
357+ renderReference. fragmentsVariants = node. flatMap ( subHeadingFragments) ?? . init ( defaultValue : [ ] )
314358 // Store the symbol's navigator title if present in the render reference
315- renderReference. navigatorTitle = node. flatMap ( navigatorFragments)
359+ renderReference. navigatorTitleVariants = node. flatMap ( navigatorFragments) ?? . init ( defaultValue : [ ] )
316360
317361 // Omit the navigator title if it's identical to the fragments
318362 if renderReference. navigatorTitle == renderReference. fragments {
0 commit comments