Skip to content

Commit a7857b3

Browse files
committed
Make tutorials language infer from module
In the same way articles do, infer the available languages of tutorials from the module's available language.
1 parent d694243 commit a7857b3

File tree

12 files changed

+281
-27
lines changed

12 files changed

+281
-27
lines changed

Sources/SwiftDocC/Infrastructure/DocumentationContext.swift

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,9 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
608608
tutorials: [SemanticResult<Tutorial>],
609609
tutorialArticles: [SemanticResult<TutorialArticle>],
610610
bundle: DocumentationBundle) {
611+
612+
let sourceLanguages = soleRootModuleReference?.sourceLanguages ?? [.swift]
613+
611614
// Technologies
612615

613616
for technologyResult in technologies {
@@ -621,15 +624,30 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
621624
// Add to document map
622625
documentLocationMap[url] = technologyResult.topicGraphNode.reference
623626

624-
let sourceLanguage = SourceLanguage.swift
625-
let node = DocumentationNode(reference: technologyResult.topicGraphNode.reference, kind: .technology, sourceLanguage: sourceLanguage, name: .conceptual(title: technology.intro.title), markup: technology.originalMarkup, semantic: technology)
626-
documentationCache[technologyResult.topicGraphNode.reference] = node
627+
let technologyReference = technologyResult.topicGraphNode.reference.withSourceLanguages(sourceLanguages)
628+
629+
let technologyNode = DocumentationNode(
630+
reference: technologyReference,
631+
kind: .technology,
632+
sourceLanguage: Self.defaultLanguage(in: sourceLanguages),
633+
availableSourceLanguages: sourceLanguages,
634+
name: .conceptual(title: technology.intro.title),
635+
markup: technology.originalMarkup,
636+
semantic: technology
637+
)
638+
documentationCache[technologyReference] = technologyNode
639+
640+
// Update the reference in the topic graph with the technology's available languages.
641+
topicGraph.updateReference(
642+
technologyResult.topicGraphNode.reference,
643+
newReference: technologyReference
644+
)
627645

628646
let anonymousVolumeName = "$volume"
629647

630648
for volume in technology.volumes {
631649
// Graph node: Volume
632-
let volumeReference = node.reference.appendingPath(volume.name ?? anonymousVolumeName)
650+
let volumeReference = technologyNode.reference.appendingPath(volume.name ?? anonymousVolumeName)
633651
let volumeNode = TopicGraph.Node(reference: volumeReference, kind: .volume, source: .file(url: url), title: volume.name ?? anonymousVolumeName)
634652
topicGraph.addNode(volumeNode)
635653

@@ -640,7 +658,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
640658
// Graph node: Module
641659
let baseNodeReference: ResolvedTopicReference
642660
if volume.name == nil {
643-
baseNodeReference = node.reference
661+
baseNodeReference = technologyNode.reference
644662
} else {
645663
baseNodeReference = volumeNode.reference
646664
}
@@ -678,8 +696,24 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
678696
// Add to document map
679697
documentLocationMap[url] = tutorialResult.topicGraphNode.reference
680698

681-
let tutorialNode = DocumentationNode(reference: tutorialResult.topicGraphNode.reference, kind: .tutorial, sourceLanguage: tutorialResult.topicGraphNode.reference.sourceLanguage, name: .conceptual(title: tutorial.intro.title), markup: tutorial.originalMarkup, semantic: tutorial)
682-
documentationCache[tutorialResult.topicGraphNode.reference] = tutorialNode
699+
let tutorialReference = tutorialResult.topicGraphNode.reference.withSourceLanguages(sourceLanguages)
700+
701+
let tutorialNode = DocumentationNode(
702+
reference: tutorialReference,
703+
kind: .tutorial,
704+
sourceLanguage: Self.defaultLanguage(in: sourceLanguages),
705+
availableSourceLanguages: sourceLanguages,
706+
name: .conceptual(title: tutorial.intro.title),
707+
markup: tutorial.originalMarkup,
708+
semantic: tutorial
709+
)
710+
documentationCache[tutorialReference] = tutorialNode
711+
712+
// Update the reference in the topic graph with the tutorial's available languages.
713+
topicGraph.updateReference(
714+
tutorialResult.topicGraphNode.reference,
715+
newReference: tutorialReference
716+
)
683717
}
684718
}
685719

@@ -695,9 +729,25 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
695729

696730
// Add to document map
697731
documentLocationMap[url] = articleResult.topicGraphNode.reference
732+
733+
let articleReference = articleResult.topicGraphNode.reference.withSourceLanguages(sourceLanguages)
734+
735+
let articleNode = DocumentationNode(
736+
reference: articleReference,
737+
kind: .tutorialArticle,
738+
sourceLanguage: Self.defaultLanguage(in: sourceLanguages),
739+
availableSourceLanguages: sourceLanguages,
740+
name: .conceptual(title: article.title ?? ""),
741+
markup: article.originalMarkup,
742+
semantic: article
743+
)
744+
documentationCache[articleReference] = articleNode
698745

699-
let articleNode = DocumentationNode(reference: articleResult.topicGraphNode.reference, kind: .tutorialArticle, sourceLanguage: articleResult.topicGraphNode.reference.sourceLanguage, name: .conceptual(title: article.title ?? ""), markup: article.originalMarkup, semantic: article)
700-
documentationCache[articleResult.topicGraphNode.reference] = articleNode
746+
// Update the reference in the topic graph with the article's available languages.
747+
topicGraph.updateReference(
748+
articleResult.topicGraphNode.reference,
749+
newReference: articleReference
750+
)
701751
}
702752
}
703753

