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
16 changes: 16 additions & 0 deletions Sources/SwiftDocC/Indexing/Navigator/NavigatorIndex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,22 @@ extension NavigatorIndex {
multiCuratedUnvisited.remove(normalizedIdentifier)
}

// Check if the render node has a variant for Objective-C
let objCVariantTrait = renderNode.variantOverrides?.values.flatMap({ $0.traits }).first { trait in
switch trait {
case .interfaceLanguage(let language):
return InterfaceLanguage.from(string: language) == .objc
}
}

// In case we have a variant for Objective-C, apply the variant and re-index the render node.
if let variantToApply = objCVariantTrait {
let encodedRenderNode = try renderNode.encodeToJSON()
let transformedData = try RenderNodeVariantOverridesApplier().applyVariantOverrides(in: encodedRenderNode, for: [variantToApply])
let variantRenderNode = try RenderNode.decode(fromJSON: transformedData)
try index(renderNode: variantRenderNode)
}

// Bump the nodes counter.
counter += 1
}
Expand Down
66 changes: 49 additions & 17 deletions Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import XCTest
typealias Node = NavigatorTree.Node
typealias PageType = NavigatorIndex.PageType

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

class NavigatorIndexingTests: XCTestCase {

Expand Down Expand Up @@ -177,7 +177,7 @@ Root

let original = NavigatorTree(root: root)
try original.write(to: indexURL)
let readTree = try NavigatorTree.read(from: indexURL, bundleIdentifier: testBundleIndetifier, interfaceLanguages: [.swift], atomically: true)
let readTree = try NavigatorTree.read(from: indexURL, bundleIdentifier: testBundleIdentifier, interfaceLanguages: [.swift], atomically: true)

XCTAssertEqual(original.root.countItems(), readTree.root.countItems())
XCTAssertTrue(compare(lhs: original.root, rhs: readTree.root))
Expand All @@ -198,7 +198,7 @@ Root
XCTAssertTrue(validateTree(node: readTree.root, validator: bundleIdentifierValidator), "The tree has bundle identifier missing.")
XCTAssertTrue(validateTree(node: readTree.root, validator: emptyPresentationIdentifierValidator), "The tree has a presentation identifier set which should not be present.")

var treeWithPresentationIdentifier = try NavigatorTree.read(from: indexURL, bundleIdentifier: testBundleIndetifier, interfaceLanguages: [.swift], atomically: true, presentationIdentifier: "com.example.test")
var treeWithPresentationIdentifier = try NavigatorTree.read(from: indexURL, bundleIdentifier: testBundleIdentifier, interfaceLanguages: [.swift], atomically: true, presentationIdentifier: "com.example.test")

let presentationIdentifierValidator: (NavigatorTree.Node) -> Bool = { node in
return node.presentationIdentifier == "com.example.test"
Expand All @@ -209,7 +209,7 @@ Root
XCTAssertTrue(validateTree(node: treeWithPresentationIdentifier.root, validator: presentationIdentifierValidator), "The tree lacks the presentation identifier.")

// Test non-atomic read.
treeWithPresentationIdentifier = try NavigatorTree.read(from: indexURL, bundleIdentifier: testBundleIndetifier, interfaceLanguages: [.swift], atomically: false, presentationIdentifier: "com.example.test")
treeWithPresentationIdentifier = try NavigatorTree.read(from: indexURL, bundleIdentifier: testBundleIdentifier, interfaceLanguages: [.swift], atomically: false, presentationIdentifier: "com.example.test")

XCTAssertTrue(validateTree(node: treeWithPresentationIdentifier.root, validator: idValidator), "The tree has IDs missing.")
XCTAssertTrue(validateTree(node: treeWithPresentationIdentifier.root, validator: bundleIdentifierValidator), "The tree has bundle identifier missing.")
Expand Down Expand Up @@ -290,7 +290,7 @@ Root
try? FileManager.default.removeItem(at: targetURL)
}

let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIndetifier)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier)
builder.setup()
builder.finalize()

Expand Down Expand Up @@ -347,7 +347,7 @@ Root
try? FileManager.default.removeItem(at: targetURL)
}

let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIndetifier)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier)
builder.setup()
try builder.index(renderNode: renderNode)
builder.finalize()
Expand All @@ -365,7 +365,7 @@ Root
// Create an index 10 times to ensure we have not undeterministic behavior across builds
for _ in 0..<10 {
let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIndetifier, sortRootChildrenByName: true)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true)
builder.setup()

