Skip to content

Commit d304317

Browse files
authored
Merge automatically curated task groups (#931)
* Merges automatically curated groups with manually curated groups Changes the automatic curation logic for symbols to only create a new section if an existing manually curated section does not already exist. If the section already exists, it adds the automatically curated symbols onto the existing section. * Adds test for merging automatically curated symbol task groups Adds a unit test to verify that the automatic curation logic for symbols is to only create a new section if an existing manually curated section does not already exist (rdar://61899214). * Adds comment about combined references in merged topics Adds a comment explaining that merging references between manually & automatic curated topics without checking for duplicates should be safe, and explains the logic behind this thinking. Resolves rdar://61899214.
1 parent fd9a406 commit d304317

File tree

2 files changed

+70
-7
lines changed

2 files changed

+70
-7
lines changed

Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,16 +1546,23 @@ public struct RenderNodeTranslator: SemanticVisitor {
15461546

15471547
// Children of the current symbol that have not been curated manually in a task group will all
15481548
// be automatically curated in task groups after their symbol kind: "Properties", "Enumerations", etc.
1549-
let alreadyCurated = Set(sections.flatMap { $0.identifiers })
15501549
let groups = try! AutomaticCuration.topics(for: documentationNode, withTraits: allowedTraits, context: context)
15511550

1552-
sections.append(contentsOf: groups.compactMap { group in
1553-
let newReferences = group.references.filter { !alreadyCurated.contains($0.absoluteString) }
1554-
guard !newReferences.isEmpty else { return nil }
1555-
1551+
for group in groups {
1552+
let newReferences = group.references
15561553
contentCompiler.collectedTopicReferences.append(contentsOf: newReferences)
1557-
return TaskGroupRenderSection(taskGroup: (title: group.title, references: newReferences))
1558-
})
1554+
1555+
// If the section has been manually curated, merge the references of both the automatic curation and the manual curation into one section (rdar://61899214).
1556+
if let duplicateSectionIndex = sections.firstIndex(where: { $0.title == group.title }) {
1557+
let originalSection = sections[duplicateSectionIndex]
1558+
// Combining all references here without checking for duplicates should be safe,
1559+
// because the automatic curation of topics only returns symbols that haven't already been manually curated.
1560+
let combinedReferences = originalSection.identifiers + newReferences.map { $0.absoluteString }
1561+
sections[duplicateSectionIndex] = TaskGroupRenderSection(title: originalSection.title, abstract: originalSection.abstract, discussion: originalSection.discussion, identifiers: combinedReferences)
1562+
} else {
1563+
sections.append(TaskGroupRenderSection(taskGroup: (title: group.title, references: newReferences)))
1564+
}
1565+
}
15591566

15601567
// Place "bottom" rendering preference automatic task groups
15611568
// after any user-defined task groups but before automatic curation.

Tests/SwiftDocCTests/Infrastructure/AutomaticCurationTests.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,62 @@ class AutomaticCurationTests: XCTestCase {
784784
"doc://com.shapes.ShapeKit/documentation/ShapeKit/OverloadedProtocol/fourthTestMemberName(test:)-961zx",
785785
])
786786
}
787+
788+
func testAutomaticallyCuratedSymbolTopicsAreMergedWithManuallyCuratedTopics() throws {
789+
for kind in availableNonExtensionSymbolKinds {
790+
let containerID = "some-container-id"
791+
let memberID = "some-member-id"
792+
let topicSectionTitle = AutomaticCuration.groupTitle(for: kind)
793+
794+
let exampleDocumentation = Folder(name: "CatalogName.docc", content: [
795+
JSONFile(name: "ModuleName.symbols.json",
796+
content: makeSymbolGraph(moduleName: "ModuleName", symbols: [
797+
makeSymbol(identifier: containerID, kind: .class, pathComponents: ["SomeClass"]),
798+
makeSymbol(identifier: memberID, kind: kind, pathComponents: ["SomeClass", "someMember"]),
799+
], relationships: [
800+
.init(source: memberID, target: containerID, kind: .memberOf, targetFallback: nil),
801+
])),
802+
TextFile(name: "SomeArticle.md", utf8Content: """
803+
# Some article
804+
805+
An article with some content.
806+
"""),
807+
TextFile(name: "SomeExtension.md", utf8Content: """
808+
# ``ModuleName/SomeClass``
809+
810+
Curate an article under a manually curated section and leave the symbol documentation to automatic curation.
811+
812+
## Topics
813+
814+
### \(topicSectionTitle)
815+
816+
- <doc:SomeArticle>
817+
"""),
818+
])
819+
let catalogURL = try exampleDocumentation.write(inside: createTemporaryDirectory())
820+
let (_, bundle, context) = try loadBundle(from: catalogURL)
821+
822+
let node = try context.entity(with: ResolvedTopicReference(bundleIdentifier: bundle.identifier, path: "/documentation/ModuleName/SomeClass", sourceLanguage: .swift))
823+
824+
// Compile docs and verify the generated Topics section
825+
var translator = RenderNodeTranslator(context: context, bundle: bundle, identifier: node.reference, source: nil)
826+
let renderNode = try XCTUnwrap(translator.visit(node.semantic) as? RenderNode)
827+
828+
// Verify that there are no duplicate sections in `SomeClass`'s "Topics" section
829+
XCTAssertEqual(renderNode.topicSections.map { $0.title }, [topicSectionTitle])
830+
831+
// Verify that uncurated element `ModuleName/SomeClass/someMember` is
832+
// automatically curated in `SomeClass`'s "Topics" under the existing manually curated topics section
833+
// along with manually curated article "SomeArticle"
834+
XCTAssertEqual([
835+
"doc://CatalogName/documentation/CatalogName/SomeArticle",
836+
"doc://CatalogName/documentation/ModuleName/SomeClass/someMember",
837+
], renderNode.topicSections.first?.identifiers)
838+
839+
// Verify that the merged section under `SideClass`'s "Topics" is correctly marked as containing manual content
840+
XCTAssertFalse(renderNode.topicSections.first?.generated ?? false)
841+
}
842+
}
787843
}
788844

789845
private func makeSymbol(

0 commit comments

Comments
 (0)