@@ -1722,13 +1772,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
17221772

17231773
// If available source languages are provided and it contains Swift, use Swift as the default language of
17241774
// the article.
1725-
let defaultSourceLanguage = availableSourceLanguages.map { availableSourceLanguages in
1726-
if availableSourceLanguages.contains(.swift) {
1727-
return .swift
1728-
} else {
1729-
return availableSourceLanguages.first ?? .swift
1730-
}
1731-
} ?? SourceLanguage.swift
1775+
let defaultSourceLanguage = defaultLanguage(in: availableSourceLanguages)
17321776

17331777
let reference = ResolvedTopicReference(
17341778
bundleIdentifier: bundle.identifier,
@@ -2692,6 +2736,16 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
26922736
}
26932737
.joined()
26942738
}
2739+
2740+
private static func defaultLanguage(in sourceLanguages: Set<SourceLanguage>?) -> SourceLanguage {
2741+
sourceLanguages.map { sourceLanguages in
2742+
if sourceLanguages.contains(.swift) {
2743+
return .swift
2744+
} else {
2745+
return sourceLanguages.first ?? .swift
2746+
}
2747+
} ?? SourceLanguage.swift
2748+
}
26952749
}
26962750

26972751
// MARK: - DocumentationCurator

Sources/SwiftDocC/Infrastructure/Topic Graph/TopicGraph.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,15 @@ struct TopicGraph {
9292
self.isResolvable = isResolvable
9393
}
9494

95+
func withReference(_ reference: ResolvedTopicReference) -> Node {
96+
Node(
97+
reference: reference,
98+
kind: kind,
99+
source: source,
100+
title: title
101+
)
102+
}
103+
95104
func hash(into hasher: inout Hasher) {
96105
hasher.combine(reference)
97106
}
@@ -166,6 +175,11 @@ struct TopicGraph {
166175
}
167176
}
168177

