Skip to content
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

Merged
merged 4 commits into from
Jan 4, 2024

Conversation

d-ronnqvist
Copy link
Contributor

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 there's only a single article in the catalog, that becomes the root.
  • Otherwise, if there's an article with the same file name as the catalog name, that's becomes the root.
  • Otherwise, synthesize a minimal root with the same name as the catalog.

If this looks like a decent approach then we should document this behavior somewhere before merging.

Dependencies

None.

Testing

One article

  • Create a new documentation catalog:
    mkdir MyCatalog.docc
  • Add a minimal article without a technology root:
    echo "# One article\n\nArticle abstract" > MyCatalog.docc/MyArticle.md
  • Preview documentation for the new catalog
    swift run docc preview MyCatalog.docc
  • Stop the preview server.

Article with same name as catalog

  • Add another article without a technology root to the catalog, with the same name as the catalog this time:
    echo "# Another article\n\nArticle abstract" > MyCatalog.docc/MyCatalog.md
  • Preview documentation for the catalog:
    swift run docc preview MyCatalog.docc
  • Stop the preview server.

Synthesized root page

  • Rename the second article so that it's no longer named the same as the catalog:
    mv MyCatalog.docc/MyCatalog.md MyCatalog.docc/OtherArticle.md
  • Preview documentation for the catalog:
    swift run docc preview MyCatalog.docc
  • Stop the preview server.

Checklist

Make sure you check off the following items. If they cannot be completed, provide a reason.

  • Added tests
  • Ran the ./bin/test script and it succeeded
  • Updated documentation if necessary

Comment on lines 1896 to 1901
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
}
Copy link
Member

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.

Copy link
Contributor Author

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

@sofiaromorales
Copy link
Member

sofiaromorales commented Jan 2, 2024

@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:

  1. Did you consider adding index.md as another replacement of the technology root?. This could be a fallback in case there's no markdown file with the same name as the doc catalog, but there's an article with the file name index.

  2. If we are moving ahead towards a direction where @TechnologyRoot is optional it might be a good idea to add some kind of deprecation note to that directive in the docs, where the use of the same name of the catalog, or index, is preferred over the use of the directive.

  3. I left a minor code comment, but overall this looks good to me. To merge it, tho, it's needed to post info about this in the swift forums first.

Regarding your question:

should this path be "documentation/mycatalog" instead?

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.

@d-ronnqvist
Copy link
Contributor Author

  1. Did you consider adding index.md as another replacement of the technology root?. This could be a fallback in case there's no markdown file with the same name as the doc catalog, but there's an article with the file name index.

I didn't but that's always something we can add later.

  1. If we are moving ahead towards a direction where @TechnologyRoot is optional it might be a good idea to add some kind of deprecation note to that directive in the docs, where the use of the same name of the catalog, or index, is preferred over the use of the directive.

We should find some way to document that @TechnologyRoot isn't always needed but I don't think we should deprecate. A developer may prefer to add @TechnologyRoot over renaming one of their articles.

  1. I left a minor code comment, but overall this looks good to me. To merge it, tho, it's needed to post info about this in the swift forums first.

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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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 }) {
Copy link
Member

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.

Suggested change
} 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.

Copy link
Contributor Author

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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

Copy link
Member

@sofiaromorales sofiaromorales left a 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 👍

@d-ronnqvist
Copy link
Contributor Author

@swift-ci please test

@d-ronnqvist
Copy link
Contributor Author

@swift-ci please test

@d-ronnqvist d-ronnqvist merged commit 5f57823 into apple:main Jan 4, 2024
2 checks passed
@d-ronnqvist d-ronnqvist deleted the optional-technology-root branch January 4, 2024 09:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants