Skip to content

Commit fc01258

Browse files
Ensure that children of multicurated pages get properly multicurated as well
This performs a BFS traversal of multicurated pages to properly add references to them in all the copied parents. rdar://94798570
1 parent a5b46ab commit fc01258

File tree

7 files changed

+239
-15
lines changed

7 files changed

+239
-15
lines changed

Sources/SwiftDocC/Indexing/Navigator/NavigatorIndex.swift

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -910,25 +910,32 @@ extension NavigatorIndex {
910910
// Assign the children to the parents, starting with multi curated nodes
911911
var nodesMultiCurated = multiCurated.map { ($0, $1) }
912912

913-
for index in 0..<nodesMultiCurated.count {
914-
let (nodeID, parent) = nodesMultiCurated[index]
915-
let placeholders = identifierToChildren[nodeID]!
916-
for reference in placeholders {
917-
if let child = identifierToNode[reference] {
918-
parent.add(child: child)
919-
pendingUncuratedReferences.remove(reference)
920-
if !multiCurated.keys.contains(reference) && reference.fragment == nil {
921-
// As the children of a multi-curated node is itself curated multiple times
922-
// we need to process it as well, ignoring items with fragments as those are sections.
923-
nodesMultiCurated.append((reference, child))
924-
multiCurated[reference] = child
913+
while !nodesMultiCurated.isEmpty {
914+
// The children of the multicurated nodes. These need to be tracked so we can multicurate them as well.
915+
var nodesMultiCuratedChildren: [(Identifier, NavigatorTree.Node)] = []
916+
917+
for index in 0..<nodesMultiCurated.count {
918+
let (nodeID, parent) = nodesMultiCurated[index]
919+
let placeholders = identifierToChildren[nodeID]!
920+
for reference in placeholders {
921+
if let child = identifierToNode[reference] {
922+
parent.add(child: child)
923+
pendingUncuratedReferences.remove(reference)
924+
if !multiCurated.keys.contains(reference) && reference.fragment == nil {
925+
// As the children of a multi-curated node is itself curated multiple times
926+
// we need to process it as well, ignoring items with fragments as those are sections.
927+
nodesMultiCuratedChildren.append((reference, child))
928+
multiCurated[reference] = child
929+
}
925930
}
926931
}
932+
// Once assigned, placeholders can be removed as we use copy later.
933+
identifierToChildren[nodeID]!.removeAll()
927934
}
928-
// Once assigned, placeholders can be removed as we use copy later.
929-
identifierToChildren[nodeID]!.removeAll()
935+
936+
nodesMultiCurated = nodesMultiCuratedChildren
930937
}
931-
938+
932939
for (nodeIdentifier, placeholders) in identifierToChildren {
933940
for reference in placeholders {
934941
let parent = identifierToNode[nodeIdentifier]!

Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,36 @@ Root
578578
)
579579
}
580580

581+
func testMultiCuratesChildrenOfMultiCuratedPages() throws {
582+
let navigatorIndex = try generatedNavigatorIndex(for: "MultiCuratedSubtree", bundleIdentifier: "org.swift.MultiCuratedSubtree")
583+
584+
XCTAssertEqual(
585+
navigatorIndex.navigatorTree.root.dumpTree(),
586+
"""
587+
[Root]
588+
┗╸Swift
589+
┗╸MultiCuratedSubtree
590+
┣╸Curation Roots
591+
┣╸FirstCurationRoot
592+
┃ ┣╸Multicurated trees
593+
┃ ┗╸MultiCuratedStruct
594+
┃ ┣╸Enumerations
595+
┃ ┗╸MultiCuratedStruct.MultiCuratedEnum
596+
┃ ┣╸Enumeration Cases
597+
┃ ┣╸MultiCuratedStruct.MultiCuratedEnum.firstCase
598+
┃ ┗╸MultiCuratedStruct.MultiCuratedEnum.secondCase
599+
┗╸SecondCurationRoot
600+
┣╸Multicurated trees
601+
┗╸MultiCuratedStruct
602+
┣╸Enumerations
603+
┗╸MultiCuratedStruct.MultiCuratedEnum
604+
┣╸Enumeration Cases
605+
┣╸MultiCuratedStruct.MultiCuratedEnum.firstCase
606+
┗╸MultiCuratedStruct.MultiCuratedEnum.secondCase
607+
"""
608+
)
609+
}
610+
581611
func testNavigatorIndexUsingPageTitleGeneration() throws {
582612
let (bundle, context) = try testBundleAndContext(named: "TestBundle")
583613
let renderContext = RenderContext(documentationContext: context, bundle: bundle)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# FirstCurationRoot
2+
3+
The first curation root for the multicurated subtree
4+
5+
## Topics
6+
7+
### Multicurated trees
8+
9+
- ``MultiCuratedStruct``
10+
11+
<!-- Copyright (c) 2022 Apple Inc and the Swift Project authors. All Rights Reserved. -->
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleVersion</key>
6+
<string>0.0.1</string>
7+
<key>CFBundleDisplayName</key>
8+
<string>MultiCuratedSubtree</string>
9+
<key>CFBundleName</key>
10+
<string>MultiCuratedSubtree</string>
11+
<key>CFBundleIdentifier</key>
12+
<string>org.swift.MultiCuratedSubtree</string>
13+
</dict>
14+
</plist>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# ``MultiCuratedSubtree``
2+
3+
The top level page
4+
5+
## Topics
6+
7+
### Curation Roots
8+
9+
- <doc:FirstCurationRoot>
10+
- <doc:SecondCurationRoot>
11+
12+
<!-- Copyright (c) 2022 Apple Inc and the Swift Project authors. All Rights Reserved. -->
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
{
2+
"metadata": {
3+
"formatVersion": {
4+
"major": 0,
5+
"minor": 5,
6+
"patch": 3
7+
},
8+
"generator": "Apple Swift version 5.7 (swiftlang-5.7.0.113.202 clang-1400.0.16.2)"
9+
},
10+
"module": {
11+
"name": "MultiCuratedSubtree",
12+
"platform": {
13+
"architecture": "x86_64",
14+
"operatingSystem": {
15+
"minimumVersion": {
16+
"major": 12,
17+
"minor": 4,
18+
"patch": 0
19+
},
20+
"name": "macosx"
21+
},
22+
"vendor": "apple"
23+
}
24+
},
25+
"relationships": [
26+
{
27+
"kind": "memberOf",
28+
"source": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO10secondCaseyA2EmF",
29+
"target": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO"
30+
},
31+
{
32+
"kind": "memberOf",
33+
"source": "s:SQsE2neoiySbx_xtFZ::SYNTHESIZED::s:19MultiCuratedSubtree0aB6StructV0aB4EnumO",
34+
"sourceOrigin": {
35+
"displayName": "Equatable.!=(_:_:)",
36+
"identifier": "s:SQsE2neoiySbx_xtFZ"
37+
},
38+
"target": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO"
39+
},
40+
{
41+
"kind": "conformsTo",
42+
"source": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO",
43+
"target": "s:SH",
44+
"targetFallback": "Swift.Hashable"
45+
},
46+
{
47+
"kind": "memberOf",
48+
"source": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO9firstCaseyA2EmF",
49+
"target": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO"
50+
},
51+
{
52+
"kind": "memberOf",
53+
"source": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO",
54+
"target": "s:19MultiCuratedSubtree0aB6StructV"
55+
},
56+
{
57+
"kind": "conformsTo",
58+
"source": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO",
59+
"target": "s:SQ",
60+
"targetFallback": "Swift.Equatable"
61+
}
62+
],
63+
"symbols": [
64+
{
65+
"accessLevel": "public",
66+
"identifier": {
67+
"interfaceLanguage": "swift",
68+
"precise": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO"
69+
},
70+
"kind": {
71+
"displayName": "Enumeration",
72+
"identifier": "swift.enum"
73+
},
74+
"names": {
75+
"title": "MultiCuratedStruct.MultiCuratedEnum"
76+
},
77+
"pathComponents": [
78+
"MultiCuratedStruct",
79+
"MultiCuratedEnum"
80+
]
81+
},
82+
{
83+
"accessLevel": "public",
84+
"identifier": {
85+
"interfaceLanguage": "swift",
86+
"precise": "s:19MultiCuratedSubtree0aB6StructV"
87+
},
88+
"kind": {
89+
"displayName": "Structure",
90+
"identifier": "swift.struct"
91+
},
92+
"names": {
93+
"title": "MultiCuratedStruct"
94+
},
95+
"pathComponents": [
96+
"MultiCuratedStruct"
97+
]
98+
},
99+
{
100+
"accessLevel": "public",
101+
"identifier": {
102+
"interfaceLanguage": "swift",
103+
"precise": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO10secondCaseyA2EmF"
104+
},
105+
"kind": {
106+
"displayName": "Case",
107+
"identifier": "swift.enum.case"
108+
},
109+
"names": {
110+
"title": "MultiCuratedStruct.MultiCuratedEnum.secondCase"
111+
},
112+
"pathComponents": [
113+
"MultiCuratedStruct",
114+
"MultiCuratedEnum",
115+
"secondCase"
116+
]
117+
},
118+
{
119+
"accessLevel": "public",
120+
"identifier": {
121+
"interfaceLanguage": "swift",
122+
"precise": "s:19MultiCuratedSubtree0aB6StructV0aB4EnumO9firstCaseyA2EmF"
123+
},
124+
"kind": {
125+
"displayName": "Case",
126+
"identifier": "swift.enum.case"
127+
},
128+
"names": {
129+
"title": "MultiCuratedStruct.MultiCuratedEnum.firstCase"
130+
},
131+
"pathComponents": [
132+
"MultiCuratedStruct",
133+
"MultiCuratedEnum",
134+
"firstCase"
135+
]
136+
}
137+
]
138+
}
139+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SecondCurationRoot
2+
3+
The second curation root for the multicurated subtree
4+
5+
## Topics
6+
7+
### Multicurated trees
8+
9+
- ``MultiCuratedStruct``
10+
11+
<!-- Copyright (c) 2022 Apple Inc and the Swift Project authors. All Rights Reserved. -->

0 commit comments

Comments
 (0)