178+
/// Updates the node with the given reference with a new reference.
179+
mutating func updateReference(_ reference: ResolvedTopicReference, newReference: ResolvedTopicReference) {
180+
nodes[reference] = nodes[reference]?.withReference(newReference)
181+
}
182+
169183
/// Adds a topic edge but it doesn't verify if the nodes exist for the given references.
170184
/// > Warning: If the references don't match already existing nodes this operation might corrupt the topic graph.
171185
/// - Parameters:

Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ public struct RenderNodeTranslator: SemanticVisitor {
129129
node.hierarchy = hierarchy.hierarchy
130130
node.metadata.category = technology.name
131131

132+
let documentationNode = try! context.entity(with: identifier)
133+
node.variants = variants(for: documentationNode)
134+
132135
node.metadata.categoryPathComponent = hierarchy.technology.url.lastPathComponent
133136

134137
var intro = visitIntro(tutorial.intro) as! IntroRenderSection
@@ -358,6 +361,9 @@ public struct RenderNodeTranslator: SemanticVisitor {
358361
node.metadata.categoryPathComponent = identifier.url.lastPathComponent
359362
node.metadata.estimatedTime = totalEstimatedDuration(for: technology)
360363
node.metadata.role = contentRenderer.role(for: .technology).rawValue
364+
365+
let documentationNode = try! context.entity(with: identifier)
366+
node.variants = variants(for: documentationNode)
361367

362368
var intro = visitIntro(technology.intro) as! IntroRenderSection
363369
if let firstTutorial = self.firstTutorial(ofTechnology: identifier) {
@@ -730,6 +736,8 @@ public struct RenderNodeTranslator: SemanticVisitor {
730736
// and produce the list of modules for the render hierarchy to display in the tutorial local navigation.
731737
node.hierarchy = hierarchy.hierarchy
732738

739+
let documentationNode = try! context.entity(with: identifier)
740+
node.variants = variants(for: documentationNode)
733741

734742
collectedTopicReferences.append(contentsOf: hierarchyTranslator.collectedTopicReferences)
735743

@@ -843,8 +851,8 @@ public struct RenderNodeTranslator: SemanticVisitor {
843851
}
844852

845853
/// Returns whether the topic with the given identifier is available in one of the traits in `allowedTraits`.
846-
func isAvailableInAllowedTrait(identifier: String) -> Bool {
847-
guard let reference = contentCompiler.collectedTopicReferences[identifier] else {
854+
func isTopicAvailableInAllowedTraits(identifier topicIdentifier: String) -> Bool {
855+
guard let reference = contentCompiler.collectedTopicReferences[topicIdentifier] else {
848856
// If there's no reference in `contentCompiler.collectedTopicReferences`, the reference refers to
849857
// a non-documentation URL (e.g., 'https://' URL), in which case it is available in all traits.
850858
return true
@@ -888,7 +896,7 @@ public struct RenderNodeTranslator: SemanticVisitor {
888896
overridingTitleInlineContent: _
889897
) = renderReference
890898
{
891-
return isAvailableInAllowedTrait(identifier: identifier.identifier)
899+
return isTopicAvailableInAllowedTraits(identifier: identifier.identifier)
892900
? identifier.identifier : nil
893901
}
894902
case let link as SymbolLink:
@@ -908,7 +916,7 @@ public struct RenderNodeTranslator: SemanticVisitor {
908916
overridingTitleInlineContent: _
909917
) = renderReference
910918
{
911-
return isAvailableInAllowedTrait(identifier: identifier.identifier)
919+
return isTopicAvailableInAllowedTraits(identifier: identifier.identifier)
912920
? identifier.identifier : nil
913921
}
914922
default: break

Tests/SwiftDocCTests/Indexing/RenderIndexTests.swift

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,50 @@ final class RenderIndexTests: XCTestCase {
7777
"title": "_MixedLanguageFrameworkVersionNumber",
7878
"type": "var"
7979
},
80+
{
81+
"title": "Tutorials",
82+
"type": "groupMarker"
83+
},
84+
{
85+
"path": "/tutorials/tutorialoverview",
86+
"title": "MixedLanguageFramework Tutorials",
87+
"type": "overview",
88+
"children": [
89+
{
90+
"title": "Chapter",
91+
"type": "groupMarker"
92+
},
93+
{
94+
"title": "Tutorial",
95+
"path": "/tutorials/mixedlanguageframework/tutorial",
96+
"type": "project"
97+
},
98+
{
99+
"title": "Tutorial Article",
100+
"path": "/tutorials/mixedlanguageframework/tutorialarticle",
101+
"type": "article"
102+
}
103+
]
104+
},
105+
{
106+
"title": "Tutorial Article",
107+
"path": "/tutorials/mixedlanguageframework/tutorialarticle",
108+
"type": "article"
109+
},
110+
{
111+
"title": "Tutorial",
112+
"path": "/tutorials/mixedlanguageframework/tutorial",
113+
"type": "project"
114+
},
115+
{
116+
"title": "Articles",
117+
"type": "groupMarker"
118+
},
119+
{
120+
"title": "Article",
121+
"path": "/documentation/mixedlanguageframework/article",
122+
"type": "article"
123+
},
80124
{
81125
"title": "Classes",
82126
"type": "groupMarker"
@@ -174,6 +218,50 @@ final class RenderIndexTests: XCTestCase {
174218
"title": "SwiftOnlyStruct",
175219
"type": "struct"
176220
},
221+
{
222+
"title": "Tutorials",
223+
"type": "groupMarker"
224+
},
225+
{
226+
"path": "/tutorials/tutorialoverview",
227+
"title": "MixedLanguageFramework Tutorials",
228+
"type": "overview",
229+
"children": [
230+
{
231+
"title": "Chapter",
232+
"type": "groupMarker"
233+
},
234+
{
235+
"title": "Tutorial",
236+
"path": "/tutorials/mixedlanguageframework/tutorial",
237+
"type": "project"
238+
},
239+
{
240+
"title": "Tutorial Article",
241+
"path": "/tutorials/mixedlanguageframework/tutorialarticle",
242+
"type": "article"
243+
}
244+
]
245+
},
246+
{
247+
"title": "Tutorial Article",
248+
"path": "/tutorials/mixedlanguageframework/tutorialarticle",
249+
"type": "article"
250+
},
251+
{
252+
"title": "Tutorial",
253+
"path": "/tutorials/mixedlanguageframework/tutorial",
254+
"type": "project"
255+
},
256+
{
257+
"title": "Articles",
258+
"type": "groupMarker"
259+
},
260+
{
261+
"title": "Article",
262+
"path": "/documentation/mixedlanguageframework/article",
263+
"type": "article"
264+
},
177265
{
178266
"title": "Classes",
179267
"type": "groupMarker"

0 commit comments

Comments
 (0)