for identifier in context.knownPages {
Expand All @@ -389,7 +389,7 @@ Root
XCTAssertEqual(Set(navigatorIndex.languages), Set(["Swift"]))
XCTAssertEqual(navigatorIndex.navigatorTree.root.countItems(), navigatorIndex.navigatorTree.numericIdentifierToNode.count)
XCTAssertTrue(validateTree(node: navigatorIndex.navigatorTree.root, validator: { (node) -> Bool in
return node.bundleIdentifier == testBundleIndetifier
return node.bundleIdentifier == testBundleIdentifier
}))

let allNodes = navigatorIndex.navigatorTree.numericIdentifierToNode.values
Expand All @@ -406,6 +406,38 @@ Root
assertEqualDumps(results.first ?? "", try testTree(named: "testNavigatorIndexGeneration"))
}

func testNavigatorIndexGenerationVariantsPayload() throws {
let jsonFile = Bundle.module.url(forResource: "Variant-render-node", withExtension: "json", subdirectory: "Test Resources")!
let jsonData = try Data(contentsOf: jsonFile)

let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true, groupByLanguage: true)
builder.setup()

let renderNode = try XCTUnwrap(RenderJSONDecoder.makeDecoder().decode(RenderNode.self, from: jsonData))
try builder.index(renderNode: renderNode)

builder.finalize()

let navigatorIndex = builder.navigatorIndex!

assertUniqueIDs(node: navigatorIndex.navigatorTree.root)
assertEqualDumps(navigatorIndex.navigatorTree.root.dumpTree(), """
[Root]
┣╸Objective-C
┃ ┗╸My Article in Objective-C
┃ ┣╸Task Group 1
┃ ┣╸Task Group 2
┃ ┗╸Task Group 3
┗╸Swift
┗╸My Article
┣╸Task Group 1
┣╸Task Group 2
┗╸Task Group 3
""")
try FileManager.default.removeItem(at: targetURL)
}

func testNavigatorIndexUsingPageTitleGeneration() throws {
let (bundle, context) = try testBundleAndContext(named: "TestBundle")
let renderContext = RenderContext(documentationContext: context, bundle: bundle)
Expand All @@ -415,7 +447,7 @@ Root
// Create an index 10 times to ensure we have not undeterministic behavior across builds
for _ in 0..<10 {
let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIndetifier, sortRootChildrenByName: true, usePageTitle: true)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true, usePageTitle: true)
builder.setup()

for identifier in context.knownPages {
Expand All @@ -439,7 +471,7 @@ Root
XCTAssertEqual(Set(navigatorIndex.languages), Set(["Swift"]))
XCTAssertEqual(navigatorIndex.navigatorTree.root.countItems(), navigatorIndex.navigatorTree.numericIdentifierToNode.count)
XCTAssertTrue(validateTree(node: navigatorIndex.navigatorTree.root, validator: { (node) -> Bool in
return node.bundleIdentifier == testBundleIndetifier
return node.bundleIdentifier == testBundleIdentifier
}))

let allNodes = navigatorIndex.navigatorTree.numericIdentifierToNode.values
Expand All @@ -464,7 +496,7 @@ Root
// Create an index 10 times to ensure we have not undeterministic behavior across builds
for _ in 0..<10 {
let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIndetifier, sortRootChildrenByName: true, writePathsOnDisk: false)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true, writePathsOnDisk: false)
builder.setup()

for identifier in context.knownPages {
Expand All @@ -489,7 +521,7 @@ Root
XCTAssertEqual(Set(navigatorIndex.languages), Set(["Swift"]))
XCTAssertEqual(navigatorIndex.navigatorTree.root.countItems(), navigatorIndex.navigatorTree.numericIdentifierToNode.count)
XCTAssertTrue(validateTree(node: navigatorIndex.navigatorTree.root, validator: { (node) -> Bool in
return node.bundleIdentifier == testBundleIndetifier
return node.bundleIdentifier == testBundleIdentifier
}))

let allNodes = navigatorIndex.navigatorTree.numericIdentifierToNode.values
Expand Down Expand Up @@ -519,7 +551,7 @@ Root
let converter = DocumentationContextConverter(bundle: bundle, context: context, renderContext: renderContext)

let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIndetifier, sortRootChildrenByName: true, groupByLanguage: true)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true, groupByLanguage: true)
builder.setup()

