Skip to content

Commit a2eb297

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 28a206e commit a2eb297

File tree

12 files changed

+247
-22
lines changed

12 files changed

+247
-22
lines changed

Sources/SwiftDocC/Infrastructure/DocumentationContext.swift

Lines changed: 53 additions & 14 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,9 +624,19 @@ 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 reference = technologyResult.topicGraphNode.reference.withSourceLanguages(sourceLanguages)
628+
629+
let node = DocumentationNode(
630+
reference: reference,
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[reference] = node
639+
topicGraph.nodes[reference]?.reference = reference
627640

628641
let anonymousVolumeName = "$volume"
629642

@@ -678,8 +691,19 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
678691
// Add to document map
679692
documentLocationMap[url] = tutorialResult.topicGraphNode.reference
680693

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
694+
let reference = tutorialResult.topicGraphNode.reference.withSourceLanguages(sourceLanguages)
695+
696+
let node = DocumentationNode(
697+
reference: reference,
698+
kind: .tutorial,
699+
sourceLanguage: Self.defaultLanguage(in: sourceLanguages),
700+
availableSourceLanguages: sourceLanguages,
701+
name: .conceptual(title: tutorial.intro.title),
702+
markup: tutorial.originalMarkup,
703+
semantic: tutorial
704+
)
705+
documentationCache[reference] = node
706+
topicGraph.nodes[reference]?.reference = reference
683707
}
684708
}
685709

@@ -695,9 +719,20 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
695719

696720
// Add to document map
697721
documentLocationMap[url] = articleResult.topicGraphNode.reference
722+
723+
let reference = articleResult.topicGraphNode.reference.withSourceLanguages(sourceLanguages)
698724

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
725+
let node = DocumentationNode(
726+
reference: reference,
727+
kind: .tutorialArticle,
728+
sourceLanguage: Self.defaultLanguage(in: sourceLanguages),
729+
availableSourceLanguages: sourceLanguages,
730+
name: .conceptual(title: article.title ?? ""),
731+
markup: article.originalMarkup,
732+
semantic: article
733+
)
734+
documentationCache[reference] = node
735+
topicGraph.nodes[reference]?.reference = reference
701736
}
702737
}
703738

@@ -1722,13 +1757,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
17221757

17231758
// If available source languages are provided and it contains Swift, use Swift as the default language of
17241759
// 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
1760+
let defaultSourceLanguage = defaultLanguage(in: availableSourceLanguages)
17321761

17331762
let reference = ResolvedTopicReference(
17341763
bundleIdentifier: bundle.identifier,
@@ -2692,6 +2721,16 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
26922721
}
26932722
.joined()
26942723
}
2724+
2725+
private static func defaultLanguage(in sourceLanguages: Set<SourceLanguage>?) -> SourceLanguage {
2726+
sourceLanguages.map { sourceLanguages in
2727+
if sourceLanguages.contains(.swift) {
2728+
return .swift
2729+
} else {
2730+
return sourceLanguages.first ?? .swift
2731+
}
2732+
} ?? SourceLanguage.swift
2733+
}
26952734
}
26962735

26972736
// MARK: - DocumentationCurator

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ struct TopicGraph {
7070
}
7171

7272
/// The reference to the `DocumentationNode` this node represents.
73-
let reference: ResolvedTopicReference
73+
var reference: ResolvedTopicReference
7474

7575
/// The kind of node.
7676
let kind: DocumentationNode.Kind

Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift

Lines changed: 8 additions & 0 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

Tests/SwiftDocCTests/Indexing/RenderIndexTests.swift

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

