diff options
89 files changed, 1195 insertions, 303 deletions
@@ -24,7 +24,7 @@ buildNumber.properties *.war *.ear -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +# virtual machine crash logs, see https://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* ### JetBrains template # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm @@ -1,4 +1,4 @@ -dokka [![official JetBrains project](http://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) +dokka [![official JetBrains project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![TeamCity (build status)](https://img.shields.io/teamcity/http/teamcity.jetbrains.com/s/Kotlin_Dokka_DokkaAntMavenGradle.svg)](https://teamcity.jetbrains.com/viewType.html?buildTypeId=Kotlin_Dokka_DokkaAntMavenGradle&branch_KotlinTools_Dokka=%3Cdefault%3E&tab=buildTypeStatusDiv) [ ![Download](https://api.bintray.com/packages/kotlin/dokka/dokka/images/download.svg) ](https://bintray.com/kotlin/dokka/dokka/_latestVersion) ===== @@ -26,7 +26,7 @@ apply plugin: 'org.jetbrains.dokka' ``` The plugin adds a task named "dokka" to the project. - + Minimal dokka configuration: ```groovy @@ -37,7 +37,7 @@ dokka { ``` [Output formats](#output_formats) - + The available configuration options are shown below: ```groovy @@ -52,7 +52,7 @@ dokka { } // List of files with module and package documentation - // http://kotlinlang.org/docs/reference/kotlin-doc.html#module-and-package-documentation + // https://kotlinlang.org/docs/reference/kotlin-doc.html#module-and-package-documentation includes = ['packages.md', 'extra.md'] // The list of files or directories containing sample code (referenced with @sample tags) @@ -100,19 +100,22 @@ dokka { // If provided, Dokka generates "source" links for each declaration. // Repeat for multiple mappings linkMapping { - // Source directory - dir = "src/main/kotlin" + // Unix based directory relative path to the root of the project (where you execute gradle respectively). + dir = "src/main/kotlin" // or simply "./" // URL showing where the source code can be accessed through the web browser - url = "https://github.com/cy6erGn0m/vertx3-lang-kotlin/blob/master/src/main/kotlin" + url = "https://github.com/cy6erGn0m/vertx3-lang-kotlin/blob/master/src/main/kotlin" //remove src/main/kotlin if you use "./" above // Suffix which is used to append the line number to the URL. Use #L for GitHub suffix = "#L" } - // No default documentation link to kotlin-stdlib + // Disable linking to online kotlin-stdlib documentation noStdlibLink = false + // Disable linking to online JDK documentation + noJdkLink = false + // Allows linking to documentation of the project's dependencies (generated with Javadoc or Dokka) // Repeat for multiple links externalDocumentationLink { @@ -157,6 +160,28 @@ task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) { Please see the [Dokka Gradle example project](https://github.com/JetBrains/kotlin-examples/tree/master/gradle/dokka-gradle-example) for an example. +#### Dokka Runtime +If you are using Gradle plugin and you want to change the version of Dokka, you can do it by setting `dokkaRuntime`: + +```groovy +buildscript { + ... +} + +apply plugin: 'org.jetbrains.dokka' + +repositories { + jcenter() +} + +dependencies { + dokkaRuntime "org.jetbrains.dokka:dokka-fatjar:0.9.18" +} +``` + +#### FAQ +Please see the [FAQ](https://github.com/Kotlin/dokka/wiki/faq). + #### Android If you are using Android there is a separate Gradle plugin. Just make sure you apply the plugin after @@ -250,7 +275,7 @@ The available configuration options are shown below: <cacheRoot>default</cacheRoot> <!-- List of '.md' files with package and module docs --> - <!-- http://kotlinlang.org/docs/reference/kotlin-doc.html#module-and-package-documentation --> + <!-- https://kotlinlang.org/docs/reference/kotlin-doc.html#module-and-package-documentation --> <includes> <file>packages.md</file> <file>extra.md</file> @@ -263,7 +288,7 @@ The available configuration options are shown below: <!-- Used for linking to JDK, default: 6 --> <jdkVersion>6</jdkVersion> - + <!-- Do not output deprecated members, applies globally, can be overridden by packageOptions --> <skipDeprecated>false</skipDeprecated> <!-- Emit warnings about not documented members, applies globally, also can be overridden by packageOptions --> @@ -297,15 +322,18 @@ The available configuration options are shown below: <!-- Source directory --> <dir>${project.basedir}/src/main/kotlin</dir> <!-- URL showing where the source code can be accessed through the web browser --> - <url>http://github.com/me/myrepo</url> + <url>https://github.com/cy6erGn0m/vertx3-lang-kotlin/blob/master/src/main/kotlin</url> <!-- //remove src/main/kotlin if you use "./" above --> <!--Suffix which is used to append the line number to the URL. Use #L for GitHub --> <urlSuffix>#L</urlSuffix> </link> </sourceLinks> - <!-- No default documentation link to kotlin-stdlib --> + <!-- Disable linking to online kotlin-stdlib documentation --> <noStdlibLink>false</noStdlibLink> + <!-- Disable linking to online JDK documentation --> + <noJdkLink>false</noJdkLink> + <!-- Allows linking to documentation of the project's dependencies (generated with Javadoc or Dokka) --> <externalDocumentationLinks> <link> @@ -365,11 +393,12 @@ The Ant task supports the following attributes: * `<sourceRoot path="src" platforms="JVM" />` - analogue of src, but allows to specify [platforms](#platforms) * `<packageOptions prefix="kotlin" includeNonPublic="false" reportUndocumented="true" skipDeprecated="false"/>` - Per package options for package `kotlin` and sub-packages of it - * `noStdlibLink` - No default documentation link to kotlin-stdlib + * `noStdlibLink` - disable linking to online kotlin-stdlib documentation + * `noJdkLink` - disable linking to online JDK documentation * `<externalDocumentationLink url="https://example.com/docs/" packageListUrl="file:///home/user/localdocs/package-list"/>` - linking to external documentation, packageListUrl should be used if package-list located not in standard location * `cacheRoot` - Use `default` or set to custom path to cache directory to enable package-list caching. When set to `default`, caches stored in $USER_HOME/.cache/dokka - + ### Using the Command Line @@ -387,20 +416,21 @@ Dokka supports the following command line arguments: * `-module` - the name of the module being documented (used as the root directory of the generated documentation) * `-include` - names of files containing the documentation for the module and individual packages * `-nodeprecated` - if set, deprecated elements are not included in the generated documentation - * `-impliedPlatforms` - List of implied platforms (comma-separated) - * `-packageOptions` - List of package options in format `prefix,-deprecated,-privateApi,+warnUndocumented;...` - * `-links` - External documentation links in format `url^packageListUrl^^url2...` - * `-noStdlibLink` - Disable documentation link to stdlib - * `-cacheRoot` - Use `default` or set to custom path to cache directory to enable package-list caching. When set to `default`, caches stored in $USER_HOME/.cache/dokka + * `-impliedPlatforms` - list of implied platforms (comma-separated) + * `-packageOptions` - list of package options in format `prefix,-deprecated,-privateApi,+warnUndocumented;...` + * `-links` - external documentation links in format `url^packageListUrl^^url2...` + * `-noStdlibLink` - disable linking to online kotlin-stdlib documentation + * `-noJdkLink` - disable linking to online JDK documentation + * `-cacheRoot` - use `default` or set to custom path to cache directory to enable package-list caching. When set to `default`, caches stored in $USER_HOME/.cache/dokka ### Output formats<a name="output_formats"></a> - * `html` - minimalistic html format used by default - * `javadoc` - Dokka mimic to javadoc - * `html-as-java` - as `html` but using java syntax - * `markdown` - Markdown structured as `html` - * `gfm` - GitHub flavored markdown + * `html` - minimalistic html format used by default, Java classes are translated to Kotlin + * `javadoc` - looks like normal Javadoc, Kotlin classes are translated to Java + * `html-as-java` - looks like `html`, but Kotlin classes are translated to Java + * `markdown` - markdown structured as `html`, Java classes are translated to Kotlin + * `gfm` - GitHub flavored markdown * `jekyll` - Jekyll compatible markdown * `kotlin-website*` - internal format used for documentation on [kotlinlang.org](https://kotlinlang.org) diff --git a/build.gradle b/build.gradle index 0825e389..ae8701ca 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ allprojects { if (project == rootProject) { println "Publication version: $dokka_version" } - + group 'org.jetbrains.dokka' version dokka_version diff --git a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt index f26829b0..603fd0e4 100644 --- a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt +++ b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt @@ -269,29 +269,32 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl return ResolverForProjectImpl( debugName = "Dokka", projectContext = projectContext, - modules = listOf(module, library), - modulesContent = modulesContent, + modules = listOf(library, module), + modulesContent = { + when (it) { + library -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope)) + module -> ModuleContent(it, emptyList(), sourcesScope) + else -> throw IllegalArgumentException("Unexpected module info") + } + }, modulePlatforms = { JvmPlatform.multiTargetPlatform }, moduleLanguageSettingsProvider = LanguageSettingsProvider.Default /* TODO: Fix this */, resolverForModuleFactoryByPlatform = { JvmAnalyzerFacade }, - platformParameters = { targetPlaftorm -> - JvmPlatformParameters( - { content -> - JvmPackagePartProvider( - configuration.languageVersionSettings, - content.moduleContentScope - ).apply { - this.addRoots(javaRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)) + platformParameters = { + JvmPlatformParameters ({ content -> + JvmPackagePartProvider( + configuration.languageVersionSettings, + content.moduleContentScope) + .apply { + addRoots(javaRoots, messageCollector) } - } - ) { it -> + }, { val file = (it as JavaClassImpl).psi.containingFile.virtualFile if (file in sourcesScope) module else library - - } + }) }, targetEnvironment = CompilerEnvironment, builtIns = builtIns diff --git a/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt b/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt index ffd95da2..319d85b1 100644 --- a/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt +++ b/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt @@ -20,10 +20,10 @@ import com.intellij.openapi.vfs.VirtualFileFilter import com.intellij.psi.search.GlobalSearchScope import com.intellij.util.messages.MessageBus import org.jetbrains.jps.model.module.JpsModuleSourceRootType -import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot -import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot import org.jetbrains.kotlin.cli.common.config.ContentRoot import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot +import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot +import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot import org.picocontainer.PicoContainer import java.io.File diff --git a/core/src/main/kotlin/Formats/StructuredFormatService.kt b/core/src/main/kotlin/Formats/StructuredFormatService.kt index 46c7f1af..04810498 100644 --- a/core/src/main/kotlin/Formats/StructuredFormatService.kt +++ b/core/src/main/kotlin/Formats/StructuredFormatService.kt @@ -205,6 +205,10 @@ abstract class StructuredOutputBuilder(val to: StringBuilder, } } + is NodeRenderContent -> { + val node = content.node + appendContent(languageService.render(node, content.mode)) + } is ContentNodeLink -> { val node = content.node val linkTo = if (node != null) locationHref(location, node, generator) else "#" diff --git a/core/src/main/kotlin/Generation/DokkaGenerator.kt b/core/src/main/kotlin/Generation/DokkaGenerator.kt index 9173dfbb..90d7cfcc 100644 --- a/core/src/main/kotlin/Generation/DokkaGenerator.kt +++ b/core/src/main/kotlin/Generation/DokkaGenerator.kt @@ -18,7 +18,6 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot -import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer diff --git a/core/src/main/kotlin/Generation/configurationImpl.kt b/core/src/main/kotlin/Generation/configurationImpl.kt index 61f3f902..46174198 100644 --- a/core/src/main/kotlin/Generation/configurationImpl.kt +++ b/core/src/main/kotlin/Generation/configurationImpl.kt @@ -11,9 +11,9 @@ data class SourceLinkDefinitionImpl(override val path: String, companion object { fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinition { val (path, urlAndLine) = srcLink.split('=') - return SourceLinkDefinitionImpl(File(path).absolutePath, + return SourceLinkDefinitionImpl(File(path).canonicalPath, urlAndLine.substringBefore("#"), - urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#" + it }) + urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#$it" }) } } } @@ -69,7 +69,7 @@ class PassConfigurationImpl ( private val defaultLinks = run { val links = mutableListOf<DokkaConfiguration.ExternalDocumentationLink>() if (!noJdkLink) - links += DokkaConfiguration.ExternalDocumentationLink.Builder("http://docs.oracle.com/javase/$jdkVersion/docs/api/").build() + links += DokkaConfiguration.ExternalDocumentationLink.Builder("https://docs.oracle.com/javase/$jdkVersion/docs/api/").build() if (!noStdlibLink) links += DokkaConfiguration.ExternalDocumentationLink.Builder("https://kotlinlang.org/api/latest/jvm/stdlib/").build() diff --git a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt index 1fe4d180..98d56856 100644 --- a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt +++ b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt @@ -6,6 +6,7 @@ import com.intellij.psi.* import com.intellij.psi.impl.JavaConstantExpressionEvaluator import com.intellij.psi.util.InheritanceUtil import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration import org.jetbrains.kotlin.asJava.elements.KtLightElement import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag @@ -19,11 +20,19 @@ fun getSignature(element: PsiElement?) = when(element) { is PsiClass -> element.qualifiedName is PsiField -> element.containingClass!!.qualifiedName + "$" + element.name is PsiMethod -> - element.containingClass!!.qualifiedName + "$" + element.name + "(" + - element.parameterList.parameters.map { it.type.typeSignature() }.joinToString(",") + ")" + methodSignature(element) + is PsiParameter -> { + val method = (element.parent.parent as PsiMethod) + methodSignature(method) + } else -> null } +private fun methodSignature(method: PsiMethod): String { + return method.containingClass!!.qualifiedName + "$" + method.name + "(" + + method.parameterList.parameters.map { it.type.typeSignature() }.joinToString(",") + ")" +} + private fun PsiType.typeSignature(): String = when(this) { is PsiArrayType -> "Array((${componentType.typeSignature()}))" is PsiPrimitiveType -> "kotlin." + canonicalText.capitalize() @@ -100,9 +109,11 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { fun nodeForElement(element: PsiNamedElement, kind: NodeKind, - name: String = element.name ?: "<anonymous>"): DocumentationNode { + name: String = element.name ?: "<anonymous>", + register: Boolean = false): DocumentationNode { val (docComment, deprecatedContent) = docParser.parseDocumentation(element) val node = DocumentationNode(name, docComment, kind) + if (register) register(element, node) if (element is PsiModifierListOwner) { node.appendModifiers(element) val modifierList = element.modifierList @@ -171,13 +182,13 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { fun PsiClass.build(): DocumentationNode { val kind = when { + isAnnotationType -> NodeKind.AnnotationClass isInterface -> NodeKind.Interface isEnum -> NodeKind.Enum - isAnnotationType -> NodeKind.AnnotationClass isException() -> NodeKind.Exception else -> NodeKind.Class } - val node = nodeForElement(this, kind) + val node = nodeForElement(this, kind, register = isAnnotationType) superTypes.filter { !ignoreSupertype(it) }.forEach { node.appendType(it, NodeKind.Supertype) val superClass = it.resolve() @@ -219,11 +230,11 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { private fun DocumentationNode.appendConstantValueIfAny(field: PsiField) { val modifierList = field.modifierList ?: return val initializer = field.initializer ?: return - if (field.type is PsiPrimitiveType && - modifierList.hasExplicitModifier(PsiModifier.FINAL) && + if (modifierList.hasExplicitModifier(PsiModifier.FINAL) && modifierList.hasExplicitModifier(PsiModifier.STATIC)) { val value = JavaConstantExpressionEvaluator.computeConstantExpression(initializer, false) val text = when(value) { + null -> return // No value found is String -> "\"" + StringUtil.escapeStringCharacters(value) + "\"" else -> value.toString() @@ -301,8 +312,26 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { return node } + private fun lookupOrBuildClass(psiClass: PsiClass): DocumentationNode { + val existing = refGraph.lookup(getSignature(psiClass)!!) + if (existing != null) return existing + val new = psiClass.build() + val packageNode = findOrCreatePackageNode(null, (psiClass.parent as PsiJavaFile).packageName, emptyMap(), refGraph) + packageNode.append(new, RefKind.Member) + return new + } + fun PsiAnnotation.build(): DocumentationNode { - val node = DocumentationNode(nameReferenceElement?.text ?: "<?>", Content.Empty, NodeKind.Annotation) + + val original = when (this) { + is KtLightAbstractAnnotation -> clsDelegate + else -> this + } + val node = DocumentationNode(qualifiedName?.substringAfterLast(".") ?: "<?>", Content.Empty, NodeKind.Annotation) + val psiClass = original.nameReferenceElement?.resolve() as? PsiClass + if (psiClass != null && psiClass.isAnnotationType) { + node.append(lookupOrBuildClass(psiClass), RefKind.Link) + } parameterList.attributes.forEach { val parameter = DocumentationNode(it.name ?: "value", Content.Empty, NodeKind.Parameter) val value = it.value diff --git a/core/src/main/kotlin/Java/JavadocParser.kt b/core/src/main/kotlin/Java/JavadocParser.kt index 9f9ea017..70af73f9 100644 --- a/core/src/main/kotlin/Java/JavadocParser.kt +++ b/core/src/main/kotlin/Java/JavadocParser.kt @@ -1,11 +1,9 @@ package org.jetbrains.dokka import com.intellij.psi.* -import com.intellij.psi.impl.source.javadoc.CorePsiDocTagValueImpl import com.intellij.psi.impl.source.tree.JavaDocElementType import com.intellij.psi.javadoc.* import com.intellij.psi.util.PsiTreeUtil -import com.intellij.util.IncorrectOperationException import com.intellij.util.containers.isNullOrEmpty import org.jetbrains.kotlin.utils.keysToMap import org.jsoup.Jsoup @@ -33,30 +31,29 @@ class JavadocParser( private fun ContentSection.appendTypeElement(signature: String, selector: (DocumentationNode) -> DocumentationNode?) { append(LazyContentBlock { - val node = refGraph.lookupOrWarn(signature, logger)?.let(selector) - if (node != null) { - it.append(NodeRenderContent(node, LanguageService.RenderMode.SUMMARY)) - it.symbol(":") - it.text(" ") - } + val node = refGraph.lookupOrWarn(signature, logger)?.let(selector) ?: return@LazyContentBlock emptyList() + listOf(ContentBlock().apply { + append(NodeRenderContent(node, LanguageService.RenderMode.SUMMARY)) + symbol(":") + text(" ") + }) }) } override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult { - val docComment = (element as? PsiDocCommentOwner)?.docComment - if (docComment == null) return JavadocParseResult.Empty + val docComment = (element as? PsiDocCommentOwner)?.docComment ?: return JavadocParseResult.Empty val result = MutableContent() var deprecatedContent: Content? = null + + val nodes = convertJavadocElements(docComment.descriptionElements.dropWhile { it.text.trim().isEmpty() }, element) + val firstParagraphContents = nodes.takeWhile { it !is ContentParagraph } val firstParagraph = ContentParagraph() - firstParagraph.convertJavadocElements(docComment.descriptionElements.dropWhile { it.text.trim().isEmpty() }, element) - val paragraphs = firstParagraph.children.dropWhile { it !is ContentParagraph } - firstParagraph.children.removeAll(paragraphs) - if (!firstParagraph.isEmpty()) { + if (firstParagraphContents.isNotEmpty()) { + firstParagraphContents.forEach { firstParagraph.append(it) } result.append(firstParagraph) } - paragraphs.forEach { - result.append(it) - } + + result.appendAll(nodes.drop(firstParagraphContents.size)) if (element is PsiMethod) { val tagsByName = element.searchInheritedTags() @@ -67,14 +64,16 @@ class JavadocParser( when (tagName) { "param" -> { section.appendTypeElement(signature) { - it.details.find { it.kind == NodeKind.Parameter }?.detailOrNull(NodeKind.Type) + it.details + .find { node -> node.kind == NodeKind.Parameter && node.name == tag.getSubjectName() } + ?.detailOrNull(NodeKind.Type) } } "return" -> { section.appendTypeElement(signature) { it.detailOrNull(NodeKind.Type) } } } - section.convertJavadocElements(tag.contentElements(), context) + section.appendAll(convertJavadocElements(tag.contentElements(), context)) } } } @@ -84,7 +83,7 @@ class JavadocParser( "see" -> result.convertSeeTag(tag) "deprecated" -> { deprecatedContent = Content().apply { - convertJavadocElements(tag.contentElements(), element) + appendAll(convertJavadocElements(tag.contentElements(), element)) } } in tagsToInherit -> {} @@ -92,7 +91,7 @@ class JavadocParser( val subjectName = tag.getSubjectName() val section = result.addSection(javadocSectionDisplayName(tag.name), subjectName) - section.convertJavadocElements(tag.contentElements(), element) + section.appendAll(convertJavadocElements(tag.contentElements(), element)) } } } @@ -133,13 +132,17 @@ class JavadocParser( return if (getSubjectName() != null) tagValueElements.dropWhile { it is PsiDocTagValue } else tagValueElements } - private fun ContentBlock.convertJavadocElements(elements: Iterable<PsiElement>, element: PsiNamedElement) { + private fun convertJavadocElements(elements: Iterable<PsiElement>, element: PsiNamedElement): List<ContentNode> { val doc = Jsoup.parse(expandAllForElements(elements, element)) - doc.body().childNodes().forEach { - convertHtmlNode(it)?.let { append(it) } + return doc.body().childNodes().mapNotNull { + convertHtmlNode(it) } } + private fun ContentBlock.appendAll(nodes: List<ContentNode>) { + nodes.forEach { append(it) } + } + private fun expandAllForElements(elements: Iterable<PsiElement>, element: PsiNamedElement): String { val htmlBuilder = StringBuilder() elements.forEach { @@ -152,28 +155,30 @@ class JavadocParser( return htmlBuilder.toString().trim() } - private fun convertHtmlNode(node: Node): ContentNode? { + private fun convertHtmlNode(node: Node, insidePre: Boolean = false): ContentNode? { if (node is TextNode) { - return ContentText(node.text()) + val text = if (insidePre) node.wholeText else node.text() + return ContentText(text) } else if (node is Element) { - val childBlock = createBlock(node) + val childBlock = createBlock(node, insidePre) + node.childNodes().forEach { - val child = convertHtmlNode(it) + val child = convertHtmlNode(it, insidePre || childBlock is ContentBlockCode) if (child != null) { childBlock.append(child) } } - return (childBlock) + return childBlock } return null } - private fun createBlock(element: Element): ContentBlock = when (element.tagName()) { + private fun createBlock(element: Element, insidePre: Boolean): ContentBlock = when (element.tagName()) { "p" -> ContentParagraph() "b", "strong" -> ContentStrong() "i", "em" -> ContentEmphasis() "s", "del" -> ContentStrikethrough() - "code" -> ContentCode() + "code" -> if (insidePre) ContentBlock() else ContentCode() "pre" -> ContentBlockCode() "ul" -> ContentUnorderedList() "ol" -> ContentOrderedList() diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt index d0650d45..ddd8a32a 100644 --- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt +++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt @@ -19,6 +19,8 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.constants.StringValue @@ -38,10 +40,10 @@ class DescriptorDocumentationParser val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver ) { - fun parseDocumentation(descriptor: DeclarationDescriptor, inline: Boolean = false): Content = - parseDocumentationAndDetails(descriptor, inline).first + fun parseDocumentation(descriptor: DeclarationDescriptor, inline: Boolean = false, isDefaultNoArgConstructor: Boolean = false): Content = + parseDocumentationAndDetails(descriptor, inline, isDefaultNoArgConstructor).first - fun parseDocumentationAndDetails(descriptor: DeclarationDescriptor, inline: Boolean = false): Pair<Content, (DocumentationNode) -> Unit> { + fun parseDocumentationAndDetails(descriptor: DeclarationDescriptor, inline: Boolean = false, isDefaultNoArgConstructor: Boolean = false): Pair<Content, (DocumentationNode) -> Unit> { if (descriptor is JavaClassDescriptor || descriptor is JavaCallableMemberDescriptor) { return parseJavadoc(descriptor) } @@ -62,7 +64,10 @@ class DescriptorDocumentationParser ?.resolveToDescriptorIfAny() ?: descriptor - var kdocText = kdoc.getContent() + var kdocText = if (isDefaultNoArgConstructor) { + getConstructorTagContent(descriptor) ?: kdoc.getContent() + } else kdoc.getContent() + // workaround for code fence parsing problem in IJ markdown parser if (kdocText.endsWith("```") || kdocText.endsWith("~~~")) { kdocText += "\n" @@ -90,6 +95,13 @@ class DescriptorDocumentationParser return content to { node -> } } + private fun getConstructorTagContent(descriptor: DeclarationDescriptor): String? { + return ((DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.navigationElement as? KtElement) as KtDeclaration).docComment?.findSectionByTag( + KDocKnownTag.CONSTRUCTOR + )?.getContent() + } + + private fun DeclarationDescriptor.isSuppressWarning() : Boolean { val suppressAnnotation = annotations.findAnnotation(FqName(Suppress::class.qualifiedName!!)) return if (suppressAnnotation != null) { diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt index 205b44bd..e3f7c35b 100644 --- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt +++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt @@ -2,7 +2,6 @@ package org.jetbrains.dokka import com.google.inject.Inject import com.intellij.openapi.util.text.StringUtil -import com.intellij.psi.PsiField import com.intellij.psi.PsiJavaFile import org.jetbrains.dokka.DokkaConfiguration.PassConfiguration import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser @@ -24,7 +23,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtModifierListOwner import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.psi.KtVariableDeclaration +import org.jetbrains.kotlin.psi.addRemoveModifier.MODIFIERS_ORDER import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.descriptorUtil.* @@ -298,7 +297,11 @@ class DocumentationBuilder fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) { val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return appendInline(descriptor, psi) - KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach { + KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { + it !in knownModifiers + }.sortedBy { + MODIFIERS_ORDER.indexOf(it) + }.forEach { if (psi.hasModifier(it)) { appendTextNode(it.value, NodeKind.Modifier) } @@ -772,13 +775,7 @@ class DocumentationBuilder } if (isConst) { - val psi = sourcePsi() - val valueText = when (psi) { - is KtVariableDeclaration -> psi.initializer?.text - is PsiField -> psi.initializer?.text - else -> null - } - valueText?.let { node.appendTextNode(it, NodeKind.Value) } + this.compileTimeInitializer?.toDocumentationNode()?.let { node.append(it, RefKind.Detail) } } @@ -903,8 +900,8 @@ class DocumentationBuilder return node } - fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value?.let { value -> - when (value) { + fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value.let { value -> + val text = when (value) { is String -> "\"" + StringUtil.escapeStringCharacters(value) + "\"" is EnumEntrySyntheticClassDescriptor -> @@ -917,10 +914,9 @@ class DocumentationBuilder value.toString() } } - else -> value.toString() - }.let { valueString -> - DocumentationNode(valueString, Content.Empty, NodeKind.Value) + else -> "$value" } + DocumentationNode(text, Content.Empty, NodeKind.Value) } diff --git a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt index be6dd2e1..6e58f766 100644 --- a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt +++ b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt @@ -6,9 +6,11 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiNamedElement import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtPropertyAccessor @@ -59,8 +61,9 @@ class KotlinAsJavaDocumentationParser return JavadocParseResult.Empty } } + val isDefaultNoArgConstructor = kotlinLightElement is KtLightMethod && origin is KtClass val descriptor = resolutionFacade.resolveToDescriptor(origin) - val content = descriptorDocumentationParser.parseDocumentation(descriptor, origin is KtParameter) + val content = descriptorDocumentationParser.parseDocumentation(descriptor, origin is KtParameter, isDefaultNoArgConstructor) return JavadocParseResult(content, null) } } diff --git a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt index ba67d93d..daa09cbf 100644 --- a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt +++ b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt @@ -11,7 +11,7 @@ class KotlinLanguageService : CommonLanguageService() { } private val fullOnlyModifiers = - setOf("public", "protected", "private", "inline", "noinline", "crossinline", "reified") + setOf("public", "protected", "private", "internal", "inline", "noinline", "crossinline", "reified") override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode { return content { @@ -166,8 +166,18 @@ class KotlinLanguageService : CommonLanguageService() { keyword("dynamic") return } + + val nullabilityModifier = node.detailOrNull(NodeKind.NullabilityModifier) + if (node.isFunctionalType()) { - renderFunctionalType(node, renderMode) + if (nullabilityModifier != null) { + symbol("(") + renderFunctionalType(node, renderMode) + symbol(")") + symbol(nullabilityModifier.name) + } else { + renderFunctionalType(node, renderMode) + } return } if (renderMode == RenderMode.FULL) { @@ -185,8 +195,8 @@ class KotlinLanguageService : CommonLanguageService() { } symbol(">") } - val nullabilityModifier = node.details(NodeKind.NullabilityModifier).singleOrNull() - if (nullabilityModifier != null) { + + nullabilityModifier ?.apply { symbol(nullabilityModifier.name) } } @@ -201,7 +211,7 @@ class KotlinLanguageService : CommonLanguageService() { "final", "public", "var", "expect", "actual", "external" -> { } else -> { - if (node.name !in fullOnlyModifiers || renderMode == RenderMode.FULL) { + if (showModifierInSummary(node) || renderMode == RenderMode.FULL) { super.renderModifier(block, node, renderMode, nowrap) } } diff --git a/core/src/main/kotlin/Model/Content.kt b/core/src/main/kotlin/Model/Content.kt index 77451d41..8312b2e2 100644 --- a/core/src/main/kotlin/Model/Content.kt +++ b/core/src/main/kotlin/Model/Content.kt @@ -35,13 +35,13 @@ class NodeRenderContent( get() = 0 //TODO: Clarify? } -class LazyContentBlock(private val fillChildren: (ContentBlock) -> Unit) : ContentBlock() { +class LazyContentBlock(private val fillChildren: () -> List<ContentNode>) : ContentBlock() { private var computed = false override val children: ArrayList<ContentNode> get() { if (!computed) { computed = true - fillChildren(this) + children.addAll(fillChildren()) } return super.children } @@ -115,6 +115,7 @@ class ContentBlockSampleCode(language: String = "kotlin", val importsBlock: Cont abstract class ContentNodeLink() : ContentBlock() { abstract val node: DocumentationNode? + abstract val text: String? } object ContentHardLineBreak : ContentNode { @@ -128,6 +129,8 @@ class ContentNodeDirectLink(override val node: DocumentationNode): ContentNodeLi override fun hashCode(): Int = children.hashCode() * 31 + node.name.hashCode() + + override val text: String? = null } class ContentNodeLazyLink(val linkText: String, val lazyNode: () -> DocumentationNode?): ContentNodeLink() { @@ -138,6 +141,8 @@ class ContentNodeLazyLink(val linkText: String, val lazyNode: () -> Documentatio override fun hashCode(): Int = children.hashCode() * 31 + linkText.hashCode() + + override val text: String? = linkText } class ContentExternalLink(val href : String) : ContentBlock() { diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt index 617816b3..1ff14ff1 100644 --- a/core/src/main/kotlin/Model/DocumentationNode.kt +++ b/core/src/main/kotlin/Model/DocumentationNode.kt @@ -203,17 +203,20 @@ val DocumentationNode.path: List<DocumentationNode> } fun findOrCreatePackageNode(module: DocumentationNode?, packageName: String, packageContent: Map<String, Content>, refGraph: NodeReferenceGraph): DocumentationNode { - val existingNode = refGraph.lookup(packageName) - if (existingNode != null) { - return existingNode - } - val newNode = DocumentationNode(packageName, + val node = refGraph.lookup(packageName) ?: run { + val newNode = DocumentationNode( + packageName, packageContent.getOrElse(packageName) { Content.Empty }, - NodeKind.Package) + NodeKind.Package + ) - refGraph.register(packageName, newNode) - module?.append(newNode, RefKind.Member) - return newNode + refGraph.register(packageName, newNode) + newNode + } + if (module != null && node !in module.members) { + module.append(node, RefKind.Member) + } + return node } fun DocumentationNode.append(child: DocumentationNode, kind: RefKind) { @@ -240,7 +243,7 @@ fun DocumentationNode.qualifiedName(): String { } else if (kind == NodeKind.Package) { return name } - return path.drop(1).map { it.name }.filter { it.length > 0 }.joinToString(".") + return path.dropWhile { it.kind == NodeKind.Module }.map { it.name }.filter { it.isNotEmpty() }.joinToString(".") } fun DocumentationNode.simpleName() = name.substringAfterLast('.') diff --git a/core/src/main/kotlin/Model/SourceLinks.kt b/core/src/main/kotlin/Model/SourceLinks.kt index 2c75cfda..99ee362e 100644 --- a/core/src/main/kotlin/Model/SourceLinks.kt +++ b/core/src/main/kotlin/Model/SourceLinks.kt @@ -10,20 +10,20 @@ import java.io.File fun DocumentationNode.appendSourceLink(psi: PsiElement?, sourceLinks: List<SourceLinkDefinition>) { val path = psi?.containingFile?.virtualFile?.path ?: return + val canonicalPath = File(path).canonicalPath val target = if (psi is PsiNameIdentifierOwner) psi.nameIdentifier else psi - val absPath = File(path).absolutePath - val linkDef = sourceLinks.firstOrNull { absPath.startsWith(it.path) } - if (linkDef != null) { - var url = linkDef.url + path.substring(linkDef.path.length) - if (linkDef.lineSuffix != null) { + val pair = determineSourceLinkDefinition(canonicalPath, sourceLinks) + if (pair != null) { + val (sourceLinkDefinition, sourceLinkCanonicalPath) = pair + var url = determineUrl(canonicalPath, sourceLinkDefinition, sourceLinkCanonicalPath) + if (sourceLinkDefinition.lineSuffix != null) { val line = target?.lineNumber() if (line != null) { - url += linkDef.lineSuffix + line.toString() + url += sourceLinkDefinition.lineSuffix + line.toString() } } - append(DocumentationNode(url, Content.Empty, NodeKind.SourceUrl), - RefKind.Detail); + append(DocumentationNode(url, Content.Empty, NodeKind.SourceUrl), RefKind.Detail) } if (target != null) { @@ -31,6 +31,28 @@ fun DocumentationNode.appendSourceLink(psi: PsiElement?, sourceLinks: List<Sourc } } +private fun determineSourceLinkDefinition( + canonicalPath: String, + sourceLinks: List<SourceLinkDefinition> +): Pair<SourceLinkDefinition, String>? { + return sourceLinks + .asSequence() + .map { it to File(it.path).canonicalPath } + .firstOrNull { (_, sourceLinkCanonicalPath) -> + canonicalPath.startsWith(sourceLinkCanonicalPath) + } +} + +private fun determineUrl( + canonicalPath: String, + sourceLinkDefinition: SourceLinkDefinition, + sourceLinkCanonicalPath: String +): String { + val relativePath = canonicalPath.substring(sourceLinkCanonicalPath.length) + val relativeUrl = relativePath.replace('\\', '/').removePrefix("/") + return "${sourceLinkDefinition.url.removeSuffix("/")}/$relativeUrl" +} + private fun PsiElement.sourcePosition(): String { val path = containingFile.virtualFile.path val lineNumber = lineNumber() diff --git a/core/src/main/kotlin/javadoc/docbase.kt b/core/src/main/kotlin/javadoc/docbase.kt index 2a14c6ff..118b134a 100644 --- a/core/src/main/kotlin/javadoc/docbase.kt +++ b/core/src/main/kotlin/javadoc/docbase.kt @@ -2,7 +2,7 @@ package org.jetbrains.dokka.javadoc import com.sun.javadoc.* import org.jetbrains.dokka.* -import java.lang.reflect.Modifier +import java.lang.reflect.Modifier.* import java.util.* import kotlin.reflect.KClass @@ -75,9 +75,7 @@ open class DocumentationNodeAdapter(override val module: ModuleNodeAdapter, node node.deprecation?.let { val content = it.content.asText() - if (content != null) { - result.add(TagImpl(this, "deprecated", content)) - } + result.add(TagImpl(this, "deprecated", content ?: "")) } return result.toTypedArray() @@ -116,20 +114,27 @@ class AnnotationTypeDocAdapter(module: ModuleNodeAdapter, node: DocumentationNod } class AnnotationDescAdapter(val module: ModuleNodeAdapter, val node: DocumentationNode) : AnnotationDesc { - override fun annotationType(): AnnotationTypeDoc? = AnnotationTypeDocAdapter(module, node) // TODO ????? + override fun annotationType(): AnnotationTypeDoc? = AnnotationTypeDocAdapter(module, node.links.find { it.kind == NodeKind.AnnotationClass } ?: node) // TODO ????? override fun isSynthesized(): Boolean = false override fun elementValues(): Array<out AnnotationDesc.ElementValuePair>? = emptyArray() // TODO } open class ProgramElementAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), ProgramElementDoc { - override fun isPublic(): Boolean = true + override fun isPublic(): Boolean = node.hasModifier("public") || node.hasModifier("internal") override fun isPackagePrivate(): Boolean = false override fun isStatic(): Boolean = node.hasModifier("static") - override fun modifierSpecifier(): Int = Modifier.PUBLIC + if (isStatic) Modifier.STATIC else 0 + override fun modifierSpecifier(): Int = visibilityModifier or (if (isStatic) STATIC else 0) + private val visibilityModifier + get() = when { + isPublic() -> PUBLIC + isPrivate() -> PRIVATE + isProtected() -> PROTECTED + else -> 0 + } override fun qualifiedName(): String? = node.qualifiedName() override fun annotations(): Array<out AnnotationDesc>? = nodeAnnotations(this).toTypedArray() override fun modifiers(): String? = "public ${if (isStatic) "static" else ""}".trim() - override fun isProtected(): Boolean = false + override fun isProtected(): Boolean = node.hasModifier("protected") override fun isFinal(): Boolean = node.hasModifier("final") @@ -165,7 +170,7 @@ open class ProgramElementAdapter(module: ModuleNodeAdapter, node: DocumentationN return null } - override fun isPrivate(): Boolean = false + override fun isPrivate(): Boolean = node.hasModifier("private") override fun isIncluded(): Boolean = containingPackage()?.isIncluded ?: false && containingClass()?.let { it.isIncluded } ?: true } @@ -173,7 +178,7 @@ open class TypeAdapter(override val module: ModuleNodeAdapter, override val node private val javaLanguageService = JavaLanguageService() override fun qualifiedTypeName(): String = javaLanguageService.getArrayElementType(node)?.qualifiedNameFromType() ?: node.qualifiedNameFromType() - override fun typeName(): String = javaLanguageService.getArrayElementType(node)?.simpleName() ?: node.simpleName() + override fun typeName(): String = (javaLanguageService.getArrayElementType(node)?.simpleName() ?: node.simpleName()) + dimension() override fun simpleTypeName(): String = typeName() // TODO difference typeName() vs simpleTypeName() override fun dimension(): String = Collections.nCopies(javaLanguageService.getArrayDimension(node), "[]").joinToString("") @@ -275,7 +280,7 @@ class ParameterizedTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNod } class ParameterAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), Parameter { - override fun typeName(): String? = JavaLanguageService().renderType(node.detail(NodeKind.Type)) + override fun typeName(): String? = type()?.typeName() override fun type(): Type? = TypeAdapter(module, node.detail(NodeKind.Type)) override fun annotations(): Array<out AnnotationDesc> = nodeAnnotations(this).toTypedArray() } @@ -317,7 +322,7 @@ open class ExecutableMemberAdapter(module: ModuleNodeAdapter, node: Documentatio .map { ThrowsTagAdapter(this, ClassDocumentationNodeAdapter(module, classOf(it.subjectName!!, NodeKind.Exception)), it.children) } .toTypedArray() - override fun isVarArgs(): Boolean = node.details(NodeKind.Parameter).any { false } // TODO + override fun isVarArgs(): Boolean = node.details(NodeKind.Parameter).last().hasModifier("vararg") override fun isSynchronized(): Boolean = node.annotations.any { it.name == "synchronized" } @@ -406,6 +411,9 @@ open class ClassDocumentationNodeAdapter(module: ModuleNodeAdapter, val classNod return classNode.simpleName() } + override fun qualifiedName(): String? { + return super.qualifiedName() + } override fun constructors(filter: Boolean): Array<out ConstructorDoc> = classNode.members(NodeKind.Constructor).map { ConstructorAdapter(module, it) }.toTypedArray() override fun constructors(): Array<out ConstructorDoc> = constructors(true) override fun importedPackages(): Array<out PackageDoc> = emptyArray() @@ -514,12 +522,13 @@ class ModuleNodeAdapter(val module: DocumentationModule, val reporter: DocErrorR } private fun DocumentationNodeAdapter.collectParamTags(kind: NodeKind, sectionFilter: (ContentSection) -> Boolean) = - (node.details(kind) - .filter(DocumentationNode::hasNonEmptyContent) - .map { ParamTagAdapter(module, this, it.name, true, it.content.children) } + (node.details(kind) + .filter(DocumentationNode::hasNonEmptyContent) + .map { ParamTagAdapter(module, this, it.name, true, it.content.children) } - + node.content.sections - .filter(sectionFilter) - .map { ParamTagAdapter(module, this, it.subjectName ?: "?", true, it.children) }) - - .toTypedArray()
\ No newline at end of file + + node.content.sections + .filter(sectionFilter) + .map { ParamTagAdapter(module, this, it.subjectName ?: "?", true, it.children) } + ) + .distinctBy { it.parameterName } + .toTypedArray()
\ No newline at end of file diff --git a/core/src/main/kotlin/javadoc/tags.kt b/core/src/main/kotlin/javadoc/tags.kt index 05d98b71..99c9bfff 100644 --- a/core/src/main/kotlin/javadoc/tags.kt +++ b/core/src/main/kotlin/javadoc/tags.kt @@ -71,7 +71,7 @@ class SeeMethodTagAdapter(holder: Doc, val method: MethodAdapter, content: Conte override fun referencedPackage(): PackageDoc? = null override fun referencedClass(): ClassDoc? = method.containingClass() override fun referencedClassName(): String = method.containingClass()?.name() ?: "" - override fun label(): String = "${method.containingClass()?.name()}.${method.name()}" + override fun label(): String = content.text ?: "${method.containingClass()?.name()}.${method.name()}" override fun inlineTags(): Array<out Tag> = emptyArray() // TODO override fun firstSentenceTags(): Array<out Tag> = inlineTags() // TODO diff --git a/core/src/test/kotlin/NodeSelect.kt b/core/src/test/kotlin/NodeSelect.kt new file mode 100644 index 00000000..fe0394f9 --- /dev/null +++ b/core/src/test/kotlin/NodeSelect.kt @@ -0,0 +1,90 @@ +package org.jetbrains.dokka.tests + +import org.jetbrains.dokka.DocumentationNode +import org.jetbrains.dokka.NodeKind +import org.jetbrains.dokka.RefKind + +class SelectBuilder { + private val root = ChainFilterNode(SubgraphTraverseFilter(), null) + private var activeNode = root + private val chainEnds = mutableListOf<SelectFilter>() + + fun withName(name: String) = matching { it.name == name } + + fun withKind(kind: NodeKind) = matching{ it.kind == kind } + + fun matching(block: (DocumentationNode) -> Boolean) { + attachFilterAndMakeActive(PredicateFilter(block)) + } + + fun subgraph() { + attachFilterAndMakeActive(SubgraphTraverseFilter()) + } + + fun subgraphOf(kind: RefKind) { + attachFilterAndMakeActive(DirectEdgeFilter(kind)) + } + + private fun attachFilterAndMakeActive(next: SelectFilter) { + activeNode = ChainFilterNode(next, activeNode) + } + + private fun endChain() { + chainEnds += activeNode + } + + fun build(): SelectFilter { + endChain() + return CombineFilterNode(chainEnds) + } +} + +private class ChainFilterNode(val filter: SelectFilter, val previous: SelectFilter?): SelectFilter() { + override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> { + return filter.select(previous?.select(roots) ?: roots) + } +} + +private class CombineFilterNode(val previous: List<SelectFilter>): SelectFilter() { + override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> { + return previous.asSequence().flatMap { it.select(roots) } + } +} + +abstract class SelectFilter { + abstract fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> +} + +private class SubgraphTraverseFilter: SelectFilter() { + override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> { + val visited = mutableSetOf<DocumentationNode>() + return roots.flatMap { + generateSequence(listOf(it)) { nodes -> + nodes.flatMap { it.allReferences() } + .map { it.to } + .filter { visited.add(it) } + .takeUnless { it.isEmpty() } + } + }.flatten() + } + +} + +private class PredicateFilter(val condition: (DocumentationNode) -> Boolean): SelectFilter() { + override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> { + return roots.filter(condition) + } +} + +private class DirectEdgeFilter(val kind: RefKind): SelectFilter() { + override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> { + return roots.flatMap { it.references(kind).asSequence() }.map { it.to } + } +} + + +fun selectNodes(root: DocumentationNode, block: SelectBuilder.() -> Unit): List<DocumentationNode> { + val builder = SelectBuilder() + builder.apply(block) + return builder.build().select(sequenceOf(root)).toMutableSet().toList() +}
\ No newline at end of file diff --git a/core/src/test/kotlin/TestAPI.kt b/core/src/test/kotlin/TestAPI.kt index 8974bd0b..6ee610cd 100644 --- a/core/src/test/kotlin/TestAPI.kt +++ b/core/src/test/kotlin/TestAPI.kt @@ -6,14 +6,15 @@ import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.FileUtil import com.intellij.rt.execution.junit.FileComparisonFailure import org.jetbrains.dokka.* +import org.jetbrains.dokka.DokkaConfiguration.SourceLinkDefinition import org.jetbrains.dokka.Utilities.DokkaAnalysisModule import org.jetbrains.dokka.Utilities.DokkaRunModule +import org.jetbrains.kotlin.cli.common.config.ContentRoot +import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot -import org.jetbrains.kotlin.config.ContentRoot -import org.jetbrains.kotlin.config.KotlinSourceRoot import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.utils.PathUtil import org.junit.Assert @@ -29,7 +30,8 @@ data class ModelConfig( val analysisPlatform: Platform = Platform.DEFAULT, val defaultPlatforms: List<String> = emptyList(), val noStdlibLink: Boolean = true, - val collectInheritedExtensionsFromLibraries: Boolean = false + val collectInheritedExtensionsFromLibraries: Boolean = false, + val sourceLinks: List<SourceLinkDefinition> = emptyList() ) fun verifyModel(modelConfig: ModelConfig, @@ -40,7 +42,7 @@ fun verifyModel(modelConfig: ModelConfig, includeNonPublic = modelConfig.includeNonPublic, skipEmptyPackages = false, includeRootPackage = true, - sourceLinks = listOf(), + sourceLinks = modelConfig.sourceLinks, perPackageOptions = modelConfig.perPackageOptions, noStdlibLink = modelConfig.noStdlibLink, noJdkLink = false, @@ -141,8 +143,8 @@ fun appendDocumentation(documentation: DocumentationModule, fun checkSourceExistsAndVerifyModel(source: String, modelConfig: ModelConfig = ModelConfig(), verifier: (DocumentationModule) -> Unit) { - if (!File(source).exists()) { - throw IllegalArgumentException("Can't find test data file $source") + require (File(source).exists()) { + "Cannot find test data file $source" } verifyModel( ModelConfig( @@ -151,6 +153,7 @@ fun checkSourceExistsAndVerifyModel(source: String, withKotlinRuntime = modelConfig.withKotlinRuntime, format = modelConfig.format, includeNonPublic = modelConfig.includeNonPublic, + sourceLinks = modelConfig.sourceLinks, analysisPlatform = modelConfig.analysisPlatform ), diff --git a/core/src/test/kotlin/format/HtmlFormatTest.kt b/core/src/test/kotlin/format/HtmlFormatTest.kt index 20891963..60e29006 100644 --- a/core/src/test/kotlin/format/HtmlFormatTest.kt +++ b/core/src/test/kotlin/format/HtmlFormatTest.kt @@ -1,9 +1,8 @@ package org.jetbrains.dokka.tests import org.jetbrains.dokka.* +import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot -import org.jetbrains.kotlin.config.KotlinSourceRoot -import org.junit.Before import org.junit.Test import java.io.File @@ -162,7 +161,7 @@ class JVMHtmlFormatTest: BaseHtmlFormatTest(Platform.jvm) { verifyOutput( ModelConfig( roots = arrayOf( - KotlinSourceRoot("testdata/format/crossLanguage/kotlinExtendsJava/Bar.kt"), + KotlinSourceRoot("testdata/format/crossLanguage/kotlinExtendsJava/Bar.kt", false), JavaSourceRoot(File("testdata/format/crossLanguage/kotlinExtendsJava"), null) ), analysisPlatform = analysisPlatform diff --git a/core/src/test/kotlin/format/MarkdownFormatTest.kt b/core/src/test/kotlin/format/MarkdownFormatTest.kt index 29d2d20f..4796c17c 100644 --- a/core/src/test/kotlin/format/MarkdownFormatTest.kt +++ b/core/src/test/kotlin/format/MarkdownFormatTest.kt @@ -107,6 +107,14 @@ abstract class BaseMarkdownFormatTest(val analysisPlatform: Platform): FileGener verifyMarkdownNode("reifiedTypeParameter", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true)) } + @Test fun suspendInlineFunctionOrder() { + verifyMarkdownNode("suspendInlineFunction", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true)) + } + + @Test fun inlineSuspendFunctionOrderChanged() { + verifyMarkdownNode("inlineSuspendFunction", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true)) + } + @Test fun annotatedTypeParameter() { verifyMarkdownNode("annotatedTypeParameter", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true)) } @@ -478,6 +486,10 @@ abstract class BaseMarkdownFormatTest(val analysisPlatform: Platform): FileGener nodesWithName } } + + @Test fun nullableTypeParameterFunction() { + verifyMarkdownNode("nullableTypeParameterFunction", ModelConfig(analysisPlatform = analysisPlatform, withKotlinRuntime = true)) + } } class JSMarkdownFormatTest: BaseMarkdownFormatTest(Platform.js) @@ -544,7 +556,12 @@ class JVMMarkdownFormatTest: BaseMarkdownFormatTest(Platform.jvm) { @Test fun javaCodeInParam() { - verifyJavaMarkdownNode("javaCodeInParam", defaultModelConfig) + verifyJavaMarkdownNodes("javaCodeInParam", defaultModelConfig) { + selectNodes(it) { + subgraphOf(RefKind.Member) + withKind(NodeKind.Function) + } + } } @Test diff --git a/core/src/test/kotlin/format/PackageDocsTest.kt b/core/src/test/kotlin/format/PackageDocsTest.kt index b7fff1e2..3ff5f123 100644 --- a/core/src/test/kotlin/format/PackageDocsTest.kt +++ b/core/src/test/kotlin/format/PackageDocsTest.kt @@ -49,7 +49,7 @@ class PackageDocsTest { @Test fun testReferenceLinksInPackageDocs() { val mockLinkResolver = mock<DeclarationLinkResolver> { - val exampleCom = "http://example.com" + val exampleCom = "https://example.com" on { tryResolveContentLink(any(), eq(exampleCom)) } doAnswer { ContentExternalLink(exampleCom) } } diff --git a/core/src/test/kotlin/javadoc/JavadocTest.kt b/core/src/test/kotlin/javadoc/JavadocTest.kt index 7976fccc..d4f82571 100644 --- a/core/src/test/kotlin/javadoc/JavadocTest.kt +++ b/core/src/test/kotlin/javadoc/JavadocTest.kt @@ -9,6 +9,7 @@ import org.jetbrains.dokka.tests.assertEqualsIgnoringSeparators import org.jetbrains.dokka.tests.checkSourceExistsAndVerifyModel import org.junit.Assert.* import org.junit.Test +import java.lang.reflect.Modifier.* class JavadocTest { val defaultModelConfig = ModelConfig(analysisPlatform = Platform.jvm) @@ -77,7 +78,7 @@ class JavadocTest { val member = classDoc.methods().find { it.name() == "main" }!! val paramType = member.parameters()[0].type() assertNull(paramType.asParameterizedType()) - assertEquals("String", paramType.typeName()) + assertEquals("String[]", paramType.typeName()) assertEquals("String", paramType.asClassDoc().name()) } } @@ -195,6 +196,115 @@ class JavadocTest { } } + @Test + fun testVararg() { + verifyJavadoc("testdata/javadoc/vararg.kt") { doc -> + val classDoc = doc.classNamed("VarargKt")!! + val methods = classDoc.methods() + methods.single { it.name() == "vararg" }.let { method -> + assertTrue(method.isVarArgs) + assertEquals("int", method.parameters().last().typeName()) + } + methods.single { it.name() == "varargInMiddle" }.let { method -> + assertFalse(method.isVarArgs) + assertEquals("int[]", method.parameters()[1].typeName()) + } + } + } + + @Test + fun shouldHaveValidVisibilityModifiers() { + verifyJavadoc("testdata/javadoc/visibilityModifiers.kt", ModelConfig(analysisPlatform = Platform.jvm, withKotlinRuntime = true)) { doc -> + val classDoc = doc.classNamed("foo.Apple")!! + val methods = classDoc.methods() + + val getName = methods[0] + val setName = methods[1] + val getWeight = methods[2] + val setWeight = methods[3] + val getRating = methods[4] + val setRating = methods[5] + val getCode = methods[6] + val color = classDoc.fields()[3] + val code = classDoc.fields()[4] + + assertTrue(getName.isProtected) + assertEquals(PROTECTED, getName.modifierSpecifier()) + assertTrue(setName.isProtected) + assertEquals(PROTECTED, setName.modifierSpecifier()) + + assertTrue(getWeight.isPublic) + assertEquals(PUBLIC, getWeight.modifierSpecifier()) + assertTrue(setWeight.isPublic) + assertEquals(PUBLIC, setWeight.modifierSpecifier()) + + assertTrue(getRating.isPublic) + assertEquals(PUBLIC, getRating.modifierSpecifier()) + assertTrue(setRating.isPublic) + assertEquals(PUBLIC, setRating.modifierSpecifier()) + + assertTrue(getCode.isPublic) + assertEquals(PUBLIC or STATIC, getCode.modifierSpecifier()) + + assertEquals(methods.size, 7) + + assertTrue(color.isPrivate) + assertEquals(PRIVATE, color.modifierSpecifier()) + + assertTrue(code.isPrivate) + assertTrue(code.isStatic) + assertEquals(PRIVATE or STATIC, code.modifierSpecifier()) + } + } + + @Test + fun shouldNotHaveDuplicatedConstructorParameters() { + verifyJavadoc("testdata/javadoc/constructorParameters.kt") { doc -> + val classDoc = doc.classNamed("bar.Banana")!! + val paramTags = classDoc.constructors()[0].paramTags() + + assertEquals(3, paramTags.size) + } + } + + @Test fun shouldHaveAllFunctionMarkedAsDeprecated() { + verifyJavadoc("testdata/javadoc/deprecated.java") { doc -> + val classDoc = doc.classNamed("bar.Banana")!! + + classDoc.methods().forEach { method -> + assertTrue(method.tags().any { it.kind() == "deprecated" }) + } + } + } + + @Test + fun testDefaultNoArgConstructor() { + verifyJavadoc("testdata/javadoc/defaultNoArgConstructor.kt") { doc -> + val classDoc = doc.classNamed("foo.Peach")!! + assertTrue(classDoc.constructors()[0].tags()[2].text() == "print peach") + } + } + + @Test + fun testNoArgConstructor() { + verifyJavadoc("testdata/javadoc/noArgConstructor.kt") { doc -> + val classDoc = doc.classNamed("foo.Plum")!! + assertTrue(classDoc.constructors()[0].tags()[2].text() == "print plum") + } + } + + @Test + fun testArgumentReference() { + verifyJavadoc("testdata/javadoc/argumentReference.kt") { doc -> + val classDoc = doc.classNamed("ArgumentReferenceKt")!! + val method = classDoc.methods().first() + val tag = method.seeTags().first() + assertEquals("argNamedError", tag.referencedMemberName()) + assertEquals("error", tag.label()) + } + } + + private fun verifyJavadoc(name: String, modelConfig: ModelConfig = ModelConfig(), callback: (ModuleNodeAdapter) -> Unit) { diff --git a/core/src/test/kotlin/model/FunctionTest.kt b/core/src/test/kotlin/model/FunctionTest.kt index 47685df2..2a60751d 100644 --- a/core/src/test/kotlin/model/FunctionTest.kt +++ b/core/src/test/kotlin/model/FunctionTest.kt @@ -159,6 +159,33 @@ Documentation""", content.description.toTestString()) } } + @Test fun suspendFunction() { + verifyPackageMember("testdata/functions/suspendFunction.kt") { func -> + val modifiers = func.details(NodeKind.Modifier).map { it.name } + assertTrue("suspend" in modifiers) + } + } + + @Test fun suspendInlineFunctionOrder() { + verifyPackageMember("testdata/functions/suspendInlineFunction.kt") { func -> + val modifiers = func.details(NodeKind.Modifier).map { it.name }.filter { + it == "suspend" || it == "inline" + } + + assertEquals(listOf("suspend", "inline"), modifiers) + } + } + + @Test fun inlineSuspendFunctionOrderChanged() { + verifyPackageMember("testdata/functions/inlineSuspendFunction.kt") { func -> + val modifiers = func.details(NodeKind.Modifier).map { it.name }.filter { + it == "suspend" || it == "inline" + } + + assertEquals(listOf("suspend", "inline"), modifiers) + } + } + @Test fun functionWithAnnotatedParam() { checkSourceExistsAndVerifyModel("testdata/functions/functionWithAnnotatedParam.kt", defaultModelConfig) { model -> with(model.members.single().members.single { it.name == "function" }) { diff --git a/core/src/test/kotlin/model/JavaTest.kt b/core/src/test/kotlin/model/JavaTest.kt index 13bb72ba..da9da624 100644 --- a/core/src/test/kotlin/model/JavaTest.kt +++ b/core/src/test/kotlin/model/JavaTest.kt @@ -25,7 +25,7 @@ public class JavaTest { with(content.sections[1]) { assertEquals("Parameters", tag) assertEquals("value", subjectName) - assertEquals("render(Type:String,SUMMARY): is int parameter", toTestString()) + assertEquals("render(Type:Int,SUMMARY): is int parameter", toTestString()) } with(content.sections[2]) { assertEquals("Author", tag) @@ -152,7 +152,7 @@ public class JavaTest { /** * `@suppress` not supported in Java! * - * [Proposed tags](http://www.oracle.com/technetwork/java/javase/documentation/proposed-tags-142378.html) + * [Proposed tags](https://www.oracle.com/technetwork/java/javase/documentation/proposed-tags-142378.html) * Proposed tag `@exclude` for it, but not supported yet */ @Ignore("@suppress not supported in Java!") @Test fun suppressTag() { diff --git a/core/src/test/kotlin/model/KotlinAsJavaTest.kt b/core/src/test/kotlin/model/KotlinAsJavaTest.kt index f6f0aa20..b5c15618 100644 --- a/core/src/test/kotlin/model/KotlinAsJavaTest.kt +++ b/core/src/test/kotlin/model/KotlinAsJavaTest.kt @@ -3,6 +3,8 @@ package org.jetbrains.dokka.tests import org.jetbrains.dokka.DocumentationModule import org.jetbrains.dokka.NodeKind import org.jetbrains.dokka.Platform +import org.jetbrains.dokka.RefKind +import org.junit.Assert import org.junit.Test import org.junit.Assert.assertEquals @@ -28,6 +30,24 @@ class KotlinAsJavaTest { assertEquals("doc", getter.content.summary.toTestString()) } } + + + @Test fun constants() { + verifyModelAsJava("testdata/java/constants.java") { cls -> + selectNodes(cls) { + subgraphOf(RefKind.Member) + matching { it.name == "constStr" || it.name == "refConst" } + }.forEach { + assertEquals("In $it", "\"some value\"", it.detailOrNull(NodeKind.Value)?.name) + } + val nullConstNode = selectNodes(cls) { + subgraphOf(RefKind.Member) + withName("nullConst") + }.single() + + Assert.assertNull(nullConstNode.detailOrNull(NodeKind.Value)) + } + } } fun verifyModelAsJava(source: String, diff --git a/core/src/test/kotlin/model/PackageTest.kt b/core/src/test/kotlin/model/PackageTest.kt index 80a2fd56..e20e6afa 100644 --- a/core/src/test/kotlin/model/PackageTest.kt +++ b/core/src/test/kotlin/model/PackageTest.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.tests import org.jetbrains.dokka.* -import org.jetbrains.kotlin.config.KotlinSourceRoot +import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot import org.junit.Assert.* import org.junit.Test @@ -50,8 +50,8 @@ abstract class BasePackageTest(val analysisPlatform: Platform) { verifyModel( ModelConfig( roots = arrayOf( - KotlinSourceRoot("testdata/packages/dottedNamePackage.kt"), - KotlinSourceRoot("testdata/packages/simpleNamePackage.kt") + KotlinSourceRoot("testdata/packages/dottedNamePackage.kt", false), + KotlinSourceRoot("testdata/packages/simpleNamePackage.kt", false) ), analysisPlatform = analysisPlatform ) @@ -79,8 +79,8 @@ abstract class BasePackageTest(val analysisPlatform: Platform) { verifyModel( ModelConfig( roots = arrayOf( - KotlinSourceRoot("testdata/packages/simpleNamePackage.kt"), - KotlinSourceRoot("testdata/packages/simpleNamePackage2.kt") + KotlinSourceRoot("testdata/packages/simpleNamePackage.kt", false), + KotlinSourceRoot("testdata/packages/simpleNamePackage2.kt", false) ), analysisPlatform = analysisPlatform ) @@ -100,7 +100,7 @@ abstract class BasePackageTest(val analysisPlatform: Platform) { @Test fun classAtPackageLevel() { verifyModel( ModelConfig( - roots = arrayOf(KotlinSourceRoot("testdata/packages/classInPackage.kt")), + roots = arrayOf(KotlinSourceRoot("testdata/packages/classInPackage.kt", false)), analysisPlatform = analysisPlatform ) ) { model -> @@ -119,7 +119,7 @@ abstract class BasePackageTest(val analysisPlatform: Platform) { @Test fun suppressAtPackageLevel() { verifyModel( ModelConfig( - roots = arrayOf(KotlinSourceRoot("testdata/packages/classInPackage.kt")), + roots = arrayOf(KotlinSourceRoot("testdata/packages/classInPackage.kt", false)), perPackageOptions = listOf( PackageOptionsImpl(prefix = "simple.name", suppress = true) ), diff --git a/core/src/test/kotlin/model/PropertyTest.kt b/core/src/test/kotlin/model/PropertyTest.kt index a41ab5a3..b3481265 100644 --- a/core/src/test/kotlin/model/PropertyTest.kt +++ b/core/src/test/kotlin/model/PropertyTest.kt @@ -116,7 +116,7 @@ class JVMPropertyTest : BasePropertyTest(Platform.jvm) { with(model.members.single().members.single()) { Assert.assertEquals(1, annotations.count()) with(annotations[0]) { - Assert.assertEquals("Volatile", name) + Assert.assertEquals("Strictfp", name) Assert.assertEquals(Content.Empty, content) Assert.assertEquals(NodeKind.Annotation, kind) } diff --git a/core/src/test/kotlin/model/SourceLinksErrorTest.kt b/core/src/test/kotlin/model/SourceLinksErrorTest.kt new file mode 100644 index 00000000..9812569d --- /dev/null +++ b/core/src/test/kotlin/model/SourceLinksErrorTest.kt @@ -0,0 +1,35 @@ +package org.jetbrains.dokka.tests.model + +import org.jetbrains.dokka.NodeKind +import org.jetbrains.dokka.SourceLinkDefinitionImpl +import org.jetbrains.dokka.tests.ModelConfig +import org.jetbrains.dokka.tests.checkSourceExistsAndVerifyModel +import org.junit.Assert +import org.junit.Test +import java.io.File + +class SourceLinksErrorTest { + + @Test + fun absolutePath_notMatching() { + val sourceLink = SourceLinkDefinitionImpl(File("testdata/nonExisting").absolutePath, "http://...", null) + verifyNoSourceUrl(sourceLink) + } + + @Test + fun relativePath_notMatching() { + val sourceLink = SourceLinkDefinitionImpl("testdata/nonExisting", "http://...", null) + verifyNoSourceUrl(sourceLink) + } + + private fun verifyNoSourceUrl(sourceLink: SourceLinkDefinitionImpl) { + checkSourceExistsAndVerifyModel("testdata/sourceLinks/dummy.kt", ModelConfig(sourceLinks = listOf(sourceLink))) { model -> + with(model.members.single().members.single()) { + Assert.assertEquals("foo", name) + Assert.assertEquals(NodeKind.Function, kind) + Assert.assertTrue("should not have source urls", details(NodeKind.SourceUrl).isEmpty()) + } + } + } +} + diff --git a/core/src/test/kotlin/model/SourceLinksTest.kt b/core/src/test/kotlin/model/SourceLinksTest.kt new file mode 100644 index 00000000..a4ba870c --- /dev/null +++ b/core/src/test/kotlin/model/SourceLinksTest.kt @@ -0,0 +1,75 @@ +package org.jetbrains.dokka.tests.model + +import org.jetbrains.dokka.NodeKind +import org.jetbrains.dokka.SourceLinkDefinitionImpl +import org.jetbrains.dokka.tests.ModelConfig +import org.jetbrains.dokka.tests.checkSourceExistsAndVerifyModel +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import java.io.File + +@RunWith(Parameterized::class) +class SourceLinksTest( + private val srcLink: String, + private val url: String, + private val lineSuffix: String?, + private val expectedUrl: String +) { + + @Test + fun test() { + val link = if(srcLink.contains(sourceLinks)){ + srcLink.substringBeforeLast(sourceLinks) + sourceLinks + } else { + srcLink.substringBeforeLast(testdata) + testdata + } + val sourceLink = SourceLinkDefinitionImpl(link, url, lineSuffix) + + checkSourceExistsAndVerifyModel(filePath, ModelConfig(sourceLinks = listOf(sourceLink))) { model -> + with(model.members.single().members.single()) { + Assert.assertEquals("foo", name) + Assert.assertEquals(NodeKind.Function, kind) + Assert.assertEquals(expectedUrl, details(NodeKind.SourceUrl).single().name) + } + } + } + + companion object { + private const val testdata = "testdata" + private const val sourceLinks = "sourceLinks" + private const val dummy = "dummy.kt" + private const val pathSuffix = "$sourceLinks/$dummy" + private const val filePath = "$testdata/$pathSuffix" + private const val url = "https://example.com" + + @Parameterized.Parameters(name = "{index}: {0}, {1}, {2} = {3}") + @JvmStatic + fun data(): Collection<Array<String?>> { + val longestPath = File(testdata).absolutePath.removeSuffix("/") + "/../$testdata/" + val maxLength = longestPath.length + val list = listOf( + arrayOf(File(testdata).absolutePath.removeSuffix("/"), "$url/$pathSuffix"), + arrayOf(File("$testdata/$sourceLinks").absolutePath.removeSuffix("/") + "/", "$url/$dummy"), + arrayOf(longestPath, "$url/$pathSuffix"), + + arrayOf(testdata, "$url/$pathSuffix"), + arrayOf("./$testdata", "$url/$pathSuffix"), + arrayOf("../core/$testdata", "$url/$pathSuffix"), + arrayOf("$testdata/$sourceLinks", "$url/$dummy"), + arrayOf("./$testdata/../$testdata/$sourceLinks", "$url/$dummy") + ) + + return list.map { arrayOf(it[0].padEnd(maxLength, '_'), url, null, it[1]) } + + listOf( + // check that it also works if url ends with / + arrayOf((File(testdata).absolutePath.removeSuffix("/") + "/").padEnd(maxLength, '_'), "$url/", null, "$url/$pathSuffix"), + // check if line suffix work + arrayOf<String?>("../core/../core/./$testdata/$sourceLinks/".padEnd(maxLength, '_'), "$url/", "#L", "$url/$dummy#L4") + ) + } + } + +} + diff --git a/core/testdata/format/JavaSupertype.html b/core/testdata/format/JavaSupertype.html index 27b8e5d0..892ef63a 100644 --- a/core/testdata/format/JavaSupertype.html +++ b/core/testdata/format/JavaSupertype.html @@ -7,7 +7,7 @@ <a href="../../index.html">test</a> / <a href="../index.html">JavaSupertype</a> / <a href="./index.html">Bar</a><br/> <br/> <h1>Bar</h1> -<code><span class="keyword">open</span> <span class="keyword">class </span><span class="identifier">Bar</span> <span class="symbol">:</span> <a href="../-foo/index.html"><span class="identifier">Foo</span></a></code> +<code><span class="keyword">open</span> <span class="keyword">class </span><span class="identifier">Bar</span> <span class="symbol">:</span> <a href="../-foo/index.html"><span class="identifier">JavaSupertype.Foo</span></a></code> <h3>Constructors</h3> <table> <tbody> @@ -28,7 +28,7 @@ <p><a href="return-foo.html">returnFoo</a></p> </td> <td> -<code><span class="keyword">open</span> <span class="keyword">fun </span><span class="identifier">returnFoo</span><span class="symbol">(</span><span class="identifier" id="JavaSupertype.Bar$returnFoo(JavaSupertype.Foo)/foo">foo</span><span class="symbol">:</span> <a href="../-foo/index.html"><span class="identifier">Foo</span></a><span class="symbol">)</span><span class="symbol">: </span><a href="../-foo/index.html"><span class="identifier">Foo</span></a></code></td> +<code><span class="keyword">open</span> <span class="keyword">fun </span><span class="identifier">returnFoo</span><span class="symbol">(</span><span class="identifier" id="JavaSupertype.Bar$returnFoo(JavaSupertype.Foo)/foo">foo</span><span class="symbol">:</span> <a href="../-foo/index.html"><span class="identifier">JavaSupertype.Foo</span></a><span class="symbol">!</span><span class="symbol">)</span><span class="symbol">: </span><a href="../-foo/index.html"><span class="identifier">JavaSupertype.Foo</span></a><span class="symbol">!</span></code></td> </tr> </tbody> </table> diff --git a/core/testdata/format/enumRef.md b/core/testdata/format/enumRef.md index 8b2a6650..f5f5a3e0 100644 --- a/core/testdata/format/enumRef.md +++ b/core/testdata/format/enumRef.md @@ -4,5 +4,5 @@ `fun f(): Unit` -[java.math.RoundingMode.UP](http://docs.oracle.com/javase/6/docs/api/java/math/RoundingMode.html#UP) +[java.math.RoundingMode.UP](https://docs.oracle.com/javase/6/docs/api/java/math/RoundingMode.html#UP) diff --git a/core/testdata/format/externalReferenceLink.kt b/core/testdata/format/externalReferenceLink.kt index 4ca0ee21..775b2e66 100644 --- a/core/testdata/format/externalReferenceLink.kt +++ b/core/testdata/format/externalReferenceLink.kt @@ -3,7 +3,7 @@ * * Sure, it is [example.com] * - * [example.com]: http://example.com + * [example.com]: https://example.com */ fun a() { diff --git a/core/testdata/format/externalReferenceLink.md b/core/testdata/format/externalReferenceLink.md index 38ffde78..3565d9aa 100644 --- a/core/testdata/format/externalReferenceLink.md +++ b/core/testdata/format/externalReferenceLink.md @@ -4,7 +4,7 @@ `fun a(): Unit` -It is link to [example site](http://example.com) +It is link to [example site](https://example.com) -Sure, it is [example.com](http://example.com) +Sure, it is [example.com](https://example.com) diff --git a/core/testdata/format/inheritedLink.md b/core/testdata/format/inheritedLink.md index e5af326c..aec07a75 100644 --- a/core/testdata/format/inheritedLink.md +++ b/core/testdata/format/inheritedLink.md @@ -13,5 +13,5 @@ Overrides [Foo.sayHello](../../p1/-foo/say-hello.md) -Says hello - [LinkedList](http://docs.oracle.com/javase/6/docs/api/java/util/LinkedList.html). +Says hello - [LinkedList](https://docs.oracle.com/javase/6/docs/api/java/util/LinkedList.html). diff --git a/core/testdata/format/inlineSuspendFunction.kt b/core/testdata/format/inlineSuspendFunction.kt new file mode 100644 index 00000000..f2009eff --- /dev/null +++ b/core/testdata/format/inlineSuspendFunction.kt @@ -0,0 +1,6 @@ +/** + * returns 1 + */ +inline suspend fun foo(): Int { + 1 +} diff --git a/core/testdata/format/inlineSuspendFunction.md b/core/testdata/format/inlineSuspendFunction.md new file mode 100644 index 00000000..946463f7 --- /dev/null +++ b/core/testdata/format/inlineSuspendFunction.md @@ -0,0 +1,8 @@ +[test](index.md) / [foo](./foo.md) + +# foo + +`suspend inline fun foo(): Int` + +returns 1 + diff --git a/core/testdata/format/javaCodeInParam.java b/core/testdata/format/javaCodeInParam.java index 73025fcc..0d1607ba 100644 --- a/core/testdata/format/javaCodeInParam.java +++ b/core/testdata/format/javaCodeInParam.java @@ -1,5 +1,7 @@ -/** - * @param T this is {@code some code} and other text - */ -class C<T> { +class C { + + /** + * @param par this is {@code some code} and other text + */ + public void withParam(String par) {} } diff --git a/core/testdata/format/javaCodeInParam.md b/core/testdata/format/javaCodeInParam.md index 319c6d87..566b176d 100644 --- a/core/testdata/format/javaCodeInParam.md +++ b/core/testdata/format/javaCodeInParam.md @@ -1,14 +1,9 @@ -[test](../index.md) / [C](./index.md) +[test](../index.md) / [C](index.md) / [withParam](./with-param.md) -# C +# withParam -`protected open class C<T : Any>` +`open fun withParam(par: String!): Unit` ### Parameters -`T` - this is `some code` and other text - -### Constructors - -| [<init>](-init-.md) | `C()` | - +`par` - String!: this is `some code` and other text
\ No newline at end of file diff --git a/core/testdata/format/javaCodeLiteralTags.md b/core/testdata/format/javaCodeLiteralTags.md index b36be04d..c2c58047 100644 --- a/core/testdata/format/javaCodeLiteralTags.md +++ b/core/testdata/format/javaCodeLiteralTags.md @@ -12,5 +12,5 @@ A<B>C ### Constructors -| [<init>](-init-.md) | `C()`<br>`A<B>C` <br>A<B>C | +| [<init>](-init-.md) | `C()`<br>`A<B>C` | diff --git a/core/testdata/format/javadocHtml.java b/core/testdata/format/javadocHtml.java index 622116b2..9e77402e 100644 --- a/core/testdata/format/javadocHtml.java +++ b/core/testdata/format/javadocHtml.java @@ -9,6 +9,18 @@ * <code>Code</code> * <pre>Block code</pre> * <ul><li>List Item</li></ul> + * <pre> + * with( some ) { + * multi = lines + * sample() + * } + * </pre> + * <pre> + * {@code + * with (some) { <code> } + * } + * </pre> + * */ public class C { } diff --git a/core/testdata/format/javadocHtml.md b/core/testdata/format/javadocHtml.md index a3c1baff..77f6c829 100644 --- a/core/testdata/format/javadocHtml.md +++ b/core/testdata/format/javadocHtml.md @@ -16,13 +16,23 @@ Block code * List Item -### Constructors -| [<init>](-init-.md) | `C()`<br>**Bold** **Strong** *Italic* *Emphasized* <br>Paragraph ~~Strikethrough~~ ~~Deleted~~ `Code` +``` + + with( some ) { + multi = lines + sample() + } + ``` + + ``` -Block code<br>``` -<br> -* List Item -<br> | +with (some) { <code> } + + ``` + +### Constructors + +| [<init>](-init-.md) | `C()`<br>**Bold** **Strong** *Italic* *Emphasized* | diff --git a/core/testdata/format/jdkLinks.md b/core/testdata/format/jdkLinks.md index 7498171d..c3a5fbf4 100644 --- a/core/testdata/format/jdkLinks.md +++ b/core/testdata/format/jdkLinks.md @@ -2,13 +2,13 @@ # C -`class C : `[`ClassLoader`](http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html) +`class C : `[`ClassLoader`](https://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html) -This is a [ClassLoader](http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html) and I can get its [ClassLoader.getResource](http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html#getResource(java.lang.String)) +This is a [ClassLoader](https://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html) and I can get its [ClassLoader.getResource](https://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html#getResource(java.lang.String)) -You can print something to [java.lang.System.out](http://docs.oracle.com/javase/6/docs/api/java/lang/System.html#out) now! +You can print something to [java.lang.System.out](https://docs.oracle.com/javase/6/docs/api/java/lang/System.html#out) now! ### Constructors -| [<init>](-init-.md) | `C()`<br>This is a [ClassLoader](http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html) and I can get its [ClassLoader.getResource](http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html#getResource(java.lang.String)) | +| [<init>](-init-.md) | `C()`<br>This is a [ClassLoader](https://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html) and I can get its [ClassLoader.getResource](https://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html#getResource(java.lang.String)) | diff --git a/core/testdata/format/markdownInLinks.html b/core/testdata/format/markdownInLinks.html index 596cca73..f0bb475e 100644 --- a/core/testdata/format/markdownInLinks.html +++ b/core/testdata/format/markdownInLinks.html @@ -9,6 +9,6 @@ <h1>foo</h1> <a name="$foo()"></a> <code><span class="keyword">fun </span><span class="identifier">foo</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code> -<p><a href="http://www.ibm.com">a<strong>b</strong><strong>d</strong> kas </a></p> +<p><a href="https://www.ibm.com">a<strong>b</strong><strong>d</strong> kas </a></p> </BODY> </HTML> diff --git a/core/testdata/format/markdownInLinks.kt b/core/testdata/format/markdownInLinks.kt index 67b6311f..380727ee 100644 --- a/core/testdata/format/markdownInLinks.kt +++ b/core/testdata/format/markdownInLinks.kt @@ -1,4 +1,4 @@ /** - * [a**b**__d__ kas ](http://www.ibm.com) + * [a**b**__d__ kas ](https://www.ibm.com) */ fun foo() {} diff --git a/core/testdata/format/nullableTypeParameterFunction.kt b/core/testdata/format/nullableTypeParameterFunction.kt new file mode 100644 index 00000000..01805a7b --- /dev/null +++ b/core/testdata/format/nullableTypeParameterFunction.kt @@ -0,0 +1,8 @@ +class Bar<T> { + val dataList = mutableListOf<T>() + + open fun checkElement( + elem: T, + addFunc: ((elem: T) -> Unit)? = { dataList.add(it) } + ): Int = 1 +}
\ No newline at end of file diff --git a/core/testdata/format/nullableTypeParameterFunction.md b/core/testdata/format/nullableTypeParameterFunction.md new file mode 100644 index 00000000..5764007b --- /dev/null +++ b/core/testdata/format/nullableTypeParameterFunction.md @@ -0,0 +1,18 @@ +[test](../index.md) / [Bar](./index.md) + +# Bar + +`class Bar<T>` + +### Constructors + +| [<init>](-init-.md) | `Bar()` | + +### Properties + +| [dataList](data-list.md) | `val dataList: MutableList<`[`T`](index.md#T)`>` | + +### Functions + +| [checkElement](check-element.md) | `fun checkElement(elem: `[`T`](index.md#T)`, addFunc: ((elem: `[`T`](index.md#T)`) -> Unit)? = { dataList.add(it) }): Int` | + diff --git a/core/testdata/format/renderFunctionalTypeInParenthesisWhenItIsReceiver.md b/core/testdata/format/renderFunctionalTypeInParenthesisWhenItIsReceiver.md index ad632fef..4b5f3a64 100644 --- a/core/testdata/format/renderFunctionalTypeInParenthesisWhenItIsReceiver.md +++ b/core/testdata/format/renderFunctionalTypeInParenthesisWhenItIsReceiver.md @@ -1,6 +1,6 @@ -[test](../index.md) / [kotlin.SuspendFunction0](./index.md) +[test](../index.md) / [kotlin.coroutines.SuspendFunction0](./index.md) -### Extensions for kotlin.SuspendFunction0 +### Extensions for kotlin.coroutines.SuspendFunction0 | [foo](foo.md) | `fun (suspend () -> Unit).foo(): Unit` | diff --git a/core/testdata/format/suspendInlineFunction.kt b/core/testdata/format/suspendInlineFunction.kt new file mode 100644 index 00000000..8af0d11a --- /dev/null +++ b/core/testdata/format/suspendInlineFunction.kt @@ -0,0 +1,6 @@ +/** + * returns 1 + */ +suspend inline fun foo(): Int { + 1 +} diff --git a/core/testdata/format/suspendInlineFunction.md b/core/testdata/format/suspendInlineFunction.md new file mode 100644 index 00000000..946463f7 --- /dev/null +++ b/core/testdata/format/suspendInlineFunction.md @@ -0,0 +1,8 @@ +[test](index.md) / [foo](./foo.md) + +# foo + +`suspend inline fun foo(): Int` + +returns 1 + diff --git a/core/testdata/functions/inlineSuspendFunction.kt b/core/testdata/functions/inlineSuspendFunction.kt new file mode 100644 index 00000000..54032ccf --- /dev/null +++ b/core/testdata/functions/inlineSuspendFunction.kt @@ -0,0 +1,2 @@ +inline suspend fun f() { +} diff --git a/core/testdata/functions/suspendFunction.kt b/core/testdata/functions/suspendFunction.kt new file mode 100644 index 00000000..49ecca2a --- /dev/null +++ b/core/testdata/functions/suspendFunction.kt @@ -0,0 +1,2 @@ +suspend fun f() { +} diff --git a/core/testdata/functions/suspendInlineFunction.kt b/core/testdata/functions/suspendInlineFunction.kt new file mode 100644 index 00000000..15a9018f --- /dev/null +++ b/core/testdata/functions/suspendInlineFunction.kt @@ -0,0 +1,2 @@ +suspend inline fun f() { +} diff --git a/core/testdata/java/constants.java b/core/testdata/java/constants.java new file mode 100644 index 00000000..26f16639 --- /dev/null +++ b/core/testdata/java/constants.java @@ -0,0 +1,5 @@ +public class Constants { + public static final String constStr = "some value"; + public static final Object nullConst = null; + public static final String refConst = constStr; +}
\ No newline at end of file diff --git a/core/testdata/javadoc/argumentReference.kt b/core/testdata/javadoc/argumentReference.kt new file mode 100644 index 00000000..ac3104e9 --- /dev/null +++ b/core/testdata/javadoc/argumentReference.kt @@ -0,0 +1,4 @@ +/** + * [error] + */ +fun argNamedError(error: String) {}
\ No newline at end of file diff --git a/core/testdata/javadoc/constructorParameters.kt b/core/testdata/javadoc/constructorParameters.kt new file mode 100644 index 00000000..c29ae912 --- /dev/null +++ b/core/testdata/javadoc/constructorParameters.kt @@ -0,0 +1,14 @@ +package bar + +/** + * Just a fruit + * + * @param weight in grams + * @param ranking quality from 0 to 10, where 10 is best + * @param color yellow is default + */ +class Banana ( + private val weight: Double, + private val ranking: Int, + color: String = "yellow" +)
\ No newline at end of file diff --git a/core/testdata/javadoc/defaultNoArgConstructor.kt b/core/testdata/javadoc/defaultNoArgConstructor.kt new file mode 100644 index 00000000..3a6d04a5 --- /dev/null +++ b/core/testdata/javadoc/defaultNoArgConstructor.kt @@ -0,0 +1,12 @@ +package foo + +/** + * Description + * + * @constructor print peach + */ +class Peach { + init { + println("peach") + } +}
\ No newline at end of file diff --git a/core/testdata/javadoc/deprecated.java b/core/testdata/javadoc/deprecated.java new file mode 100644 index 00000000..5a6cdd77 --- /dev/null +++ b/core/testdata/javadoc/deprecated.java @@ -0,0 +1,28 @@ +package bar; + +/** + * Just a fruit + */ +public class Banana { + private Double weight; + + /** + * Returns weight + * + * @return weight + * @deprecated + */ + public Double getWeight() { + return weight; + } + + /** + * Sets weight + * + * @param weight in grams + * @deprecated with message + */ + public void setWeight(Double weight) { + this.weight = weight; + } +}
\ No newline at end of file diff --git a/core/testdata/javadoc/noArgConstructor.kt b/core/testdata/javadoc/noArgConstructor.kt new file mode 100644 index 00000000..25e5548c --- /dev/null +++ b/core/testdata/javadoc/noArgConstructor.kt @@ -0,0 +1,12 @@ +package foo + +/** + * Description + * + * @constructor print plum + */ +class Plum() { + init { + println("plum") + } +}
\ No newline at end of file diff --git a/core/testdata/javadoc/vararg.kt b/core/testdata/javadoc/vararg.kt new file mode 100644 index 00000000..aa6c26d7 --- /dev/null +++ b/core/testdata/javadoc/vararg.kt @@ -0,0 +1,3 @@ +fun vararg(a: String, vararg b: Int) {} + +fun varargInMiddle(a: String, vararg b: Int, c: Short) {}
\ No newline at end of file diff --git a/core/testdata/javadoc/visibilityModifiers.kt b/core/testdata/javadoc/visibilityModifiers.kt new file mode 100644 index 00000000..e48e7f62 --- /dev/null +++ b/core/testdata/javadoc/visibilityModifiers.kt @@ -0,0 +1,15 @@ +package foo + +abstract class Apple { + protected var name: String = "foo" + internal var weight: Int = 180 + var rating: Int = 10 + private var color: String = "red" + + companion object { + @JvmStatic + val code : Int = 123456 + } + + +}
\ No newline at end of file diff --git a/core/testdata/markdown/spec.txt b/core/testdata/markdown/spec.txt index fce87924..916bdd89 100644 --- a/core/testdata/markdown/spec.txt +++ b/core/testdata/markdown/spec.txt @@ -23,7 +23,7 @@ HTML but in LaTeX and many other formats. ## Why is a spec needed? John Gruber's [canonical description of Markdown's -syntax](http://daringfireball.net/projects/markdown/syntax) +syntax](https://daringfireball.net/projects/markdown/syntax) does not specify the syntax unambiguously. Here are some examples of questions it does not answer: @@ -34,7 +34,7 @@ questions it does not answer: not require that. This is hardly a "corner case," and divergences between implementations on this issue often lead to surprises for users in real documents. (See [this comment by John - Gruber](http://article.gmane.org/gmane.text.markdown.general/1997).) + Gruber](https://article.gmane.org/gmane.text.markdown.general/1997).) 2. Is a blank line needed before a block quote or header? Most implementations do not require the blank line. However, @@ -42,7 +42,7 @@ questions it does not answer: also to ambiguities in parsing (note that some implementations put the header inside the blockquote, while others do not). (John Gruber has also spoken [in favor of requiring the blank - lines](http://article.gmane.org/gmane.text.markdown.general/2146).) + lines](https://article.gmane.org/gmane.text.markdown.general/2146).) 3. Is a blank line needed before an indented code block? (`Markdown.pl` requires it, but this is not mentioned in the @@ -75,7 +75,7 @@ questions it does not answer: ``` (There are some relevant comments by John Gruber - [here](http://article.gmane.org/gmane.text.markdown.general/2554).) + [here](https://article.gmane.org/gmane.text.markdown.general/2554).) 5. Can list markers be indented? Can ordered list markers be right-aligned? @@ -509,7 +509,7 @@ More than six `#` characters is not a header: A space is required between the `#` characters and the header's contents. Note that many implementations currently do not require the space. However, the space was required by the [original ATX -implementation](http://www.aaronsw.com/2002/atx/atx.py), and it helps +implementation](https://www.aaronsw.com/2002/atx/atx.py), and it helps prevent things like the following from being parsed as headers: . @@ -3686,9 +3686,9 @@ raw HTML: . . -<http://google.com?find=\*> +<https://google.com?find=\*> . -<p><a href="http://google.com?find=%5C*">http://google.com?find=\*</a></p> +<p><a href="https://google.com?find=%5C*">https://google.com?find=\*</a></p> . . @@ -3736,7 +3736,7 @@ and simplifies the job of implementations targetting other languages, as these w UTF8 chars and need not be HTML-entity aware. [Named entities](#name-entities) <a id="named-entities"></a> consist of `&` -+ any of the valid HTML5 entity names + `;`. The [following document](http://www.whatwg.org/specs/web-apps/current-work/multipage/entities.json) ++ any of the valid HTML5 entity names + `;`. The [following document](https://www.whatwg.org/specs/web-apps/current-work/multipage/entities.json) is used as an authoritative source of the valid entity names and their corresponding codepoints. Conforming implementations that target Markdown don't need to generate entities for all the valid @@ -3955,9 +3955,9 @@ And this is not parsed as a link: But this is a link: . -<http://foo.bar.`baz>` +<https://foo.bar.`baz>` . -<p><a href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p> +<p><a href="https://foo.bar.%60baz">https://foo.bar.`baz</a>`</p> . And this is an HTML tag: @@ -3986,7 +3986,7 @@ we just have literal backticks: ## Emphasis and strong emphasis John Gruber's original [Markdown syntax -description](http://daringfireball.net/projects/markdown/syntax#em) says: +description](https://daringfireball.net/projects/markdown/syntax#em) says: > Markdown treats asterisks (`*`) and underscores (`_`) as indicators of > emphasis. Text wrapped with one `*` or `_` will be wrapped with an HTML @@ -4229,15 +4229,15 @@ _a `_`_ . . -**a<http://foo.bar?q=**> +**a<https://foo.bar?q=**> . -<p>**a<a href="http://foo.bar?q=**">http://foo.bar?q=**</a></p> +<p>**a<a href="https://foo.bar?q=**">https://foo.bar?q=**</a></p> . . -__a<http://foo.bar?q=__> +__a<https://foo.bar?q=__> . -<p>__a<a href="http://foo.bar?q=__">http://foo.bar?q=__</a></p> +<p>__a<a href="https://foo.bar?q=__">https://foo.bar?q=__</a></p> . This is not emphasis, because the opening delimiter is @@ -5455,15 +5455,15 @@ soap.beep`, `soap.beeps`, `tag`, `tel`, `telnet`, `tftp`, `thismessage`, Here are some valid autolinks: . -<http://foo.bar.baz> +<https://foo.bar.baz> . -<p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p> +<p><a href="https://foo.bar.baz">https://foo.bar.baz</a></p> . . -<http://foo.bar.baz?q=hello&id=22&boolean> +<https://foo.bar.baz?q=hello&id=22&boolean> . -<p><a href="http://foo.bar.baz?q=hello&id=22&boolean">http://foo.bar.baz?q=hello&id=22&boolean</a></p> +<p><a href="https://foo.bar.baz?q=hello&id=22&boolean">https://foo.bar.baz?q=hello&id=22&boolean</a></p> . . @@ -5483,9 +5483,9 @@ Uppercase is also fine: Spaces are not allowed in autolinks: . -<http://foo.bar/baz bim> +<https://foo.bar/baz bim> . -<p><http://foo.bar/baz bim></p> +<p><https://foo.bar/baz bim></p> . An [email autolink](#email-autolink) <a id="email-autolink"></a> @@ -5496,7 +5496,7 @@ and the URL is `mailto:` followed by the email address. An [email address](#email-address), <a id="email-address"></a> for these purposes, is anything that matches the [non-normative regex from the HTML5 -spec](http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-%28type=email%29): +spec](https://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-%28type=email%29): /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ @@ -5530,9 +5530,9 @@ These are not autolinks: . . -< http://foo.bar > +< https://foo.bar > . -<p>< http://foo.bar ></p> +<p>< https://foo.bar ></p> . . @@ -5548,9 +5548,9 @@ These are not autolinks: . . -http://google.com +https://google.com . -<p>http://google.com</p> +<p>https://google.com</p> . . diff --git a/core/testdata/packagedocs/referenceLinks.kotlin.md b/core/testdata/packagedocs/referenceLinks.kotlin.md index ac7e4b48..f7b1edad 100644 --- a/core/testdata/packagedocs/referenceLinks.kotlin.md +++ b/core/testdata/packagedocs/referenceLinks.kotlin.md @@ -1,7 +1,6 @@ Core functions and types -See [ref](http://example.com) -Also, [example](http://example.com) +See [ref](https://example.com) +Also, [example](https://example.com) -
\ No newline at end of file diff --git a/core/testdata/packagedocs/referenceLinks.md b/core/testdata/packagedocs/referenceLinks.md index 7583ee9d..177dea0c 100644 --- a/core/testdata/packagedocs/referenceLinks.md +++ b/core/testdata/packagedocs/referenceLinks.md @@ -14,4 +14,4 @@ See [ref] Also, [example][ref] <!-- Refs --> -[ref]: http://example.com +[ref]: https://example.com diff --git a/core/testdata/packagedocs/referenceLinks.module.md b/core/testdata/packagedocs/referenceLinks.module.md index ddbdbe2f..08372175 100644 --- a/core/testdata/packagedocs/referenceLinks.module.md +++ b/core/testdata/packagedocs/referenceLinks.module.md @@ -4,6 +4,6 @@ The Kotlin standard library is a set of functions and types implementing idiomatic patterns when working with collections, text and files. -See [ref](http://example.com) -Also, [example](http://example.com) +See [ref](https://example.com) +Also, [example](https://example.com) diff --git a/core/testdata/properties/annotatedProperty.kt b/core/testdata/properties/annotatedProperty.kt index 8990af29..3c12691b 100644 --- a/core/testdata/properties/annotatedProperty.kt +++ b/core/testdata/properties/annotatedProperty.kt @@ -1 +1 @@ -@Volatile var property = "test"
\ No newline at end of file +@Strictfp var property = "test"
\ No newline at end of file diff --git a/core/testdata/sourceLinks/dummy.kt b/core/testdata/sourceLinks/dummy.kt new file mode 100644 index 00000000..cbaffe7c --- /dev/null +++ b/core/testdata/sourceLinks/dummy.kt @@ -0,0 +1,6 @@ +/** + * Some doc. + */ +fun foo(){ + +} diff --git a/gradle.properties b/gradle.properties index eec65c0b..3d61b9d0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,5 @@ -dokka_version_base=0.9.18 +dokka_version=0.9.18-SNAPSHOT +dokka_version_base=0.9.18-SNAPSHOT dokka_publication_channel=dokka #Kotlin compiler and plugin @@ -13,4 +14,7 @@ maven_version=3.5.0 maven_archiver_version=2.5 plexus_utils_version=3.0.22 plexus_archiver_version=3.4 -maven_plugin_tools_version=3.5 +maven_plugin_tools_version=3.5.2 + +#For CI +mvn=mvn
\ No newline at end of file diff --git a/runners/android-gradle-plugin/build.gradle b/runners/android-gradle-plugin/build.gradle index 72d1be9e..28b0cbb9 100644 --- a/runners/android-gradle-plugin/build.gradle +++ b/runners/android-gradle-plugin/build.gradle @@ -76,7 +76,7 @@ artifacts { } pluginBundle { - website = 'http://www.kotlinlang.org/' + website = 'https://www.kotlinlang.org/' vcsUrl = 'https://github.com/kotlin/dokka.git' description = 'Dokka, the Kotlin documentation tool' tags = ['dokka', 'kotlin', 'kdoc', 'android'] diff --git a/runners/android-gradle-plugin/src/main/kotlin/mainAndroid.kt b/runners/android-gradle-plugin/src/main/kotlin/mainAndroid.kt index bd2e88c2..b1996da0 100644 --- a/runners/android-gradle-plugin/src/main/kotlin/mainAndroid.kt +++ b/runners/android-gradle-plugin/src/main/kotlin/mainAndroid.kt @@ -10,6 +10,7 @@ open class DokkaAndroidPlugin : Plugin<Project> { override fun apply(project: Project) { DokkaVersion.loadFrom(javaClass.getResourceAsStream("/META-INF/gradle-plugins/org.jetbrains.dokka-android.properties")) project.tasks.create("dokka", DokkaAndroidTask::class.java).apply { + dokkaRuntime = project.configurations.create("dokkaRuntime") moduleName = project.name outputDirectory = File(project.buildDir, "dokka").absolutePath } diff --git a/runners/ant/src/main/kotlin/ant/dokka.kt b/runners/ant/src/main/kotlin/ant/dokka.kt index 5a4111e8..fe793396 100644 --- a/runners/ant/src/main/kotlin/ant/dokka.kt +++ b/runners/ant/src/main/kotlin/ant/dokka.kt @@ -80,7 +80,7 @@ class AntPassConfig(task: Task) : DokkaConfiguration.PassConfiguration { get() { val links = mutableListOf<DokkaConfiguration.ExternalDocumentationLink>() if (!noJdkLink) - links += DokkaConfiguration.ExternalDocumentationLink.Builder("http://docs.oracle.com/javase/$jdkVersion/docs/api/").build() + links += DokkaConfiguration.ExternalDocumentationLink.Builder("https://docs.oracle.com/javase/$jdkVersion/docs/api/").build() if (!noStdlibLink) links += DokkaConfiguration.ExternalDocumentationLink.Builder("https://kotlinlang.org/api/latest/jvm/stdlib/").build() @@ -172,6 +172,9 @@ class DokkaAntTask: Task(), DokkaConfiguration { if (sourceLink.path == null) { throw BuildException("'path' attribute of a <sourceLink> element is required") } + if (sourceLink.path.contains("\\")) { + throw BuildException("'dir' attribute of a <sourceLink> - incorrect value, only Unix based path allowed") + } if (sourceLink.url == null) { throw BuildException("'url' attribute of a <sourceLink> element is required") diff --git a/runners/gradle-integration-tests/build.gradle b/runners/gradle-integration-tests/build.gradle index a681c82e..297a175a 100644 --- a/runners/gradle-integration-tests/build.gradle +++ b/runners/gradle-integration-tests/build.gradle @@ -56,4 +56,5 @@ testClasses.dependsOn createClasspathManifest test { systemProperty "android.licenses.overwrite", project.findProperty("android.licenses.overwrite") ?: "" + inputs.dir(file('testData')) }
\ No newline at end of file diff --git a/runners/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/TypeSafeConfigurationTest.kt b/runners/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/TypeSafeConfigurationTest.kt new file mode 100644 index 00000000..7b179e92 --- /dev/null +++ b/runners/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/TypeSafeConfigurationTest.kt @@ -0,0 +1,36 @@ +package org.jetbrains.dokka.gradle + +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +@RunWith(Parameterized::class) +class TypeSafeConfigurationTest(private val testCase: TestCase) : AbstractDokkaGradleTest() { + + data class TestCase(val gradleVersion: String, val kotlinVersion: String) { + override fun toString(): String = "Gradle $gradleVersion and Kotlin $kotlinVersion" + } + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun testCases() = listOf( + TestCase("4.0", "1.1.2"), + TestCase("4.5", "1.2.20"), + TestCase("4.10.1", "1.2.60") + ) + } + + @Test + fun test() { + + testDataFolder.resolve("typeSafeConfiguration").toFile() + .copyRecursively(testProjectDir.root) + + configure( + testCase.gradleVersion, + testCase.kotlinVersion, + arguments = arrayOf("help", "-s") + ).build() + } +} diff --git a/runners/gradle-integration-tests/testData/androidApp/build.gradle b/runners/gradle-integration-tests/testData/androidApp/build.gradle index 59477b52..35356b90 100644 --- a/runners/gradle-integration-tests/testData/androidApp/build.gradle +++ b/runners/gradle-integration-tests/testData/androidApp/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() jcenter() maven { url 'https://maven.google.com' } - maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } } dependencies { @@ -15,7 +15,7 @@ allprojects { repositories { mavenCentral() jcenter() - maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } } } diff --git a/runners/gradle-integration-tests/testData/androidApp/fileTree.txt b/runners/gradle-integration-tests/testData/androidApp/fileTree.txt index 3827b69e..f66c79e3 100644 --- a/runners/gradle-integration-tests/testData/androidApp/fileTree.txt +++ b/runners/gradle-integration-tests/testData/androidApp/fileTree.txt @@ -9,6 +9,7 @@ -init-.html index.html on-create-options-menu.html + on-create.html -kotlin-activity/ -init-.html index.html diff --git a/runners/gradle-integration-tests/testData/androidAppJavadoc/build.gradle b/runners/gradle-integration-tests/testData/androidAppJavadoc/build.gradle index 59477b52..35356b90 100644 --- a/runners/gradle-integration-tests/testData/androidAppJavadoc/build.gradle +++ b/runners/gradle-integration-tests/testData/androidAppJavadoc/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() jcenter() maven { url 'https://maven.google.com' } - maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } } dependencies { @@ -15,7 +15,7 @@ allprojects { repositories { mavenCentral() jcenter() - maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } } } diff --git a/runners/gradle-integration-tests/testData/androidMultiFlavourApp/build.gradle b/runners/gradle-integration-tests/testData/androidMultiFlavourApp/build.gradle index 59477b52..35356b90 100644 --- a/runners/gradle-integration-tests/testData/androidMultiFlavourApp/build.gradle +++ b/runners/gradle-integration-tests/testData/androidMultiFlavourApp/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() jcenter() maven { url 'https://maven.google.com' } - maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } } dependencies { @@ -15,7 +15,7 @@ allprojects { repositories { mavenCentral() jcenter() - maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } } } diff --git a/runners/gradle-integration-tests/testData/androidMultiFlavourApp/fileTree.txt b/runners/gradle-integration-tests/testData/androidMultiFlavourApp/fileTree.txt index 5e969d8b..77b563b2 100644 --- a/runners/gradle-integration-tests/testData/androidMultiFlavourApp/fileTree.txt +++ b/runners/gradle-integration-tests/testData/androidMultiFlavourApp/fileTree.txt @@ -10,6 +10,7 @@ -init-.html index.html on-create-options-menu.html + on-create.html -kotlin-activity/ -init-.html index.html @@ -35,6 +36,7 @@ -init-.html index.html on-create-options-menu.html + on-create.html -kotlin-activity/ -init-.html index.html diff --git a/runners/gradle-integration-tests/testData/basic/build.gradle b/runners/gradle-integration-tests/testData/basic/build.gradle index 4a259f50..a3116751 100644 --- a/runners/gradle-integration-tests/testData/basic/build.gradle +++ b/runners/gradle-integration-tests/testData/basic/build.gradle @@ -2,7 +2,7 @@ buildscript { repositories { mavenCentral() jcenter() - maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } } dependencies { @@ -21,7 +21,7 @@ repositories { mavenCentral() jcenter() maven { - url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" + url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" diff --git a/runners/gradle-integration-tests/testData/multiProjectSingleOut/build.gradle b/runners/gradle-integration-tests/testData/multiProjectSingleOut/build.gradle index 68d93e30..4f561472 100644 --- a/runners/gradle-integration-tests/testData/multiProjectSingleOut/build.gradle +++ b/runners/gradle-integration-tests/testData/multiProjectSingleOut/build.gradle @@ -7,7 +7,7 @@ subprojects { repositories { mavenCentral() jcenter() - maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } } dependencies { @@ -17,7 +17,7 @@ subprojects { repositories { mavenCentral() jcenter() - maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } } } diff --git a/runners/gradle-integration-tests/testData/sourcesChange/build.gradle b/runners/gradle-integration-tests/testData/sourcesChange/build.gradle index bc20e1cf..4627e8ef 100644 --- a/runners/gradle-integration-tests/testData/sourcesChange/build.gradle +++ b/runners/gradle-integration-tests/testData/sourcesChange/build.gradle @@ -2,7 +2,7 @@ buildscript { repositories { mavenCentral() jcenter() - maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" } } dependencies { @@ -21,7 +21,7 @@ repositories { mavenCentral() jcenter() maven { - url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" + url "https://dl.bintray.com/kotlin/kotlin-eap-1.1" } maven { url "https://dl.bintray.com/kotlin/kotlin-dev" diff --git a/runners/gradle-integration-tests/testData/typeSafeConfiguration/build.gradle b/runners/gradle-integration-tests/testData/typeSafeConfiguration/build.gradle new file mode 100644 index 00000000..327cead8 --- /dev/null +++ b/runners/gradle-integration-tests/testData/typeSafeConfiguration/build.gradle @@ -0,0 +1,84 @@ +import org.jetbrains.dokka.* +import org.jetbrains.dokka.gradle.* +import org.jetbrains.kotlin.gradle.tasks.* + +import groovy.transform.CompileStatic +import java.util.concurrent.Callable + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$test_kotlin_version" + } +} + +plugins { + id 'org.jetbrains.dokka' +} + +apply plugin: 'kotlin' + +@CompileStatic +def configureDokkaTypeSafely(DokkaTask dokka) { + dokka.with { + moduleName = "some String" + outputFormat = "some String" + outputDirectory = "some String" + classpath = Collections.singleton(file("someClassDir")) + includes = Collections.emptyList() + linkMappings = new ArrayList<LinkMapping>() + samples = Collections.emptyList() + jdkVersion = 6 + sourceDirs = Collections.<File>emptyList() + sourceRoots = new ArrayList<SourceRoot>() + dokkaFatJar = file("some File") + includeNonPublic = false + skipDeprecated = false + skipEmptyPackages = true + reportUndocumented = true + perPackageOptions = new ArrayList<PackageOptions>() + impliedPlatforms = Collections.<String>emptyList() + externalDocumentationLinks = new ArrayList<DokkaConfiguration.ExternalDocumentationLink>() + noStdlibLink = false + cacheRoot = null as String + languageVersion = null as String + apiVersion = null as String + kotlinTasks(new Callable<List<Object>>() { + @Override + List<Object> call() { + return defaultKotlinTasks() + } + }) + linkMapping(new Action<LinkMapping>() { + @Override + void execute(LinkMapping mapping) { + mapping.dir = "some String" + mapping.url = "some String" + } + }) + sourceRoot(new Action<SourceRoot>() { + @Override + void execute(SourceRoot sourceRoot) { + sourceRoot.path = "some String" + } + }) + packageOptions(new Action<PackageOptions>() { + @Override + void execute(PackageOptions packageOptions) { + packageOptions.prefix = "some String" + } + }) + externalDocumentationLink(new Action<DokkaConfiguration.ExternalDocumentationLink.Builder>() { + @Override + void execute(DokkaConfiguration.ExternalDocumentationLink.Builder builder) { + builder.url = uri("some URI").toURL() + } + }) + } +} + +project.tasks.withType(DokkaTask) { dokka -> + configureDokkaTypeSafely(dokka) +} diff --git a/runners/gradle-integration-tests/testData/typeSafeConfiguration/settings.gradle b/runners/gradle-integration-tests/testData/typeSafeConfiguration/settings.gradle new file mode 100644 index 00000000..be82e328 --- /dev/null +++ b/runners/gradle-integration-tests/testData/typeSafeConfiguration/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "type-safe-configuration"
\ No newline at end of file diff --git a/runners/gradle-plugin/build.gradle b/runners/gradle-plugin/build.gradle index 661d432b..8e59a7be 100644 --- a/runners/gradle-plugin/build.gradle +++ b/runners/gradle-plugin/build.gradle @@ -74,7 +74,7 @@ artifacts { } pluginBundle { - website = 'http://www.kotlinlang.org/' + website = 'https://www.kotlinlang.org/' vcsUrl = 'https://github.com/kotlin/dokka.git' description = 'Dokka, the Kotlin documentation tool' tags = ['dokka', 'kotlin', 'kdoc'] diff --git a/runners/gradle-plugin/src/main/kotlin/main.kt b/runners/gradle-plugin/src/main/kotlin/main.kt index 25ca370b..f726c6c7 100644 --- a/runners/gradle-plugin/src/main/kotlin/main.kt +++ b/runners/gradle-plugin/src/main/kotlin/main.kt @@ -1,10 +1,12 @@ package org.jetbrains.dokka.gradle import groovy.lang.Closure +import org.gradle.api.Action import org.gradle.api.DefaultTask import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task +import org.gradle.api.artifacts.Configuration import org.gradle.api.file.FileCollection import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.plugins.JavaPluginConvention @@ -30,6 +32,7 @@ open class DokkaPlugin : Plugin<Project> { override fun apply(project: Project) { DokkaVersion.loadFrom(javaClass.getResourceAsStream("/META-INF/gradle-plugins/org.jetbrains.dokka.properties")) project.tasks.create("dokka", DokkaTask::class.java).apply { + dokkaRuntime = project.configurations.create("dokkaRuntime") moduleName = project.name outputDirectory = File(project.buildDir, "dokka").absolutePath } @@ -80,7 +83,7 @@ open class DokkaTask : DefaultTask() { @Input var outputFormat: String = "html" var outputDirectory: String = "" - + var dokkaRuntime: Configuration? = null @Deprecated("Going to be removed in 0.9.16, use classpath + sourceDirs instead if kotlinTasks is not suitable for you") @Input var processConfigurations: List<Any?> = emptyList() @@ -147,14 +150,17 @@ open class DokkaTask : DefaultTask() { private var kotlinTasksConfigurator: () -> List<Any?>? = { defaultKotlinTasks() } private val kotlinTasks: List<Task> by lazy { extractKotlinCompileTasks() } + fun kotlinTasks(taskSupplier: Callable<List<Any>>) { + kotlinTasksConfigurator = { taskSupplier.call() } + } + fun kotlinTasks(closure: Closure<Any?>) { kotlinTasksConfigurator = { closure.call() as? List<Any?> } } - fun linkMapping(closure: Closure<Unit>) { + fun linkMapping(action: Action<LinkMapping>) { val mapping = LinkMapping() - closure.delegate = mapping - closure.call() + action.execute(mapping) if (mapping.path.isEmpty()) { throw IllegalArgumentException("Link mapping should have dir") @@ -166,33 +172,55 @@ open class DokkaTask : DefaultTask() { linkMappings.add(mapping) } - fun sourceRoot(closure: Closure<Unit>) { + fun linkMapping(closure: Closure<Unit>) { + linkMapping(Action { mapping -> + closure.delegate = mapping + closure.call() + }) + } + + fun sourceRoot(action: Action<SourceRoot>) { val sourceRoot = SourceRoot() - closure.delegate = sourceRoot - closure.call() + action.execute(sourceRoot) sourceRoots.add(sourceRoot) } - fun packageOptions(closure: Closure<Unit>) { + fun sourceRoot(closure: Closure<Unit>) { + sourceRoot(Action { sourceRoot -> + closure.delegate = sourceRoot + closure.call() + }) + } + + fun packageOptions(action: Action<PackageOptions>) { val packageOptions = PackageOptions() - closure.delegate = packageOptions - closure.call() + action.execute(packageOptions) perPackageOptions.add(packageOptions) } - fun externalDocumentationLink(closure: Closure<Unit>) { + fun packageOptions(closure: Closure<Unit>) { + packageOptions(Action { packageOptions -> + closure.delegate = packageOptions + closure.call() + }) + } + + fun externalDocumentationLink(action: Action<DokkaConfiguration.ExternalDocumentationLink.Builder>) { val builder = DokkaConfiguration.ExternalDocumentationLink.Builder() - closure.delegate = builder - closure.call() + action.execute(builder) externalDocumentationLinks.add(builder.build()) } - fun tryResolveFatJar(project: Project): File { + fun externalDocumentationLink(closure: Closure<Unit>) { + externalDocumentationLink(Action { builder -> + closure.delegate = builder + closure.call() + }) + } + + fun tryResolveFatJar(project: Project): Set<File> { return try { - val dependency = project.buildscript.dependencies.create(dokkaFatJar) - val configuration = project.buildscript.configurations.detachedConfiguration(dependency) - configuration.description = "Dokka main jar" - configuration.resolve().first() + dokkaRuntime!!.resolve() } catch (e: Exception) { project.parent?.let { tryResolveFatJar(it) } ?: throw e } @@ -200,11 +228,11 @@ open class DokkaTask : DefaultTask() { fun loadFatJar() { if (fatJarClassLoader == null) { - val fatjar = if (dokkaFatJar is File) - dokkaFatJar as File + val jars = if (dokkaFatJar is File) + setOf(dokkaFatJar as File) else tryResolveFatJar(project) - fatJarClassLoader = URLClassLoader(arrayOf(fatjar.toURI().toURL()), ClassLoader.getSystemClassLoader().parent) + fatJarClassLoader = URLClassLoader(jars.map { it.toURI().toURL() }.toTypedArray(), ClassLoader.getSystemClassLoader().parent) } } @@ -269,6 +297,11 @@ open class DokkaTask : DefaultTask() { @TaskAction fun generate() { + if (dokkaRuntime == null){ + dokkaRuntime = project.configurations.getByName("dokkaRuntime") + } + + dokkaRuntime?.defaultDependencies{ dependencies -> dependencies.add(project.dependencies.create(dokkaFatJar)) } val kotlinColorsEnabledBefore = System.getProperty(COLORS_ENABLED_PROPERTY) ?: "false" System.setProperty(COLORS_ENABLED_PROPERTY, "false") try { @@ -414,7 +447,9 @@ open class LinkMapping : Serializable, DokkaConfiguration.SourceLinkDefinition { var dir: String get() = path set(value) { - path = value + if (value.contains("\\")) + throw java.lang.IllegalArgumentException("Incorrect dir property, only Unix based path allowed.") + else path = value } override var path: String = "" diff --git a/runners/maven-plugin/build.gradle b/runners/maven-plugin/build.gradle index 7e94058e..2e9d0b1b 100644 --- a/runners/maven-plugin/build.gradle +++ b/runners/maven-plugin/build.gradle @@ -49,50 +49,84 @@ task setupMaven(type: Sync) { into "$buildDir/maven-bin" } +def mavenBuildDir = "$buildDir/maven" + + +sourceSets.main.resources { + srcDirs += "$mavenBuildDir/classes/java/main" + exclude "**/*.class" +} + task generatePom() { inputs.file(new File(projectDir, "pom.tpl.xml")) - outputs.file(new File(buildDir, "pom.xml")) + outputs.file(new File(mavenBuildDir, "pom.xml")) doLast { final pomTemplate = new File(projectDir, "pom.tpl.xml") - final pom = new File(buildDir, "pom.xml") + final pom = new File(mavenBuildDir, "pom.xml") + pom.parentFile.mkdirs() pom.text = pomTemplate.text.replace("<version>dokka_version</version>", "<version>$dokka_version</version>") .replace("<maven.version></maven.version>", "<maven.version>$maven_version</maven.version>") .replace("<version>maven-plugin-plugin</version>", "<version>$maven_plugin_tools_version</version>") } } - -task mergeClassOutputs doLast { - def sourceDir = new File(buildDir, "classes/kotlin") - def targetDir = new File(buildDir, "classes/java") - - sourceDir.eachFileRecurse FileType.ANY, { - def filePath = it.toPath() - def targetFilePath = targetDir.toPath().resolve(sourceDir.toPath().relativize(filePath)) - if (it.isFile()) { - Files.move(filePath, targetFilePath, StandardCopyOption.REPLACE_EXISTING) - } else if (it.isDirectory()) { - targetFilePath.toFile().mkdirs() - } +// +//task mergeClassOutputs doLast { +// def sourceDir = new File(buildDir, "classes/kotlin") +// def targetDir = new File(buildDir, "classes/java") +// +// sourceDir.eachFileRecurse FileType.ANY, { +// def filePath = it.toPath() +// def targetFilePath = targetDir.toPath().resolve(sourceDir.toPath().relativize(filePath)) +// if (it.isFile()) { +// Files.move(filePath, targetFilePath, StandardCopyOption.REPLACE_EXISTING) +// } else if (it.isDirectory()) { +// targetFilePath.toFile().mkdirs() +// } +// } +//} + + + +task syncKotlinClasses(type: Sync, dependsOn: compileKotlin) { + from "$buildDir/classes/kotlin" + into "$mavenBuildDir/classes/java" + + preserve { + include '**/*.class' } } -task pluginDescriptor(type: CrossPlatformExec, dependsOn: setupMaven) { - workingDir buildDir - commandLine mvn, '-e', '-B', 'org.apache.maven.plugins:maven-plugin-plugin:descriptor' +task syncJavaClasses(type: Sync, dependsOn: compileJava) { + from "$buildDir/classes/java" + into "$mavenBuildDir/classes/java" - dependsOn mergeClassOutputs + preserve { + include '**/*.class' + } } task helpMojo(type: CrossPlatformExec, dependsOn: setupMaven) { - workingDir buildDir + workingDir mavenBuildDir commandLine mvn, '-e', '-B', 'org.apache.maven.plugins:maven-plugin-plugin:helpmojo' - dependsOn mergeClassOutputs + dependsOn syncKotlinClasses +} + + +task pluginDescriptor(type: CrossPlatformExec, dependsOn: setupMaven) { + workingDir mavenBuildDir + commandLine mvn, '-e', '-B', 'org.apache.maven.plugins:maven-plugin-plugin:descriptor' + + dependsOn syncJavaClasses } + +//mergeClassOutputs.dependsOn compileKotlin +//helpMojo.dependsOn mergeClassOutputs helpMojo.dependsOn generatePom -sourceSets.main.java.srcDir("$buildDir/generated-sources/plugin") +sourceSets.main.java.srcDir("$buildDir/maven/generated-sources/plugin") compileJava.dependsOn helpMojo +processResources.dependsOn pluginDescriptor pluginDescriptor.dependsOn generatePom diff --git a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt index a2771306..ed8a659f 100644 --- a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt +++ b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt @@ -4,6 +4,7 @@ import org.apache.maven.archiver.MavenArchiveConfiguration import org.apache.maven.archiver.MavenArchiver import org.apache.maven.execution.MavenSession import org.apache.maven.plugin.AbstractMojo +import org.apache.maven.plugin.MojoExecutionException import org.apache.maven.plugins.annotations.* import org.apache.maven.project.MavenProject import org.apache.maven.project.MavenProjectHelper @@ -122,6 +123,12 @@ abstract class AbstractDokkaMojo : AbstractMojo() { return } + sourceLinks.forEach { + if (it.dir.contains("\\")) { + throw MojoExecutionException("Incorrect dir property, only Unix based path allowed.") + } + } + val passConfiguration = PassConfigurationImpl( sourceLinks = sourceLinks.map { SourceLinkDefinitionImpl(it.dir, it.url, it.urlSuffix) }, jdkVersion = jdkVersion, @@ -200,7 +207,7 @@ class DokkaJavadocJarMojo : AbstractDokkaMojo() { /** * The archive configuration to use. - * See [Maven Archiver Reference](http://maven.apache.org/shared/maven-archiver/index.html) + * See [Maven Archiver Reference](https://maven.apache.org/shared/maven-archiver/index.html) */ @Parameter private val archive = MavenArchiveConfiguration() |