Skip to content

Commit 665321f

Browse files
committed
Add warning for symbols with @TechnologyRoot pages
When documentation contains symbols (from symbol graphs) and also has @TechnologyRoot pages, emit a warning about the unsupported setup with multiple roots in the documentation hierarchy. The solution suggests removing the @TechnologyRoot directive so pages are treated as articles under the module instead.
1 parent d260243 commit 665321f

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

Sources/SwiftDocC/Infrastructure/DocumentationContext.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2429,6 +2429,39 @@ public class DocumentationContext {
24292429
return node.reference
24302430
}
24312431

2432+
// Warn when the documentation contains both symbols (modules) and @TechnologyRoot pages
2433+
// This is an unsupported setup that creates multiple roots in the documentation hierarchy
2434+
if !rootModules.isEmpty && !rootPageArticles.isEmpty {
2435+
let problems = rootPageArticles.map { rootPageArticle -> Problem in
2436+
let diagnostic = Diagnostic(
2437+
source: rootPageArticle.source,
2438+
severity: .warning,
2439+
range: rootPageArticle.value.metadata?.technologyRoot?.originalMarkup.range,
2440+
identifier: "org.swift.docc.TechnologyRootWithSymbols",
2441+
summary: "Documentation contains both symbols and articles with @TechnologyRoot directives",
2442+
explanation: """
2443+
When documentation contains symbols (from symbol graph files), @TechnologyRoot directives create an unsupported setup with multiple roots in the documentation hierarchy.
2444+
Remove the @TechnologyRoot directive so that this page is treated as an article under the module.
2445+
"""
2446+
)
2447+
2448+
guard let range = rootPageArticle.value.metadata?.technologyRoot?.originalMarkup.range else {
2449+
return Problem(diagnostic: diagnostic)
2450+
}
2451+
2452+
let solution = Solution(
2453+
summary: "Remove the \(TechnologyRoot.directiveName.singleQuoted) directive",
2454+
replacements: [
2455+
Replacement(range: range, replacement: "")
2456+
]
2457+
)
2458+
2459+
return Problem(diagnostic: diagnostic, possibleSolutions: [solution])
2460+
}
2461+
2462+
diagnosticEngine.emit(problems)
2463+
}
2464+
24322465
// Articles that will be automatically curated can be resolved but they need to be pre registered before resolving links.
24332466
let rootNodeForAutomaticCuration = soleRootModuleReference.flatMap(topicGraph.nodeWithReference(_:))
24342467
if configuration.convertServiceConfiguration.allowsRegisteringArticlesWithoutTechnologyRoot || rootNodeForAutomaticCuration != nil {

Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContext+RootPageTests.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,50 @@ class DocumentationContext_RootPageTests: XCTestCase {
218218
}
219219
}
220220

221+
func testWarnsAboutSymbolsWithTechnologyRootPages() async throws {
222+
// Test the third case: documentation contains symbols (has a module) and also has @TechnologyRoot pages
223+
let (_, context) = try await loadBundle(catalog:
224+
Folder(name: "symbols-with-root.docc", content: [
225+
// Symbol graph with a module
226+
JSONFile(name: "MyModule.symbols.json", content: makeSymbolGraph(moduleName: "MyModule")),
227+
228+
// Article with @TechnologyRoot directive
229+
TextFile(name: "GettingStarted.md", utf8Content: """
230+
# Getting Started
231+
@Metadata {
232+
@TechnologyRoot
233+
}
234+
Learn how to use MyModule.
235+
"""),
236+
237+
// Another article with @TechnologyRoot directive
238+
TextFile(name: "Overview.md", utf8Content: """
239+
# Overview
240+
@Metadata {
241+
@TechnologyRoot
242+
}
243+
Overview of the technology.
244+
"""),
245+
])
246+
)
247+
248+
// Verify that we emit warnings for @TechnologyRoot directives when symbols are present
249+
let symbolsWithRootProblems = context.problems.filter { $0.diagnostic.identifier == "org.swift.docc.TechnologyRootWithSymbols" }
250+
XCTAssertEqual(symbolsWithRootProblems.count, 2, "Should emit warnings for both @TechnologyRoot directives when symbols are present")
251+
252+
// Verify the warnings are associated with the correct files
253+
let problemSources = symbolsWithRootProblems.compactMap { $0.diagnostic.source?.lastPathComponent }.sorted()
254+
XCTAssertEqual(problemSources, ["GettingStarted.md", "Overview.md"])
255+
256+
// Verify each warning has a solution to remove the TechnologyRoot directive
257+
for problem in symbolsWithRootProblems {
258+
XCTAssertEqual(problem.possibleSolutions.count, 1)
259+
let solution = try XCTUnwrap(problem.possibleSolutions.first)
260+
XCTAssertEqual(solution.summary, "Remove the 'TechnologyRoot' directive")
261+
XCTAssertEqual(solution.replacements.count, 1)
262+
}
263+
}
264+
221265
func testWarnsAboutMultipleMainModules() async throws {
222266
// Create a bundle with multiple symbol graphs for different modules
223267
let (_, context) = try await loadBundle(catalog:

0 commit comments

Comments
 (0)