Tests/SwiftDocCTests/Model/SemaToRenderNodeMultiLanguageTests.swift

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class SemaToRenderNodeMixedLanguageTests: ExperimentalObjectiveCTestCase {
1616
func testBaseRenderNodeFromMixedLanguageFramework() throws {
1717
let (_, context) = try testBundleAndContext(named: "MixedLanguageFramework")
1818

19-
for documentationNode in context.documentationCache.values {
19+
for documentationNode in context.documentationCache.values where documentationNode.kind.isSymbol {
2020
let symbolUSR = try XCTUnwrap((documentationNode.semantic as? Symbol)?.externalID)
2121

2222
let expectedSwiftOnlyUSRs: Set<String> = [
@@ -61,6 +61,16 @@ class SemaToRenderNodeMixedLanguageTests: ExperimentalObjectiveCTestCase {
6161
)
6262
}
6363
}
64+
65+
for documentationNode in context.documentationCache.values
66+
where !documentationNode.kind.isSymbol && documentationNode.kind.isPage
67+
{
68+
XCTAssertEqual(
69+
documentationNode.availableSourceLanguages,
70+
[.swift, .objectiveC],
71+
"Expected non-symbol page to be available in both Swift and Objective-C: \(documentationNode.name)"
72+
)
73+
}
6474
}
6575

6676
func testOutputsMultiLanguageRenderNodes() throws {
@@ -103,7 +113,7 @@ class SemaToRenderNodeMixedLanguageTests: ExperimentalObjectiveCTestCase {
103113
XCTAssertEqual(
104114
Set(
105115
outputConsumer.renderNodes(withInterfaceLanguages: ["swift", "occ"])
106-
.map { $0.metadata.externalID }
116+
.map { $0.metadata.externalID ?? $0.metadata.title }
107117
),
108118
[
109119
"MixedLanguageFramework",
@@ -114,6 +124,10 @@ class SemaToRenderNodeMixedLanguageTests: ExperimentalObjectiveCTestCase {
114124
"c:@E@Foo@third",
115125
"c:objc(cs)Bar",
116126
"c:objc(cs)Bar(cm)myStringFunction:error:",
127+
"Article",
128+
"MixedLanguageFramework Tutorials",
129+
"Tutorial Article",
130+
"Tutorial",
117131
]
118132
)
119133
}
@@ -135,14 +149,22 @@ class SemaToRenderNodeMixedLanguageTests: ExperimentalObjectiveCTestCase {
135149
discussionSection: nil,
136150
topicSectionIdentifiers: [
137151
"doc://org.swift.MixedLanguageFramework/documentation/MixedLanguageFramework/SwiftOnlyStruct",
152+
"doc://org.swift.MixedLanguageFramework/tutorials/TutorialOverview",
153+
"doc://org.swift.MixedLanguageFramework/tutorials/MixedLanguageFramework/TutorialArticle",
154+
"doc://org.swift.MixedLanguageFramework/tutorials/MixedLanguageFramework/Tutorial",
155+
"doc://org.swift.MixedLanguageFramework/documentation/MixedLanguageFramework/Article",
138156
"doc://org.swift.MixedLanguageFramework/documentation/MixedLanguageFramework/Bar",
139157
"doc://org.swift.MixedLanguageFramework/documentation/MixedLanguageFramework/Foo-swift.struct",
140158
],
141159
referenceTitles: [
160+
"Article",
142161
"Bar",
143162
"Foo",
144163
"MixedLanguageFramework",
164+
"MixedLanguageFramework Tutorials",
145165
"SwiftOnlyStruct",
166+
"Tutorial",
167+
"Tutorial Article",
146168
"_MixedLanguageFrameworkVersionNumber",
147169
"_MixedLanguageFrameworkVersionString"
148170
],
@@ -171,15 +193,23 @@ class SemaToRenderNodeMixedLanguageTests: ExperimentalObjectiveCTestCase {
171193
discussionSection: nil,
172194
topicSectionIdentifiers: [
173195
"doc://org.swift.MixedLanguageFramework/documentation/MixedLanguageFramework/_MixedLanguageFrameworkVersionNumber",
196+
"doc://org.swift.MixedLanguageFramework/tutorials/TutorialOverview",
197+
"doc://org.swift.MixedLanguageFramework/tutorials/MixedLanguageFramework/TutorialArticle",
198+
"doc://org.swift.MixedLanguageFramework/tutorials/MixedLanguageFramework/Tutorial",
199+
"doc://org.swift.MixedLanguageFramework/documentation/MixedLanguageFramework/Article",
174200
"doc://org.swift.MixedLanguageFramework/documentation/MixedLanguageFramework/Bar",
175201
"doc://org.swift.MixedLanguageFramework/documentation/MixedLanguageFramework/_MixedLanguageFrameworkVersionString",
176202
"doc://org.swift.MixedLanguageFramework/documentation/MixedLanguageFramework/Foo-swift.struct",
177203
],
178204
referenceTitles: [
205+
"Article",
179206
"Bar",
180207
"Foo",
181208
"MixedLanguageFramework",
209+
"MixedLanguageFramework Tutorials",
182210
"SwiftOnlyStruct",
211+
"Tutorial",
212+
"Tutorial Article",
183213
"_MixedLanguageFrameworkVersionNumber",
184214
"_MixedLanguageFrameworkVersionString"
185215
],
@@ -553,17 +583,26 @@ private class TestRenderNodeOutputConsumer: ConvertOutputConsumer {
553583
}
554584

555585
extension TestRenderNodeOutputConsumer {
556-
func renderNodes(withInterfaceLanguages interfaceLanguages: Set<String>) -> [RenderNode] {
586+
func renderNodes(withInterfaceLanguages interfaceLanguages: Set<String>?) -> [RenderNode] {
557587
renderNodes.sync { renderNodes in
558588
renderNodes.filter { renderNode in
559-
let actualInterfaceLanguages: [String] = renderNode.variants?.flatMap { variant in
589+
guard let interfaceLanguages = interfaceLanguages else {
590+
// If there are no interface languages set, return the nodes with no variants.
591+
return renderNode.variants == nil
592+
}
593+
594+
guard let variants = renderNode.variants else {
595+
return false
596+
}
597+
598+
let actualInterfaceLanguages: [String] = variants.flatMap { variant in
560599
variant.traits.compactMap { trait in
561600
guard case .interfaceLanguage(let interfaceLanguage) = trait else {
562601
return nil
563602
}
564603
return interfaceLanguage
565604
}
566-
} ?? []
605+
}
567606

568607
return Set(actualInterfaceLanguages) == interfaceLanguages
569608
}

0 commit comments

Comments
 (0)