Skip to content

Commit 45aa567

Browse files
authored
Emit variants if any root module is a symbol kind (#1333)
* Extract helper in `RenderNodeTranslatorTests` One of the test methods in `RenderNodeTranslatorTests` was duplicated multiple times. It has been extracted out of the tests and deduplicated. * Emit variants if any root module is a symbol When the render node translator visits articles, it emits variants for each language that the article is supported in. This step is skipped if an article-only catalog is being built, since it would otherwise lead to a redundant "Swift" language marker being rendered in the page. However, if a catalog contains more than one module, i.e. an article-only collection and a different module's symbol graph in the same catalog, then the variants are not emitted despite the possibility of the page being available in more than one language. This commit changes the boolean check to skip emitting variants only if all root modules are article-only. It does not affect the behaviour when building a correctly configured catalog that contains a sole root module. rdar://163926698
1 parent 7b74f5c commit 45aa567

File tree

3 files changed

+62
-37
lines changed

3 files changed

+62
-37
lines changed

Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -632,9 +632,8 @@ public struct RenderNodeTranslator: SemanticVisitor {
632632
// Emit variants only if we're not compiling an article-only catalog to prevent renderers from
633633
// advertising the page as "Swift", which is the language DocC assigns to pages in article only catalogs.
634634
// (github.com/swiftlang/swift-docc/issues/240).
635-
if let topLevelModule = context.soleRootModuleReference,
636-
try! context.entity(with: topLevelModule).kind.isSymbol
637-
{
635+
let isArticleOnlyCatalog = context.rootModules.allSatisfy { !context.isSymbol(reference: $0) }
636+
if !isArticleOnlyCatalog {
638637
node.variants = variants(for: documentationNode)
639638
}
640639

Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import SwiftDocCTestUtilities
1515
typealias Node = NavigatorTree.Node
1616
typealias PageType = NavigatorIndex.PageType
1717

18-
let testBundleIdentifier = "org.swift.docc.example"
18+
private let testBundleIdentifier = "org.swift.docc.example"
1919

2020
class NavigatorIndexingTests: XCTestCase {
2121

Tests/SwiftDocCTests/Rendering/RenderNodeTranslatorTests.swift

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,31 +1334,22 @@ class RenderNodeTranslatorTests: XCTestCase {
13341334
),
13351335
]
13361336
)
1337-
let (bundle, context) = try await loadBundle(catalog: catalog)
1337+
let (_, context) = try await loadBundle(catalog: catalog)
13381338

1339-
func renderNodeArticleFromReferencePath(
1340-
referencePath: String
1341-
) throws -> RenderNode {
1342-
let reference = ResolvedTopicReference(bundleID: bundle.id, path: referencePath, sourceLanguage: .swift)
1343-
let symbol = try XCTUnwrap(context.entity(with: reference).semantic as? Article)
1344-
var translator = RenderNodeTranslator(context: context, identifier: reference)
1345-
return try XCTUnwrap(translator.visitArticle(symbol) as? RenderNode)
1346-
}
1347-
13481339
// Assert that articles that curates any symbol gets 'API Collection' assigned as the eyebrow title.
1349-
var renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/APICollection")
1340+
var renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/APICollection")
13501341
XCTAssertEqual(renderNode.metadata.roleHeading, "API Collection")
13511342
// Assert that articles that curates only other articles don't get any value assigned as the eyebrow title.
1352-
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/Collection")
1343+
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/Collection")
13531344
XCTAssertEqual(renderNode.metadata.roleHeading, nil)
13541345
// Assert that articles that don't curate anything else get 'Article' assigned as the eyebrow title.
1355-
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/Article")
1346+
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/Article")
13561347
XCTAssertEqual(renderNode.metadata.roleHeading, "Article")
13571348
// Assert that articles that have a custom title heading the eyebrow title assigned properly.
1358-
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/CustomRole")
1349+
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/CustomRole")
13591350
XCTAssertEqual(renderNode.metadata.roleHeading, "Custom Role")
13601351
// Assert that articles that have a custom page kind the eyebrow title assigned properly.
1361-
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/SampleCode")
1352+
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/SampleCode")
13621353
XCTAssertEqual(renderNode.metadata.roleHeading, "Sample Code")
13631354
}
13641355

@@ -1426,35 +1417,26 @@ class RenderNodeTranslatorTests: XCTestCase {
14261417
),
14271418
]
14281419
)
1429-
let (bundle, context) = try await loadBundle(catalog: catalog)
1430-
1431-
func renderNodeArticleFromReferencePath(
1432-
referencePath: String
1433-
) throws -> RenderNode {
1434-
let reference = ResolvedTopicReference(bundleID: bundle.id, path: referencePath, sourceLanguage: .swift)
1435-
let symbol = try XCTUnwrap(context.entity(with: reference).semantic as? Article)
1436-
var translator = RenderNodeTranslator(context: context, identifier: reference)
1437-
return try XCTUnwrap(translator.visitArticle(symbol) as? RenderNode)
1438-
}
1420+
let (_, context) = try await loadBundle(catalog: catalog)
14391421

