Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -632,9 +632,8 @@ public struct RenderNodeTranslator: SemanticVisitor {
// Emit variants only if we're not compiling an article-only catalog to prevent renderers from
// advertising the page as "Swift", which is the language DocC assigns to pages in article only catalogs.
// (github.com/swiftlang/swift-docc/issues/240).
if let topLevelModule = context.soleRootModuleReference,
try! context.entity(with: topLevelModule).kind.isSymbol
{
let isArticleOnlyCatalog = context.rootModules.allSatisfy { !context.isSymbol(reference: $0) }
if !isArticleOnlyCatalog {
node.variants = variants(for: documentationNode)
}

Expand Down
2 changes: 1 addition & 1 deletion Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import SwiftDocCTestUtilities
typealias Node = NavigatorTree.Node
typealias PageType = NavigatorIndex.PageType

let testBundleIdentifier = "org.swift.docc.example"
private let testBundleIdentifier = "org.swift.docc.example"

class NavigatorIndexingTests: XCTestCase {

Expand Down
92 changes: 59 additions & 33 deletions Tests/SwiftDocCTests/Rendering/RenderNodeTranslatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1334,31 +1334,22 @@ class RenderNodeTranslatorTests: XCTestCase {
),
]
)
let (bundle, context) = try await loadBundle(catalog: catalog)
let (_, context) = try await loadBundle(catalog: catalog)

func renderNodeArticleFromReferencePath(
referencePath: String
) throws -> RenderNode {
let reference = ResolvedTopicReference(bundleID: bundle.id, path: referencePath, sourceLanguage: .swift)
let symbol = try XCTUnwrap(context.entity(with: reference).semantic as? Article)
var translator = RenderNodeTranslator(context: context, identifier: reference)
return try XCTUnwrap(translator.visitArticle(symbol) as? RenderNode)
}

// Assert that articles that curates any symbol gets 'API Collection' assigned as the eyebrow title.
var renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/APICollection")
var renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/APICollection")
XCTAssertEqual(renderNode.metadata.roleHeading, "API Collection")
// Assert that articles that curates only other articles don't get any value assigned as the eyebrow title.
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/Collection")
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/Collection")
XCTAssertEqual(renderNode.metadata.roleHeading, nil)
// Assert that articles that don't curate anything else get 'Article' assigned as the eyebrow title.
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/Article")
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/Article")
XCTAssertEqual(renderNode.metadata.roleHeading, "Article")
// Assert that articles that have a custom title heading the eyebrow title assigned properly.
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/CustomRole")
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/CustomRole")
XCTAssertEqual(renderNode.metadata.roleHeading, "Custom Role")
// Assert that articles that have a custom page kind the eyebrow title assigned properly.
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/SampleCode")
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/SampleCode")
XCTAssertEqual(renderNode.metadata.roleHeading, "Sample Code")
}

Expand Down Expand Up @@ -1426,35 +1417,26 @@ class RenderNodeTranslatorTests: XCTestCase {
),
]
)
let (bundle, context) = try await loadBundle(catalog: catalog)

func renderNodeArticleFromReferencePath(
referencePath: String
) throws -> RenderNode {
let reference = ResolvedTopicReference(bundleID: bundle.id, path: referencePath, sourceLanguage: .swift)
let symbol = try XCTUnwrap(context.entity(with: reference).semantic as? Article)
var translator = RenderNodeTranslator(context: context, identifier: reference)
return try XCTUnwrap(translator.visitArticle(symbol) as? RenderNode)
}
let (_, context) = try await loadBundle(catalog: catalog)

// Assert that API collections disabling automatic title headings don't get any value assigned as the eyebrow title,
// but that the node's role itself is unaffected.
var renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/APICollection")
var renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/APICollection")
XCTAssertEqual(renderNode.metadata.roleHeading, nil)
XCTAssertEqual(renderNode.metadata.role, RenderMetadata.Role.collectionGroup.rawValue)
// Assert that articles disabling automatic title headings don't get any value assigned as the eyebrow title,
// but that the node's role itself is unaffected.
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/Article")
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/Article")
XCTAssertEqual(renderNode.metadata.roleHeading, nil)
XCTAssertEqual(renderNode.metadata.role, RenderMetadata.Role.article.rawValue)
// Assert that articles that have a custom title heading have the eyebrow title assigned properly,
// even when automatic title headings are disabled.
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/CustomRole")
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/CustomRole")
XCTAssertEqual(renderNode.metadata.roleHeading, "Custom Role")
XCTAssertEqual(renderNode.metadata.role, RenderMetadata.Role.article.rawValue)
// Assert that articles that have a custom page kind have the eyebrow title assigned properly,
// even when automatic title headings are disabled.
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/SampleCode")
renderNode = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/unit-test/SampleCode")
XCTAssertEqual(renderNode.metadata.roleHeading, "Sample Code")
}

Expand Down Expand Up @@ -1544,7 +1526,7 @@ class RenderNodeTranslatorTests: XCTestCase {
]
))

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

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

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

// Assert that duplicate alternate representations are not added as variants
renderNode = try renderNodeArticleFromReferencePath(referencePath: "/documentation/unit-test/MultipleSwiftVariantsSymbol")
renderNode = try renderNodeSymbolFromReferencePath(referencePath: "/documentation/unit-test/MultipleSwiftVariantsSymbol")
XCTAssertEqual(renderNode.variants?.count, 1)
XCTAssertEqual(renderNode.variants, [
.init(traits: [.interfaceLanguage("swift")], paths: ["/documentation/unit-test/multipleswiftvariantssymbol"]),
])
}

// Tests if variants are emitted in catalogs with more than one root module.
func testEmitVariantsInCatalogWithMultipleModules() async throws {
let (_, context) = try await loadBundle(catalog: Folder(
name: "UnitTest.docc",
content: [
TextFile(name: "UnitTest.md", utf8Content: """
# Unit test

@Metadata {
@TechnologyRoot
@SupportedLanguage(swift)
@SupportedLanguage(occ)
}

This is an article in a catalog containing a module different from the article-only collection.
"""),
// The correct way to configure a catalog is to have a single
// root module. If multiple modules are present, it is not
// possible to determine which module an article is supposed to
// be registered with. This test includes another module to
// verify if the variants are correctly emitted when there is
// no sole root module.
JSONFile(name: "foo.symbols.json", content: makeSymbolGraph(moduleName: "foo")),
]
))

let article = try renderNodeArticleFromReferencePath(context: context, referencePath: "/documentation/UnitTest")
XCTAssertEqual(article.variants?.count, 2)
XCTAssertEqual(article.variants, [
.init(traits: [.interfaceLanguage("swift")], paths: ["/documentation/unittest"]),
.init(traits: [.interfaceLanguage("occ")], paths: ["/documentation/unittest"])
])
}

private func renderNodeArticleFromReferencePath(
context: DocumentationContext,
referencePath: String
) throws -> RenderNode {
let reference = ResolvedTopicReference(bundleID: context.inputs.id, path: referencePath, sourceLanguage: .swift)
let article = try XCTUnwrap(context.entity(with: reference).semantic as? Article)
var translator = RenderNodeTranslator(context: context, identifier: reference)
return try XCTUnwrap(translator.visitArticle(article) as? RenderNode)
}
}