Skip to content

Commit f99a431

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 1802539 commit f99a431

File tree

13 files changed

+353
-83
lines changed

13 files changed

+353
-83
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: 84 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,20 @@ 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+
return true
849+
}
850+
851+
return reference.sourceLanguages
852+
.contains { sourceLanguage in
853+
allowedTraits.contains { trait in
854+
trait.interfaceLanguage == sourceLanguage.id
855+
}
856+
}
857+
}
858+
826859
let taskGroupRenderSection = TaskGroupRenderSection(
827860
title: group.heading?.plainText,
828861
abstract: abstractContent,
@@ -838,29 +871,43 @@ public struct RenderNodeTranslator: SemanticVisitor {
838871
}
839872

840873
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
874+
let renderReference = referenceInlines.first(where: { inline in
875+
switch inline {
876+
case .reference(_,_,_,_):
877+
return true
878+
default:
879+
return false
880+
}
881+
}),
882+
case let RenderInlineContent.reference(
883+
identifier: identifier,
884+
isActive: _,
885+
overridingTitle: _,
886+
overridingTitleInlineContent: _
887+
) = renderReference
888+
{
889+
return isAvailableInAllowedTrait(identifier: identifier.identifier)
890+
? identifier.identifier : nil
851891
}
852892
case let link as SymbolLink:
853893
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
894+
let renderReference = referenceInlines.first(where: { inline in
895+
switch inline {
896+
case .reference:
897+
return true
898+
default:
899+
return false
900+
}
901+
}),
902+
case let RenderInlineContent.reference(
903+
identifier: identifier,
904+
isActive: _,
905+
overridingTitle: _,
906+
overridingTitleInlineContent: _
907+
) = renderReference
908+
{
909+
return isAvailableInAllowedTrait(identifier: identifier.identifier)
910+
? identifier.identifier : nil
864911
}
865912
default: break
866913
}
@@ -1011,7 +1058,7 @@ public struct RenderNodeTranslator: SemanticVisitor {
10111058
DeclarationsSectionTranslator(),
10121059
ReturnsSectionTranslator(),
10131060
ParametersSectionTranslator(),
1014-
DiscussionSectionTranslator()
1061+
DiscussionSectionTranslator(),
10151062
]
10161063
)
10171064
)
@@ -1098,7 +1145,12 @@ public struct RenderNodeTranslator: SemanticVisitor {
10981145
var sections = [TaskGroupRenderSection]()
10991146
if let topics = topics, !topics.taskGroups.isEmpty {
11001147
sections.append(
1101-
contentsOf: renderGroups(topics, allowExternalLinks: false, contentCompiler: &contentCompiler)
1148+
contentsOf: renderGroups(
1149+
topics,
1150+
allowExternalLinks: false,
1151+
allowedTraits: [trait],
1152+
contentCompiler: &contentCompiler
1153+
)
11021154
)
11031155
}
11041156

@@ -1199,7 +1251,12 @@ public struct RenderNodeTranslator: SemanticVisitor {
11991251

12001252
if let seeAlso = symbol.seeAlsoVariants[trait] {
12011253
seeAlsoSections.append(
1202-
contentsOf: renderGroups(seeAlso, allowExternalLinks: true, contentCompiler: &contentCompiler)
1254+
contentsOf: renderGroups(
1255+
seeAlso,
1256+
allowExternalLinks: true,
1257+
allowedTraits: [trait],
1258+
contentCompiler: &contentCompiler
1259+
)
12031260
)
12041261
}
12051262

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
@@ -66,6 +66,15 @@ final class RenderIndexTests: XCTestCase {
6666
{
6767
"interfaceLanguages": {
6868
"occ": [
69+
{
70+
"title": "Objective-C–only APIs",
71+
"type": "groupMarker"
72+
},
73+
{
74+
"path": "\/documentation\/mixedlanguageframework\/_mixedlanguageframeworkversionnumber",
75+
"title": "_MixedLanguageFrameworkVersionNumber",
76+
"type": "var"
77+
},
6978
{
7079
"title": "Classes",
7180
"type": "groupMarker"
@@ -101,11 +110,6 @@ final class RenderIndexTests: XCTestCase {
101110
"title": "Variables",
102111
"type": "groupMarker"
103112
},
104-
{
105-
"path": "\/documentation\/mixedlanguageframework\/_mixedlanguageframeworkversionnumber",
106-
"title": "_MixedLanguageFrameworkVersionNumber",
107-
"type": "var"
108-
},
109113
{
110114
"path": "\/documentation\/mixedlanguageframework\/_mixedlanguageframeworkversionstring",
111115
"title": "_MixedLanguageFrameworkVersionString",
@@ -148,6 +152,26 @@ final class RenderIndexTests: XCTestCase {
148152
}
149153
],
150154
"swift": [
155+
{
156+
"title": "Swift-only APIs",
157+
"type": "groupMarker"
158+
},
159+
{
160+
"children": [
161+
{
162+
"title": "Instance Methods",
163+
"type": "groupMarker"
164+
},
165+
{
166+
"path": "\/documentation\/mixedlanguageframework\/swiftonlystruct\/tada()",
167+
"title": "func tada()",
168+
"type": "method"
169+
}
170+
],
171+
"path": "\/documentation\/mixedlanguageframework\/swiftonlystruct",
172+
"title": "SwiftOnlyStruct",
173+
"type": "struct"
174+
},
151175
{
152176
"title": "Classes",
153177
"type": "groupMarker"
@@ -159,12 +183,6 @@ final class RenderIndexTests: XCTestCase {
159183
"type": "groupMarker"
160184
},
161185
{
162-
"children": [
163-
{
164-
"title": "Custom",
165-
"type": "groupMarker"
166-
}
167-
],
168186
"path": "\/documentation\/mixedlanguageframework\/bar\/mystringfunction(_:)",
169187
"title": "class func myStringFunction(String) throws -> String",
170188
"type": "method"
@@ -217,22 +235,6 @@ final class RenderIndexTests: XCTestCase {
217235
"path": "\/documentation\/mixedlanguageframework\/foo-swift.struct",
218236
"title": "Foo",
219237
"type": "struct"
220-
},
221-
{
222-
"children": [
223-
{
224-
"title": "Instance Methods",
225-
"type": "groupMarker"
226-
},
227-
{
228-
"path": "\/documentation\/mixedlanguageframework\/swiftonlystruct\/tada()",
229-
"title": "func tada()",
230-
"type": "method"
231-
}
232-
],
233-
"path": "\/documentation\/mixedlanguageframework\/swiftonlystruct",
234-
"title": "SwiftOnlyStruct",
235-
"type": "struct"
236238
}
237239
]
238240
},

0 commit comments

Comments
 (0)