14401422
// Assert that API collections disabling automatic title headings don't get any value assigned as the eyebrow title,
14411423
// but that the node's role itself is unaffected.
1442-
var renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/APICollection")
1424+
var renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/APICollection")
14431425
XCTAssertEqual(renderNode.metadata.roleHeading, nil)
14441426
XCTAssertEqual(renderNode.metadata.role, RenderMetadata.Role.collectionGroup.rawValue)
14451427
// Assert that articles disabling automatic title headings don't get any value assigned as the eyebrow title,
14461428
// but that the node's role itself is unaffected.
1447-
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/Article")
1429+
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/Article")
14481430
XCTAssertEqual(renderNode.metadata.roleHeading, nil)
14491431
XCTAssertEqual(renderNode.metadata.role, RenderMetadata.Role.article.rawValue)
14501432
// Assert that articles that have a custom title heading have the eyebrow title assigned properly,
14511433
// even when automatic title headings are disabled.
1452-
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/CustomRole")
1434+
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/CustomRole")
14531435
XCTAssertEqual(renderNode.metadata.roleHeading, "Custom Role")
14541436
XCTAssertEqual(renderNode.metadata.role, RenderMetadata.Role.article.rawValue)
14551437
// Assert that articles that have a custom page kind have the eyebrow title assigned properly,
14561438
// even when automatic title headings are disabled.
1457-
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/SampleCode")
1439+
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/SampleCode")
14581440
XCTAssertEqual(renderNode.metadata.roleHeading, "Sample Code")
14591441
}
14601442

@@ -1544,7 +1526,7 @@ class RenderNodeTranslatorTests: XCTestCase {
15441526
]
15451527
))
15461528

1547-
func renderNodeArticleFromReferencePath(
1529+
func renderNodeSymbolFromReferencePath(
15481530
referencePath: String
15491531
) throws -> RenderNode {
15501532
let reference = ResolvedTopicReference(bundleID: context.inputs.id, path: referencePath, sourceLanguage: .swift)
@@ -1554,25 +1536,69 @@ class RenderNodeTranslatorTests: XCTestCase {
15541536
}
15551537

15561538
// Assert that CounterpartSymbol's source languages have been added as source languages of Symbol
1557-
var renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/Symbol")
1539+
var renderNode = try renderNodeSymbolFromReferencePath(referencePath: "/documentation/unit-test/Symbol")
15581540
XCTAssertEqual(renderNode.variants?.count, 2)
15591541
XCTAssertEqual(renderNode.variants, [
15601542
.init(traits: [.interfaceLanguage("swift")], paths: ["/documentation/unit-test/symbol"]),
15611543
.init(traits: [.interfaceLanguage("occ")], paths: ["/documentation/unit-test/counterpartsymbol"])
15621544
])
15631545

15641546
// Assert that alternate representations which can't be resolved are ignored
1565-
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/OtherSymbol")
1547+
renderNode = try renderNodeSymbolFromReferencePath(referencePath: "/documentation/unit-test/OtherSymbol")
15661548
XCTAssertEqual(renderNode.variants?.count, 1)
15671549
XCTAssertEqual(renderNode.variants, [
15681550
.init(traits: [.interfaceLanguage("swift")], paths: ["/documentation/unit-test/othersymbol"]),
15691551
])
15701552

15711553
// Assert that duplicate alternate representations are not added as variants
1572-
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/MultipleSwiftVariantsSymbol")
1554+
renderNode = try renderNodeSymbolFromReferencePath(referencePath: "/documentation/unit-test/MultipleSwiftVariantsSymbol")
15731555
XCTAssertEqual(renderNode.variants?.count, 1)
15741556
XCTAssertEqual(renderNode.variants, [
15751557
.init(traits: [.interfaceLanguage("swift")], paths: ["/documentation/unit-test/multipleswiftvariantssymbol"]),
15761558
])
15771559
}
1560+
1561+
// Tests if variants are emitted in catalogs with more than one root module.
1562+
func testEmitVariantsInCatalogWithMultipleModules() async throws {
1563+
let (_, context) = try await loadBundle(catalog: Folder(
1564+
name: "UnitTest.docc",
1565+
content: [
1566+
TextFile(name: "UnitTest.md", utf8Content: """
1567+
# Unit test
1568+
1569+
@Metadata {
1570+
@TechnologyRoot
1571+
@SupportedLanguage(swift)
1572+
@SupportedLanguage(occ)
1573+
}
1574+
1575+
This is an article in a catalog containing a module different from the article-only collection.
1576+
"""),
1577+
// The correct way to configure a catalog is to have a single
1578+
// root module. If multiple modules are present, it is not
1579+
// possible to determine which module an article is supposed to
1580+
// be registered with. This test includes another module to
1581+
// verify if the variants are correctly emitted when there is
1582+
// no sole root module.
1583+
JSONFile(name: "foo.symbols.json", content: makeSymbolGraph(moduleName: "foo")),
1584+
]
1585+
))
1586+
1587+
let article = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/UnitTest")
1588+
XCTAssertEqual(article.variants?.count, 2)
1589+
XCTAssertEqual(article.variants, [
1590+
.init(traits: [.interfaceLanguage("swift")], paths: ["/documentation/unittest"]),
1591+
.init(traits: [.interfaceLanguage("occ")], paths: ["/documentation/unittest"])
1592+
])
1593+
}
1594+
1595+
private func renderNodeArticleFromReferencePath(
1596+
context: DocumentationContext,
1597+
referencePath: String
1598+
) throws -> RenderNode {
1599+
let reference = ResolvedTopicReference(bundleID: context.inputs.id, path: referencePath, sourceLanguage: .swift)
1600+
let article = try XCTUnwrap(context.entity(with: reference).semantic as? Article)
1601+
var translator = RenderNodeTranslator(context: context, identifier: reference)
1602+
return try XCTUnwrap(translator.visitArticle(article) as? RenderNode)
1603+
}
15781604
}

0 commit comments

Comments
 (0)