-
Notifications
You must be signed in to change notification settings - Fork 473
JEP 413: Add support for @snippet tag in Javadoc
#4392
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
base: master
Are you sure you want to change the base?
Conversation
| children = listOf( | ||
| Text( | ||
| """ | ||
| |/* |
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.
In this test and the test below, WholeFileSnippet.java is used from resources, which contain copyright. The output of the test is whole file content including the copyright, which is expected. I’m concerned about whether this is okay, since the copyright header may be updated by a script in the future, which could break those tests. Should I change something here, or is it better to leave it as is?
| } | ||
|
|
||
| val substring = attributes["substring"]?.htmlEscape() | ||
| val regex = attributes["regex"]?.htmlEscape()?.toRegex() |
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.
htmlEscape is needed to apply here to match literal symbols such as [&, <, >, "], because htmlEscape function is applied to the raw line before applying any markup. But < and > can be used in regex constructs, for instance lookbehind. Should we adjust the logic to handle this, or leave it as is, given that such cases are quite rare and unlikely to occur?
Mentioned function:
public fun String.htmlEscape(): String = replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """)
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.
Do you really need htmlEscape here? It seems unnecessary, since the result is result.replace(regex) { match -> match.value.wrapInTag() } that is, the escaped value is not used in the returned value.
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.
htmlEscape is needed to match literal symbol such as [&, <, >, "], because htmlEscape function is applied to the raw line before applying any markup.
Without htmlEscape on regex following examples wont work:
// @replace regex='".*"' replacement="..."
or
// @replace regex='"(.*)"' replacement='"I said, $1"'
because " in regex pattern wont be matched, since " in the line were changed to the "
vmishenev
left a comment
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.
👍
|
|
||
| val psiFiles = sourceRoots.parallelMap { sourceRoot -> | ||
| sourceRoot.absoluteFile.walkTopDown().mapNotNull { | ||
| sourceRoot.absoluteFile.walkTopDown().filter { !it.path.contains("/snippet-files") }.mapNotNull { |
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.
minor: if sourceRoot contains "snippet-files/", the whole source root will be filter out. Can you fix it?
nitpick: filterNot is better for readability.
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.
see 61f298c
| snippet: PsiSnippetDocTag | ||
| ): String { | ||
| val value = snippet.valueElement ?: run { | ||
| logger.error("@snippet: unable to resolve snippet") |
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.
logger.warn is more appropriate here. logger.error is intended for more fatal conditions. See the KDoc for logger.error.
Also, could you add some information about the snippet, for example, its location? (and in the messages below)
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.
see 85d2ecc
...i/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/SnippetToHtmlConverter.kt
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| if (parsedSnippet.isBlank()) { | ||
| logger.error("@snippet: unable to resolve snippet") |
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.
nitpick:
logger.error("@snippet: unable to resolve snippet")
SNIPPET_NOT_RESOLVEDlooks like a code duplication. Maybe it’s better to extract it into a function.
...i/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/SnippetToHtmlConverter.kt
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| val substring = attributes["substring"]?.htmlEscape() | ||
| val regex = attributes["regex"]?.htmlEscape()?.toRegex() |
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.
Do you really need htmlEscape here? It seems unnecessary, since the result is result.replace(regex) { match -> match.value.wrapInTag() } that is, the escaped value is not used in the returned value.
dokka-subprojects/plugin-base/src/test/kotlin/parsers/javadoc/SnippetTest.kt
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.
Pull request overview
This PR implements support for the @snippet Javadoc tag introduced in JEP 413 (Java 18). The snippet tag provides a modern alternative to @code and <pre> blocks, with better support for generics, annotations, external files, regions, and markup features like highlighting, replacing, and linking.
Key changes include:
- Implementation of snippet parsing with support for inline snippets, external files from
snippet-files, and files from thesamplesconfiguration path - Support for snippet regions using
@start/@endmarkers - Support for markup tags (
@highlight,@replace,@link) within snippets - Updates to parser signatures to pass
DokkaSourceSetthrough the call chain to enable snippet path resolution
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| SnippetToHtmlConverter.kt | New file implementing the core snippet parsing and conversion logic with support for all JEP 413 features |
| PsiElementToHtmlConverter.kt | Integrates snippet converter into the Javadoc parsing pipeline |
| HtmlToDocTagConverter.kt | Adds lang attribute handling for <pre> tags to support language-specific code blocks |
| PsiDocTagParser.kt | Updated to pass DokkaContext and DokkaSourceSet through the parsing chain |
| JavadocParser.kt, JavaDocCommentParser.kt, DocCommentParser.kt | Updated signatures to accept and propagate DokkaSourceSet parameter |
| DokkaPsiParser.kt | Updated to pass sourceSet to documentation parsing methods |
| DefaultPsiToDocumentableTranslator.kt | Added filtering to exclude snippet-files directory from analysis |
| KotlinDocCommentParser.kt, DescriptorKotlinDocCommentParser.kt, KDocProvider.kt | Updated to propagate sourceSet through documentation parsing |
| DefaultSymbolToDocumentableTranslator.kt | Updated to pass sourceSet to Javadoc parsing |
| SyntheticElementDocumentationProvider.kt | Updated to accept and use sourceSet parameter |
| JavaAnalysisPlugin.kt | Refactored to pass DokkaContext to PsiDocTagParser at creation time |
| JavadocParserTest.kt | Package renamed from parsers to parsers.javadoc and minor test updates |
| SnippetTest.kt | Comprehensive test suite covering all snippet features and edge cases |
| Test resources | Sample snippet files for testing external snippet functionality |
| analysis-java-psi.api | Public API updates reflecting signature changes |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
...i/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/SnippetToHtmlConverter.kt
Outdated
Show resolved
Hide resolved
dokka-subprojects/plugin-base/src/test/resources/parsers/javadoc/snippets/ExternalSnippets.java
Outdated
Show resolved
Hide resolved
...-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DefaultPsiToDocumentableTranslator.kt
Outdated
Show resolved
Hide resolved
...i/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/SnippetToHtmlConverter.kt
Show resolved
Hide resolved
…ation and add unit test
Impl for #3005
Useful links:
https://bugs.openjdk.org/browse/JDK-8201533
https://blogs.oracle.com/javamagazine/java-javadoc-snippet/
https://docs.oracle.com/en/java/javase/21/javadoc/snippets.html
https://belief-driven-design.com/better-code-snippets-in-javadoc-b27f5
https://docs.oracle.com/en/java/javase/18/docs/specs/javadoc/doc-comment-spec.html