Skip to content

Commit d694243

Browse files
committed
Filter out topics in other languages
Filter out topics that are not available in the language of the symbol that curates them. rdar://89124291
1 parent 1805de5 commit d694243

File tree

12 files changed

+357
-82
lines changed

12 files changed

+357
-82
lines changed

Sources/SwiftDocC/Infrastructure/DocumentationContext.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,13 +2417,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
24172417
///
24182418
/// Adds any non-resolving reference to the `allCandidateURLs` collection.
24192419
func attemptToResolve(_ reference: ResolvedTopicReference) -> TopicReferenceResolutionResult? {
2420-
if topicGraph.nodeWithReference(reference) != nil {
2421-
let resolved = ResolvedTopicReference(
2422-
bundleIdentifier: referenceBundleIdentifier,
2423-
path: reference.url.path,
2424-
fragment: reference.fragment,
2425-
sourceLanguages: reference.sourceLanguages
2426-
)
2420+
if let resolved = topicGraph.nodeWithReference(reference)?.reference {
24272421
// If resolving a symbol link, only match symbol nodes.
24282422
if isCurrentlyResolvingSymbolLink && !(documentationCache[resolved]?.semantic is Symbol) {
24292423
allCandidateURLs.append(reference.url)

Sources/SwiftDocC/Model/Rendering/DocumentationContentRenderer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ public class DocumentationContentRenderer {
346346
}
347347

348348
// Collect the reference dependencies.
349-
dependencies.topicReferences = contentCompiler.collectedTopicReferences
349+
dependencies.topicReferences = Array(contentCompiler.collectedTopicReferences)
350350
dependencies.linkReferences = Array(contentCompiler.linkReferences.values)
351351

352352
let isRequired = (node?.semantic as? Symbol)?.isRequired ?? false

Sources/SwiftDocC/Model/Rendering/RenderContentCompiler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ struct RenderContentCompiler: MarkupVisitor {
2424
var identifier: ResolvedTopicReference
2525
var imageReferences: [String: ImageReference] = [:]
2626
/// Resolved topic references that were seen by the visitor. These should be used to populate the references dictionary.
27-
var collectedTopicReferences: [ResolvedTopicReference] = []
27+
var collectedTopicReferences = GroupedSequence<String, ResolvedTopicReference> { $0.absoluteString }
2828
var linkReferences: [String: LinkReference] = [:]
2929

3030
init(context: DocumentationContext, bundle: DocumentationBundle, identifier: ResolvedTopicReference) {

Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift

Lines changed: 86 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

4-
Copyright (c) 2021 Apple Inc. and the Swift project authors
4+
Copyright (c) 2021-2022 Apple Inc. and the Swift project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See https://swift.org/LICENSE.txt for license information
@@ -618,7 +618,14 @@ public struct RenderNodeTranslator: SemanticVisitor {
618618

619619
if let topics = article.topics, !topics.taskGroups.isEmpty {
620620
// Don't set an eyebrow as collections and groups don't have one; append the authored Topics section
621-
node.topicSections.append(contentsOf: renderGroups(topics, allowExternalLinks: false, contentCompiler: &contentCompiler))
621+
node.topicSections.append(
622+
contentsOf: renderGroups(
623+
topics,
624+
allowExternalLinks: false,
625+
allowedTraits: documentationNode.availableVariantTraits,
626+
contentCompiler: &contentCompiler
627+
)
628+
)
622629
}
623630

624631
// Place "top" rendering preference automatic task groups
@@ -666,7 +673,14 @@ public struct RenderNodeTranslator: SemanticVisitor {
666673

667674
// Authored See Also section
668675
if let seeAlso = article.seeAlso, !seeAlso.taskGroups.isEmpty {
669-
node.seeAlsoSections.append(contentsOf: renderGroups(seeAlso, allowExternalLinks: true, contentCompiler: &contentCompiler))
676+
node.seeAlsoSections.append(
677+
contentsOf: renderGroups(
678+
seeAlso,
679+
allowExternalLinks: true,
680+
allowedTraits: documentationNode.availableVariantTraits,
681+
contentCompiler: &contentCompiler
682+
)
683+
)
670684
}
671685

672686
// Automatic See Also section
@@ -811,7 +825,12 @@ public struct RenderNodeTranslator: SemanticVisitor {
811825
}
812826

813827
/// Renders a list of topic groups.
814-
private mutating func renderGroups(_ topics: GroupedSection, allowExternalLinks: Bool, contentCompiler: inout RenderContentCompiler) -> [TaskGroupRenderSection] {
828+
private mutating func renderGroups(
829+
_ topics: GroupedSection,
830+
allowExternalLinks: Bool,
831+
allowedTraits: Set<DocumentationDataVariantsTrait>,
832+
contentCompiler: inout RenderContentCompiler
833+
) -> [TaskGroupRenderSection] {
815834
return topics.taskGroups.compactMap { group in
816835

817836
let abstractContent = group.abstract.map {
@@ -823,6 +842,22 @@ public struct RenderNodeTranslator: SemanticVisitor {
823842
return ContentRenderSection(kind: .content, content: discussionContent, heading: "Discussion")
824843
}
825844

845+
/// 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 {
848+
// If there's no reference in `contentCompiler.collectedTopicReferences`, the reference refers to
849+
// a non-documentation URL (e.g., 'https://' URL), in which case it is available in all traits.
850+
return true
851+
}
852+
853+
return reference.sourceLanguages
854+
.contains { sourceLanguage in
855+
allowedTraits.contains { trait in
856+
trait.interfaceLanguage == sourceLanguage.id
857+
}
858+
}
859+
}
860+
826861
let taskGroupRenderSection = TaskGroupRenderSection(
827862
title: group.heading?.plainText,
828863
abstract: abstractContent,
@@ -838,29 +873,43 @@ public struct RenderNodeTranslator: SemanticVisitor {
838873
}
839874

840875
if let referenceInlines = contentCompiler.visitLink(link) as? [RenderInlineContent],
841-
let renderReference = referenceInlines.first(where: { inline in
842-
switch inline {
843-
case .reference(_,_,_,_):
844-
return true
845-
default:
846-
return false
847-
}
848-
}),
849-
case let RenderInlineContent.reference(identifier: identifier, isActive: _, overridingTitle: _, overridingTitleInlineContent: _) = renderReference {
850-
return identifier.identifier
876+
let renderReference = referenceInlines.first(where: { inline in
877+
switch inline {
878+
case .reference(_,_,_,_):
879+
return true
880+
default:
881+
return false
882+
}
883+
}),
884+
case let RenderInlineContent.reference(
885+
identifier: identifier,
886+
isActive: _,
887+
overridingTitle: _,
888+
overridingTitleInlineContent: _
889+
) = renderReference
890+
{
891+
return isAvailableInAllowedTrait(identifier: identifier.identifier)
892+
? identifier.identifier : nil
851893
}
852894
case let link as SymbolLink:
853895
if let referenceInlines = contentCompiler.visitSymbolLink(link) as? [RenderInlineContent],
854-
let renderReference = referenceInlines.first(where: { inline in
855-
switch inline {
856-
case .reference:
857-
return true
858-
default:
859-
return false
860-
}
861-
}),
862-
case let RenderInlineContent.reference(identifier: identifier, isActive: _, overridingTitle: _, overridingTitleInlineContent: _) = renderReference {
863-
return identifier.identifier
896+
let renderReference = referenceInlines.first(where: { inline in
897+
switch inline {
898+
case .reference:
899+
return true
900+
default:
901+
return false
902+
}
903+
}),
904+
case let RenderInlineContent.reference(
905+
identifier: identifier,
906+
isActive: _,
907+
overridingTitle: _,
908+
overridingTitleInlineContent: _
909+
) = renderReference
910+
{
911+
return isAvailableInAllowedTrait(identifier: identifier.identifier)
912+
? identifier.identifier : nil
864913
}
865914
default: break
866915
}
@@ -1011,7 +1060,7 @@ public struct RenderNodeTranslator: SemanticVisitor {
10111060
DeclarationsSectionTranslator(),
10121061
ReturnsSectionTranslator(),
10131062
ParametersSectionTranslator(),
1014-
DiscussionSectionTranslator()
1063+
DiscussionSectionTranslator(),
10151064
]
10161065
)
10171066
)
@@ -1098,7 +1147,12 @@ public struct RenderNodeTranslator: SemanticVisitor {
10981147
var sections = [TaskGroupRenderSection]()
10991148
if let topics = topics, !topics.taskGroups.isEmpty {
11001149
sections.append(
1101-
contentsOf: renderGroups(topics, allowExternalLinks: false, contentCompiler: &contentCompiler)
1150+
contentsOf: renderGroups(
1151+
topics,
1152+
allowExternalLinks: false,
1153+
allowedTraits: [trait],
1154+
contentCompiler: &contentCompiler
1155+
)
11021156
)
11031157
}
11041158

@@ -1199,7 +1253,12 @@ public struct RenderNodeTranslator: SemanticVisitor {
11991253

12001254
if let seeAlso = symbol.seeAlsoVariants[trait] {
12011255
seeAlsoSections.append(
1202-
contentsOf: renderGroups(seeAlso, allowExternalLinks: true, contentCompiler: &contentCompiler)
1256+
contentsOf: renderGroups(
1257+
seeAlso,
1258+
allowExternalLinks: true,
1259+
allowedTraits: [trait],
1260+
contentCompiler: &contentCompiler
1261+
)
12031262
)
12041263
}
12051264

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2022 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See https://swift.org/LICENSE.txt for license information
8+
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import Foundation
12+
13+
/// A sequence that groups its elements to optimize accesses.
14+
///
15+
/// You use a grouped sequence when you need efficient access to its elements via a grouping mechanism of your
16+
/// choosing and you aren't concerned with the order of the elements in the sequence.
17+
///
18+
/// ```swift
19+
/// var groupedSequence = GroupedSequence<Int, String> { $0.count }
20+
/// groupedSequence.append("a")
21+
/// groupedSequence.append(contentsOf: ["aa", "aaa"])
22+
///
23+
/// print(groupedSequence[1])
24+
/// // Prints ["a"]
25+
///
26+
/// print(groupedSequence[2])
27+
/// // Prints ["aa"]
28+
/// ```
29+
///
30+
/// You can iterate through a grouped sequence's unordered elements.
31+
///
32+
/// ```swift
33+
/// for item in groupedSequence {
34+
/// print(item)
35+
/// }
36+
///
37+
/// // Prints "aa"
38+
/// // Prints "a"
39+
/// // Prints "aaa"
40+
/// ```
41+
struct GroupedSequence<Key: Hashable, Element>: Sequence, CustomStringConvertible {
42+
fileprivate var storage = [Key: Element]()
43+
44+
/// A closure that transforms an element into its key.
45+
private var deriveKey: (Element) -> Key
46+
47+
var description: String {
48+
storage.values.description
49+
}
50+
51+
/// Creates an empty grouped sequence.
52+
init(deriveKey: @escaping (Element) -> Key) {
53+
self.deriveKey = deriveKey
54+
}
55+
56+
/// Adds an element to the group sequence.
57+
///
58+
/// If an element with the same derived key was appended before, it will be replaced with the new element.
59+
mutating func append(_ element: Element) {
60+
storage[deriveKey(element)] = element
61+
}
62+
63+
/// Adds the contents of a sequence to the group sequence.
64+
///
65+
/// Existing elements with the same derived key will be replaced with the new element.
66+
mutating func append<S: Sequence>(contentsOf newElements: S) where S.Element == Element {
67+
for element in newElements {
68+
append(element)
69+
}
70+
}
71+
72+
/// Accesses the member using the given key.
73+
subscript(key: Key) -> Element? {
74+
get {
75+
storage[key]
76+
}
77+
}
78+
79+
/// Returns an iterator over the members of the sequence.
80+
func makeIterator() -> Dictionary<Key, Element>.Values.Iterator {
81+
storage.values.makeIterator()
82+
}
83+
}
84+
85+
extension Array {
86+
/// Creates an array given a grouped sequence.
87+
init<Key>(_ groupedSequence: GroupedSequence<Key, Element>) {
88+
self = Array(groupedSequence.storage.values)
89+
}
90+
}

Tests/SwiftDocCTests/Indexing/RenderIndexTests.swift

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ final class RenderIndexTests: XCTestCase {
6868
{
6969
"interfaceLanguages": {
7070
"occ": [
71+
{
72+
"title": "Objective-C–only APIs",
73+
"type": "groupMarker"
74+
},
75+
{
76+
"path": "\/documentation\/mixedlanguageframework\/_mixedlanguageframeworkversionnumber",
77+
"title": "_MixedLanguageFrameworkVersionNumber",
78+
"type": "var"
79+
},
7180
{
7281
"title": "Classes",
7382
"type": "groupMarker"
@@ -103,11 +112,6 @@ final class RenderIndexTests: XCTestCase {
103112
"title": "Variables",
104113
"type": "groupMarker"
105114
},
106-
{
107-
"path": "\/documentation\/mixedlanguageframework\/_mixedlanguageframeworkversionnumber",
108-
"title": "_MixedLanguageFrameworkVersionNumber",
109-
"type": "var"
110-
},
111115
{
112116
"path": "\/documentation\/mixedlanguageframework\/_mixedlanguageframeworkversionstring",
113117
"title": "_MixedLanguageFrameworkVersionString",
@@ -150,6 +154,26 @@ final class RenderIndexTests: XCTestCase {
150154
}
151155
],
152156
"swift": [
157+
{
158+
"title": "Swift-only APIs",
159+
"type": "groupMarker"
160+
},
161+
{
162+
"children": [
163+
{
164+
"title": "Instance Methods",
165+
"type": "groupMarker"
166+
},
167+
{
168+
"path": "\/documentation\/mixedlanguageframework\/swiftonlystruct\/tada()",
169+
"title": "func tada()",
170+
"type": "method"
171+
}
172+
],
173+
"path": "\/documentation\/mixedlanguageframework\/swiftonlystruct",
174+
"title": "SwiftOnlyStruct",
175+
"type": "struct"
176+
},
153177
{
154178
"title": "Classes",
155179
"type": "groupMarker"
@@ -161,12 +185,6 @@ final class RenderIndexTests: XCTestCase {
161185
"type": "groupMarker"
162186
},
163187
{
164-
"children": [
165-
{
166-
"title": "Custom",
167-
"type": "groupMarker"
168-
}
169-
],
170188
"path": "\/documentation\/mixedlanguageframework\/bar\/mystringfunction(_:)",
171189
"title": "class func myStringFunction(String) throws -> String",
172190
"type": "method"
@@ -219,22 +237,6 @@ final class RenderIndexTests: XCTestCase {
219237
"path": "\/documentation\/mixedlanguageframework\/foo-swift.struct",
220238
"title": "Foo",
221239
"type": "struct"
222-
},
223-
{
224-
"children": [
225-
{
226-
"title": "Instance Methods",
227-
"type": "groupMarker"
228-
},
229-
{
230-
"path": "\/documentation\/mixedlanguageframework\/swiftonlystruct\/tada()",
231-
"title": "func tada()",
232-
"type": "method"
233-
}
234-
],
235-
"path": "\/documentation\/mixedlanguageframework\/swiftonlystruct",
236-
"title": "SwiftOnlyStruct",
237-
"type": "struct"
238240
}
239241
]
240242
},

0 commit comments

Comments
 (0)