-
Notifications
You must be signed in to change notification settings - Fork 146
Fix "missing technology root" warning for tutorials #812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix "missing technology root" warning for tutorials #812
Conversation
…mated- tutorials. rdar://117866037
Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift
Outdated
Show resolved
Hide resolved
Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift
Outdated
Show resolved
Hide resolved
Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift
Outdated
Show resolved
Hide resolved
Co-authored-by: mayaepps <[email protected]>
@@ -3071,31 +3071,71 @@ class ConvertActionTests: XCTestCase { | |||
|
|||
// Tests that when converting a catalog with no technology root a warning is raised (r93371988) | |||
func testConvertWithNoTechnologyRoot() throws { | |||
let bundle = Folder(name: "unit-test.docc", content: [ | |||
func convert(_ bundle: Folder) throws -> ConvertAction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's more common code in these 3 example catalogs that could moved into this test helper. Doing so would help focus the test on only the inputs and the expected problems. For example:
func problemsFromConverting(_ catalogContent: [File]) throws -> [Problem] {
let catalog = Folder(name: "unit-test.docc", content: catalogContent)
let testDataProvider = try TestFileSystem(folders: [catalog, Folder.emptyHTMLTemplateDirectory])
let engine = DiagnosticEngine()
var action = try ConvertAction(
documentationBundleURL: catalog.absoluteURL,
outOfProcessResolver: nil,
analyze: false,
targetDirectory: URL(fileURLWithPath: "/output"),
htmlTemplateDirectory: Folder.emptyHTMLTemplateDirectory.absoluteURL,
emitDigest: false,
currentPlatforms: nil,
dataProvider: testDataProvider,
fileManager: testDataProvider,
temporaryDirectory: URL(fileURLWithPath: "/tmp"),
diagnosticEngine: engine
)
_ = try action.perform(logHandle: .none)
return engine.problems
}
could be used like
let onlyTutorialArticleProblems = try problemsFromConverting([
InfoPlist(displayName: "TestBundle", identifier: "com.test.example"),
TextFile(name: "Article.tutorial", utf8Content: """
@Article(time: 20) {
@Intro(title: "Slothy Tutorials") {
This is an abstract for the intro.
}
}
"""
),
])
XCTAssert(onlyTutorialArticleProblems.contains(where: { $0.diagnostic.identifier == "org.swift.docc.MissingTechnologyRoot" }))
postConversionProblems.append( | ||
Problem( | ||
diagnostic: Diagnostic( | ||
severity: .warning, | ||
identifier: "org.swift.docc.MissingTechnologyRoot", | ||
summary: "No TechnologyRoot to organize article-only documentation.", | ||
explanation: "Article-only documentation needs a TechnologyRoot page (indicated by a `TechnologyRoot` directive within a `Metadata` directive) to define the root of the documentation hierarchy." | ||
summary: "There was no root found for this documentation catalog.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering recent changes to @TechnologyRoot
, I feel like this diagnostic is more general than it would more actionable if it focused on what's wrong and how to fix it.
Currently, there are a two different groups of cases that could result in this warning:
- The catalog could be "empty" (
context.knownPages.isEmpty
) - The catalog could have
@Tutorial
or@Article
files but no tutorial table of contents page (@Tutorials
)
The action that the developer would take to fix these two groups is different, so I think that it could make sense make one tailored diagnostic for each group of cases.
The "empty" catalog case has 3 different possibilities could happen if the catalog
- didn't contain any markdown files or tutorial files at all
- contains a markdown file that doesn't start with a level one heading, for example
Some content without a level one heading
- contains a documentation extension file but no input for symbol graph files
If the catalog truly has no files and no symbol graph input is provided to DocC, I don't know if it makes much sense to warn about it. We can, but it may not be all that informative and helpful to the developer.
If the article starts with anything other than a level one heading we already raise a "org.swift.docc.Article.Title.NotFound" warning with a fixit. If the article is completely empty, we don't seem to raise this warning. Maybe we should?
If the link in the documentation extension file doesn't resolve to a symbol, we already warn about the unresolved link.
So, I don't feel that it's necessary to raise a warning about the "empty" catalog cases but it's probably fine if we do.
The case where the catalog does contain one ore more @Tutorial
or @Article
files but no tutorial table of contents page (@Tutorials
) is a bit different from the "empty" catalog cases. The issue is very specific and there's a very specific way that the developer can fix it; add a @Tutorials
file1.
Given this, I feel like the issue would be clearer to the developer if this diagnostic focused on the missing table of contents issue.
postConversionProblems.append(
Problem(
diagnostic: Diagnostic(
severity: .warning,
identifier: "org.swift.docc.MissingTableOfContents",
summary: "Missing tutorial table of contents page.",
explanation: "`@Tutorial` and `@Article` pages require a `@Tutorials` table of content page to define the documentation hierarchy"
),
possibleSolutions: Solution(summary: "Create a `@Tutorials` table of content page", replacements: [])
)
)
Footnotes
-
A future enhancement could be to synthesize a minimal table of contents page if the developer doesn't create one—just like we do with the technology root—which would remove the need for this warning. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if fixits/solutions support defining new files or if they can only modify existing files. If it's possible to define a new file in a fixit/solution then maybe we could reuse the init command code to fill in most of the necessary information for the developer
let tableOfContentsFilename = "table-of-contents.tutorial"
let source = rootURL?.appendingPathComponent(tableOfContentsFilename)
Solution(
summary: "Create a `@Tutorials` table of content page",
replacements: [
Replacement(
range: .init(line: 1, column: 1, source: source) ..< .init(line: 1, column: 1, source: source),
replacement: CatalogTemplateKind.tutorialTemplateFiles(converter.firstAvailableBundle()?.displayName ?? "Project Name")[tableOfContentsFilename]! // this file name is known to exist in the dictionary
)
]
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added your suggestion and tweaked how formattedDiagnosticSource
works in order to be able to suggest addition of new content files without having to refactor the Replacement
struct.
guard let diagnosticRange = diagnostic.range
else {
// If the replacement operation involves adding new files,
// emit the file content as an addition instead of a replacement.
//
// Example:
// --> /path/to/new/file.md
// Summary
// suggestion:
// 0 + Addition file and
// 1 + multiline file content.
var addition = ""
solutions.forEach { solution in
addition.append("\n" + solution.summary)
solution.replacements.forEach { replacement in
let solutionFragments = replacement.replacement.split(separator: "\n")
addition += "\nsuggestion:\n" + solutionFragments.enumerated().map {
"\($0.offset) + \($0.element)"
}.joined(separator: "\n")
}
}
return "\n--> \(formattedSourcePath(url))\(addition)"
}
Since the diagnostic does not belongs to an existing range in the source code the diagnostic.range
will be nil and we log the suggestion.
This allows us to use fixits/solutions for defining new files instead of only modify existing files.
The other possible improvement to do here is making range
in Replacement
optional, but I don't know if that might be a breaking API change.
Implemented here d7720d9.
Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift
Outdated
Show resolved
Hide resolved
…o the diagnostic message. - Replaced `org.swift.docc.MissingTechnologyRoot` diagnostic for `org.swift.docc.MissingTableOfContents`
@swift-ci please test |
1 similar comment
@swift-ci please test |
@swift-ci please test |
Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift
Outdated
Show resolved
Hide resolved
Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me.
One comment about potentially adding one more test but I don't consider that blocking.
Sources/SwiftDocCUtilities/Action/Actions/Convert/ConvertAction.swift
Outdated
Show resolved
Hide resolved
@swift-ci please test |
@swift-ci please test |
@swift-ci please test |
1 similar comment
@swift-ci please test |
Bug/issue #, if applicable: rdar://117866037
Summary
When either previewing or converting a tutorial, the diagnostic engine was emitting a warning about a missing technology-root, even when the tutorial was well structured and with the appropriate root. This fix resolved the problem by also checking the context root technology.
Testing
Steps:
No TechnologyRoot to organize article-only documentation.
warning.Tutorial.docc.zip
Checklist
Make sure you check off the following items. If they cannot be completed, provide a reason.
./bin/test
script and it succeeded