-
Notifications
You must be signed in to change notification settings - Fork 116
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
Make @TechnologyRoot
optional in article-only documentation
#778
Conversation
guard markup.childCount == 2, | ||
let blockDirective = markup.child(at: 1) as? BlockDirective, | ||
let metadata = Metadata(from: blockDirective, for: bundle, in: self) | ||
else { | ||
throw ContextError.unableToSynthesizeRootPage | ||
} |
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.
@d-ronnqvist Since markup
is a constant and this is a programmer error would this not be better handled with an assertion?
Removing the guard statement also lets us get rid of the throwing function, which I think it makes sense here because there's nothing that could fail during runtime in this function.
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'm a little bit hesitant to trusting the parsed content completely since it also contains the # \(title)
which comes from the bundle display name and I don't know if there's any content that a developer could accidentally put in there that would break the markup and cause a hard to debug crash.
That said, the markup is simple enough that I can manually construct it and avoid the parsing all together. I did this in 43ff6d4
@d-ronnqvist Thanks for working on this. I think this is a good idea, since it makes the entry barrier to this type of documentation way lower. Some comments:
Regarding your question:
I think that keeping it as currently works is best, since it is consistent with the behaviour of docc for other types of catalogs, where the URL last path component is the same as the top level file name. |
448ec15
to
43ff6d4
Compare
I didn't but that's always something we can add later.
We should find some way to document that
I can post something small in the forums about this to make people aware of the change but I don't think that it needs to block the PR. I view this more as a small enhancement than as a new feature. |
@@ -1874,6 +1874,52 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate { | |||
} | |||
} | |||
|
|||
private func synthesizeArticleOnlyRootPage(articles: inout [DocumentationContext.SemanticResult<Article>], bundle: DocumentationBundle) { |
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.
private func synthesizeArticleOnlyRootPage(articles: inout [DocumentationContext.SemanticResult<Article>], bundle: DocumentationBundle) { | |
/// Assigns or creates a top level page to the documentation. | |
/// | |
/// This method assigns a root to the only article in a single-article catalog, | |
/// to the article with the same file name as the catalog folder name, | |
/// or synthesizes a root with the same name as the catalog. | |
/// | |
/// - Parameters: | |
/// - articles: Non-root articles from the catalog. | |
/// - bundle: The bundle containing the articles. | |
private func synthesizeArticleOnlyRootPage(articles: inout [DocumentationContext.SemanticResult<Article>], bundle: DocumentationBundle) { |
var onlyArticle = articles.removeFirst() | ||
onlyArticle.value = Article(markup: onlyArticle.value.markup, metadata: metadata, redirects: onlyArticle.value.redirects, options: onlyArticle.value.options) | ||
registerRootPages(from: [onlyArticle], in: bundle) | ||
} else if let nameMatchIndex = articles.firstIndex(where: { $0.source.deletingPathExtension().lastPathComponent == title }) { |
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 is what takes to add the "index" as possible root, + the unit test ofc.
} else if let nameMatchIndex = articles.firstIndex(where: { $0.source.deletingPathExtension().lastPathComponent == title }) { | |
} else if let nameMatchIndex = articles.firstIndex(where: { $0.source.deletingPathExtension().lastPathComponent == title || $0.source.deletingPathExtension().lastPathComponent == "index" }) { | |
// This catalog has an article with the same name as the catalog itself, or an article named index, so we make that the root. |
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.
Yes, it's very easy to implement another file name as a possible root but I'm not convinced there's a strong use case for it. If people want their "index.md" file to be a root for their article-only documentation they can always add a @TechnologyRoot
directive to it.
What—in my opinion—makes the file matching the catalog name different is that that if we didn't turn that into a root page it would result in a "/documentation/CatalogName/CatalogName" URL (once for the catalog name and once for the article name) that I think people would find mildly surprising.
I searched for usages of "index.md" within documentation catalogs but almost all of the matches are for files that are the documentation extension of the module, so this wouldn't apply to those anyway. A refined search show 5 projects that have an "Index.md" / "index.md" file that isn't the documentation extension for the module.
- "Apollo" in "apollographql"
- "hummingbird-docs" in "hummingbird-project"
Already have @TechnologyRoot
directives but those catalog also has a module so any root page file name logic wouldn't apply.
- "Conformance" in "swift-protobuf"
- "SwiftyESBuild" in "tuist"
- "leetcode" in "rossmassey"
have modules in their catalogs so this root page file name logic wouldn't apply.
nameMatch.value = Article(markup: nameMatch.value.markup, metadata: metadata, redirects: nameMatch.value.redirects, options: nameMatch.value.options) | ||
registerRootPages(from: [nameMatch], in: bundle) | ||
} else { | ||
let path = NodeURLGenerator.Path.documentation(path: title).stringValue |
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.
let path = NodeURLGenerator.Path.documentation(path: title).stringValue | |
// Synthesize a minimal root with the same name as the catalog. | |
let path = NodeURLGenerator.Path.documentation(path: title).stringValue |
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.
Left minor comments about the code comments. Looks good to merge 👍
@swift-ci please test |
@swift-ci please test |
Bug/issue #, if applicable:
Summary
This makes
@TechnologyRoot
optional in article-only documentation.When building documentation for a catalog of only articles with no explicit root article, DocC will follow the following logic to find a root:
If this looks like a decent approach then we should document this behavior somewhere before merging.
Dependencies
None.
Testing
One article
mkdir MyCatalog.docc
echo "# One article\n\nArticle abstract" > MyCatalog.docc/MyArticle.md
swift run docc preview MyCatalog.docc
Question: should this path be "documentation/mycatalog" instead?
Article with same name as catalog
echo "# Another article\n\nArticle abstract" > MyCatalog.docc/MyCatalog.md
swift run docc preview MyCatalog.docc
Synthesized root page
mv MyCatalog.docc/MyCatalog.md MyCatalog.docc/OtherArticle.md
swift run docc preview MyCatalog.docc
Checklist
Make sure you check off the following items. If they cannot be completed, provide a reason.
./bin/test
script and it succeeded