for identifier in context.knownPages {
Expand Down Expand Up @@ -570,7 +602,7 @@ Root
// Create an index 10 times to ensure we have no undeterministic behavior across builds
for _ in 0..<10 {
let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIndetifier, sortRootChildrenByName: true)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true)
builder.setup()

for identifier in context.knownPages {
Expand Down Expand Up @@ -631,7 +663,7 @@ Root
let converter = DocumentationContextConverter(bundle: bundle, context: context, renderContext: renderContext)

let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIndetifier, sortRootChildrenByName: true)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true)
builder.setup()

for identifier in context.knownPages {
Expand All @@ -646,7 +678,7 @@ Root
let navigatorIndex = try NavigatorIndex(url: targetURL)

XCTAssertEqual(navigatorIndex.pathHasher, .md5)
XCTAssertEqual(navigatorIndex.bundleIdentifier, testBundleIndetifier)
XCTAssertEqual(navigatorIndex.bundleIdentifier, testBundleIdentifier)
XCTAssertEqual(navigatorIndex.availabilityIndex.platforms, [.watchOS, .iOS, .macCatalyst, .tvOS, .macOS])
XCTAssertEqual(navigatorIndex.availabilityIndex.versions(for: .macOS), Set([
Platform.Version(string: "10.9")!,
Expand Down Expand Up @@ -730,7 +762,7 @@ Root
let converter = DocumentationContextConverter(bundle: bundle, context: context, renderContext: renderContext)

let targetURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIndetifier, sortRootChildrenByName: true)
let builder = NavigatorIndex.Builder(outputURL: targetURL, bundleIdentifier: testBundleIdentifier, sortRootChildrenByName: true)
builder.setup()

// Change the path hasher to the FNV-1 implementation and make sure paths and mappings are still working.
Expand Down
134 changes: 134 additions & 0 deletions Tests/SwiftDocCTests/Test Resources/Variant-render-node.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
{
"abstract": [],
"documentVersion": 0,
"identifier": {
"interfaceLanguage": "swift",
"url": "doc://org.swift.docc/documentation/mykit/my-article"
},
"kind": "article",
"metadata": {
"modules": [
{
"name": "mykit"
}
],
"role": "article",
"roleHeading": "Article",
"title": "My Article"
},
"primaryContentSections": [],
"references": {
"doc://org.swift.docc/documentation/mykit": {
"identifier": "doc://org.swift.docc/documentation/mykit",
"kind": "symbol",
"role": "collection",
"title": "mykit",
"type": "topic",
"url": "/documentation/mykit"
},
"doc://org.swift.docc/documentation/mykit/my-article": {
"abstract": [],
"identifier": "doc://org.swift.docc/documentation/mykit/my-article",
"kind": "article",
"role": "article",
"title": "My Article",
"type": "topic",
"url": "/documentation/mykit/my-article"
},
"doc://org.swift.docc/documentation/mykit/myclass": {
"abstract": [],
"fragments": [
{
"kind": "text",
"text": "class "
},
{
"kind": "identifier",
"text": "myclass"
}
],
"identifier": "doc://org.swift.docc/documentation/mykit/myclass",
"kind": "symbol",
"role": "symbol",
"title": "myclass",
"type": "topic",
"url": "/documentation/mykit/myclass"
}
},
"schemaVersion": {
"major": 0,
"minor": 1,
"patch": 0
},
"sections": [],
"seeAlsoSections": [],
"topicSections": [
{
"anchor": "2959524",
"identifiers": [
"doc://org.swift.docc/documentation/mykit/myclass"
],
"kind": "taskGroup",
"title": "Task Group 1"
},
{
"anchor": "2958803",
"identifiers": [
"doc://org.swift.docc/documentation/mykit/myclass"
],
"kind": "taskGroup",
"title": "Task Group 2"
},
{
"anchor": "3016821",
"identifiers": [
"doc://org.swift.docc/documentation/mykit/myclass"
],
"kind": "taskGroup",
"title": "Task Group 3"
}
],
"variants": [
{
"paths": [
"documentation/mykit/my-article"
],
"traits": [
{
"interfaceLanguage": "objc"
}
]
},
{
"paths": [
"documentation/mykit/my-article"
],
"traits": [
{
"interfaceLanguage": "swift"
}
]
}
],
"variantOverrides": [
{
"patch": [
{
"op": "replace",
"path": "/metadata/title",
"value": "My Article in Objective-C"
},
{
"op": "replace",
"path": "/identifier/interfaceLanguage",
"value": "objc"
}
],
"traits": [
{
"interfaceLanguage": "objc"
}
]
}
]
}