Skip to content

Commit 5d47f78

Browse files
committed
Resolve topic references in @AlternateRepresentation
Adds logic in `DocumentationContext` which will resolve the references inside the alternate representation directive. The same logic is used as for resolving all other links. This is done outside the usual ReferenceResolver visit of the semantic object, because `Symbol` objects don't have access to the node metadata, where the unresolved link resides. If the link cannot be resolved, the usual diagnostic is emitted: ``` warning: 'MissingSymbol' doesn't exist at '/Synonyms' --> SynonymSample.docc/SymbolExtension2.md:4:19-4:32 2 | 3 | @metadata { 4 + @AlternateRepresentation(``Synonyms/MissingSymbol``) 5 | } ```
1 parent 930bc62 commit 5d47f78

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

Sources/SwiftDocC/Infrastructure/DocumentationContext.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,19 @@ public class DocumentationContext {
618618
resolver.visit(documentationNode.semantic)
619619
}
620620

621+
// Also resolve the node's alternate representations. This isn't part of the node's 'semantic' value (resolved above).
622+
if let alternateRepresentations = documentationNode.metadata?.alternateRepresentations {
623+
for alternateRepresentation in alternateRepresentations {
624+
let resolutionResult = resolver.resolve(
625+
alternateRepresentation.reference,
626+
in: bundle.rootReference,
627+
range: alternateRepresentation.originalMarkup.range,
628+
severity: .warning
629+
)
630+
alternateRepresentation.reference = .resolved(resolutionResult)
631+
}
632+
}
633+
621634
let problems: [Problem]
622635
if documentationNode.semantic is Article {
623636
// Diagnostics for articles have correct source ranges and don't need to be modified.

Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5356,6 +5356,84 @@ let expected = """
53565356
XCTAssertEqual(externalRenderReference.title, externalModuleName)
53575357
XCTAssertEqual(externalRenderReference.abstract, [.text("Some description of this module.")])
53585358
}
5359+
5360+
func testResolvesAlternateDeclarations() throws {
5361+
let (bundle, context) = try loadBundle(catalog: Folder(
5362+
name: "unit-test.docc",
5363+
content: [
5364+
TextFile(name: "Symbol.md", utf8Content: """
5365+
# ``Symbol``
5366+
@Metadata {
5367+
@AlternateRepresentation(``CounterpartSymbol``)
5368+
@AlternateRepresentation(OtherCounterpartSymbol)
5369+
@AlternateRepresentation(``MissingSymbol``)
5370+
}
5371+
A symbol extension file defining an alternate representation.
5372+
"""),
5373+
JSONFile(
5374+
name: "unit-test.swift.symbols.json",
5375+
content: makeSymbolGraph(
5376+
moduleName: "unit-test",
5377+
symbols: [
5378+
makeSymbol(id: "symbol-id", kind: .class, pathComponents: ["Symbol"]),
5379+
]
5380+
)
5381+
),
5382+
JSONFile(
5383+
name: "unit-test.occ.symbols.json",
5384+
content: makeSymbolGraph(
5385+
moduleName: "unit-test",
5386+
symbols: [
5387+
makeSymbol(id: "counterpart-symbol-id", language: .objectiveC, kind: .class, pathComponents: ["CounterpartSymbol"]),
5388+
]
5389+
)
5390+
),
5391+
JSONFile(
5392+
name: "unit-test.js.symbols.json",
5393+
content: makeSymbolGraph(
5394+
moduleName: "unit-test",
5395+
symbols: [
5396+
makeSymbol(id: "other-counterpart-symbol-id", language: .javaScript, kind: .class, pathComponents: ["OtherCounterpartSymbol"]),
5397+
]
5398+
)
5399+
),
5400+
]
5401+
))
5402+
5403+
let reference = ResolvedTopicReference(bundleID: bundle.id, path: "/documentation/unit-test/Symbol", sourceLanguage: .swift)
5404+
5405+
let entity = try context.entity(with: reference)
5406+
XCTAssertEqual(entity.metadata?.alternateRepresentations.count, 3)
5407+
5408+
// First alternate representation should have been resolved successfully
5409+
var alternateRepresentation = try XCTUnwrap(entity.metadata?.alternateRepresentations.first)
5410+
XCTAssertEqual(
5411+
alternateRepresentation.reference,
5412+
.resolved(.success(.init(bundleID: bundle.id, path: "/documentation/unit-test/CounterpartSymbol", sourceLanguage: .objectiveC)))
5413+
)
5414+
5415+
// Second alternate representation without "``" should also have been resolved successfully
5416+
alternateRepresentation = try XCTUnwrap(entity.metadata?.alternateRepresentations.dropFirst().first)
5417+
XCTAssertEqual(
5418+
alternateRepresentation.reference,
5419+
.resolved(.success(.init(bundleID: bundle.id, path: "/documentation/unit-test/OtherCounterpartSymbol", sourceLanguage: .objectiveC)))
5420+
)
5421+
5422+
// Third alternate representation shouldn't have been resolved at all
5423+
alternateRepresentation = try XCTUnwrap(entity.metadata?.alternateRepresentations.dropFirst().last)
5424+
guard case .resolved(.failure(let unresolvedPath, _)) = alternateRepresentation.reference else {
5425+
XCTFail("Expected alternate representation to be unresolved, but was resolved as \(alternateRepresentation.reference)")
5426+
return
5427+
}
5428+
XCTAssertEqual(unresolvedPath, .init(topicURL: .init(parsingAuthoredLink: "MissingSymbol")!))
5429+
5430+
// And an error should have been reported
5431+
XCTAssertEqual(context.problems.count, 1)
5432+
5433+
let problem = try XCTUnwrap(context.problems.first)
5434+
XCTAssertEqual(problem.diagnostic.severity, .warning)
5435+
XCTAssertEqual(problem.diagnostic.summary, "Can't resolve 'MissingSymbol'")
5436+
}
53595437
}
53605438

53615439
func assertEqualDumps(_ lhs: String, _ rhs: String, file: StaticString = #file, line: UInt = #line) {

0 commit comments

Comments
 (0)