diff options
25 files changed, 757 insertions, 538 deletions
diff --git a/plugins/base/api/base.api b/plugins/base/api/base.api index 083c9973..bf5dcff7 100644 --- a/plugins/base/api/base.api +++ b/plugins/base/api/base.api @@ -400,22 +400,44 @@ public abstract class org/jetbrains/dokka/base/renderers/html/NavigationDataProv } public final class org/jetbrains/dokka/base/renderers/html/NavigationNode : org/jetbrains/dokka/model/WithChildren { - public fun <init> (Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Ljava/util/List;)V + public fun <init> (Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon;Ljava/util/List;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Lorg/jetbrains/dokka/links/DRI; public final fun component3 ()Ljava/util/Set; - public final fun component4 ()Ljava/util/List; - public final fun copy (Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Ljava/util/List;)Lorg/jetbrains/dokka/base/renderers/html/NavigationNode; - public static synthetic fun copy$default (Lorg/jetbrains/dokka/base/renderers/html/NavigationNode;Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Ljava/util/List;ILjava/lang/Object;)Lorg/jetbrains/dokka/base/renderers/html/NavigationNode; + public final fun component4 ()Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public final fun component5 ()Ljava/util/List; + public final fun copy (Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon;Ljava/util/List;)Lorg/jetbrains/dokka/base/renderers/html/NavigationNode; + public static synthetic fun copy$default (Lorg/jetbrains/dokka/base/renderers/html/NavigationNode;Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon;Ljava/util/List;ILjava/lang/Object;)Lorg/jetbrains/dokka/base/renderers/html/NavigationNode; public fun equals (Ljava/lang/Object;)Z public fun getChildren ()Ljava/util/List; public final fun getDri ()Lorg/jetbrains/dokka/links/DRI; + public final fun getIcon ()Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; public final fun getName ()Ljava/lang/String; public final fun getSourceSets ()Ljava/util/Set; public fun hashCode ()I public fun toString ()Ljava/lang/String; } +public final class org/jetbrains/dokka/base/renderers/html/NavigationNodeIcon : java/lang/Enum { + public static final field ABSTRACT_CLASS Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field ABSTRACT_CLASS_KT Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field ANNOTATION_CLASS Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field ANNOTATION_CLASS_KT Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field CLASS Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field CLASS_KT Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field ENUM_CLASS Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field ENUM_CLASS_KT Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field EXCEPTION Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field FUNCTION Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field INTERFACE Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field INTERFACE_KT Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field OBJECT Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field VAL Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static final field VAR Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; + public static fun values ()[Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon; +} + public final class org/jetbrains/dokka/base/renderers/html/NavigationPage : org/jetbrains/dokka/pages/RendererSpecificPage { public fun <init> (Lorg/jetbrains/dokka/base/renderers/html/NavigationNode;Ljava/lang/String;Lorg/jetbrains/dokka/plugability/DokkaContext;)V public fun getChildren ()Ljava/util/List; diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt new file mode 100644 index 00000000..647ba687 --- /dev/null +++ b/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt @@ -0,0 +1,90 @@ +package org.jetbrains.dokka.base.renderers.html + +import org.jetbrains.dokka.base.renderers.sourceSets +import org.jetbrains.dokka.base.transformers.documentables.isException +import org.jetbrains.dokka.base.translators.documentables.DocumentableLanguage +import org.jetbrains.dokka.base.translators.documentables.documentableLanguage +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.pages.* + +abstract class NavigationDataProvider { + open fun navigableChildren(input: RootPageNode): NavigationNode = input.withDescendants() + .first { it is ModulePage || it is MultimoduleRootPage }.let { visit(it as ContentPage) } + + open fun visit(page: ContentPage): NavigationNode = + NavigationNode( + name = page.displayableName(), + dri = page.dri.first(), + sourceSets = page.sourceSets(), + icon = chooseNavigationIcon(page), + children = page.navigableChildren() + ) + + /** + * Parenthesis is applied in 1 case: + * - page only contains functions (therefore documentable from this page is [DFunction]) + */ + private fun ContentPage.displayableName(): String = + if (this is WithDocumentables && documentables.all { it is DFunction }) { + "$name()" + } else { + name + } + + private fun chooseNavigationIcon(contentPage: ContentPage): NavigationNodeIcon? { + return if (contentPage is WithDocumentables) { + val documentable = contentPage.documentables.firstOrNull() + val isJava = documentable?.hasAnyJavaSources() ?: false + + when (documentable) { + is DClass -> when { + documentable.isException -> NavigationNodeIcon.EXCEPTION + documentable.isAbstract() -> { + if (isJava) NavigationNodeIcon.ABSTRACT_CLASS else NavigationNodeIcon.ABSTRACT_CLASS_KT + } + else -> if (isJava) NavigationNodeIcon.CLASS else NavigationNodeIcon.CLASS_KT + } + is DFunction -> NavigationNodeIcon.FUNCTION + is DProperty -> { + val isVar = documentable.extra[IsVar] != null + if (isVar) NavigationNodeIcon.VAR else NavigationNodeIcon.VAL + } + is DInterface -> if (isJava) NavigationNodeIcon.INTERFACE else NavigationNodeIcon.INTERFACE_KT + is DEnum, + is DEnumEntry -> if (isJava) NavigationNodeIcon.ENUM_CLASS else NavigationNodeIcon.ENUM_CLASS_KT + is DAnnotation -> { + if (isJava) NavigationNodeIcon.ANNOTATION_CLASS else NavigationNodeIcon.ANNOTATION_CLASS_KT + } + is DObject -> NavigationNodeIcon.OBJECT + else -> null + } + } else { + null + } + } + + private fun Documentable.hasAnyJavaSources(): Boolean { + val withSources = this as? WithSources ?: return false + return this.sourceSets.any { withSources.documentableLanguage(it) == DocumentableLanguage.JAVA } + } + + private fun DClass.isAbstract(): Boolean { + return modifier.values.all { it is KotlinModifier.Abstract || it is JavaModifier.Abstract } + } + + private fun ContentPage.navigableChildren(): List<NavigationNode> { + return if (this !is ClasslikePageNode) { + children + .filterIsInstance<ContentPage>() + .map { visit(it) } + .sortedBy { it.name.toLowerCase() } + } else if (documentables.any { it is DEnum }) { + // no sorting for enum entries, should be the same as in source code + children + .filter { child -> child is WithDocumentables && child.documentables.any { it is DEnumEntry } } + .map { visit(it as ContentPage) } + } else { + emptyList() + } + } +} diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt index e0b20f01..e5183699 100644 --- a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt +++ b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt @@ -7,13 +7,15 @@ import org.jetbrains.dokka.base.templating.AddToNavigationCommand import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.DisplaySourceSet import org.jetbrains.dokka.model.WithChildren -import org.jetbrains.dokka.pages.PageNode -import org.jetbrains.dokka.pages.RendererSpecificPage -import org.jetbrains.dokka.pages.RenderingStrategy +import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext -class NavigationPage(val root: NavigationNode, val moduleName: String, val context: DokkaContext) : - RendererSpecificPage { +class NavigationPage( + val root: NavigationNode, + val moduleName: String, + val context: DokkaContext +) : RendererSpecificPage { + override val name = "navigation" override val children = emptyList<PageNode>() @@ -46,22 +48,69 @@ class NavigationPage(val root: NavigationNode, val moduleName: String, val conte span("navButtonContent") } } - buildLink(node.dri, node.sourceSets.toList()) { buildBreakableText(node.name) } + buildLink(node.dri, node.sourceSets.toList()) { + // special condition for Enums as it has children enum entries in navigation + val withIcon = node.icon != null && (node.children.isEmpty() || node.isEnum()) + if (withIcon) { + // in case link text is so long that it needs to have word breaks, + // and it stretches to two or more lines, make sure the icon + // is always on the left in the grid and is not wrapped with text + span("nav-link-grid") { + span("nav-link-child ${node.icon?.style()}") + span("nav-link-child") { + buildBreakableText(node.name) + } + } + } else { + buildBreakableText(node.name) + } + } } node.children.withIndex().forEach { (n, p) -> visit(p, "$navId-$n", renderer) } } } + + private fun NavigationNode.isEnum(): Boolean { + return icon == NavigationNodeIcon.ENUM_CLASS || icon == NavigationNodeIcon.ENUM_CLASS_KT + } } data class NavigationNode( val name: String, val dri: DRI, val sourceSets: Set<DisplaySourceSet>, + val icon: NavigationNodeIcon?, override val children: List<NavigationNode> ) : WithChildren<NavigationNode> +/** + * [CLASS] represents a neutral (a.k.a Java-style) icon, + * whereas [CLASS_KT] should be Kotlin-styled + */ +enum class NavigationNodeIcon( + private val cssClass: String +) { + CLASS("class"), + CLASS_KT("class-kt"), + ABSTRACT_CLASS("abstract-class"), + ABSTRACT_CLASS_KT("abstract-class-kt"), + ENUM_CLASS("enum-class"), + ENUM_CLASS_KT("enum-class-kt"), + ANNOTATION_CLASS("annotation-class"), + ANNOTATION_CLASS_KT("annotation-class-kt"), + INTERFACE("interface"), + INTERFACE_KT("interface-kt"), + FUNCTION("function"), + EXCEPTION("exception-class"), + OBJECT("object"), + VAL("val"), + VAR("var"); + + internal fun style(): String = "nav-icon $cssClass" +} + fun NavigationPage.transform(block: (NavigationNode) -> NavigationNode) = NavigationPage(root.transform(block), moduleName, context) fun NavigationNode.transform(block: (NavigationNode) -> NavigationNode) = - run(block).let { NavigationNode(it.name, it.dri, it.sourceSets, it.children.map(block)) } + run(block).let { NavigationNode(it.name, it.dri, it.sourceSets, it.icon, it.children.map(block)) } diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt index 4527baa7..2de6f2b7 100644 --- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt +++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt @@ -2,60 +2,16 @@ package org.jetbrains.dokka.base.renderers.html import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.DokkaBaseConfiguration -import org.jetbrains.dokka.base.renderers.sourceSets import org.jetbrains.dokka.base.templating.AddToSourcesetDependencies import org.jetbrains.dokka.base.templating.toJsonString -import org.jetbrains.dokka.model.DEnum -import org.jetbrains.dokka.model.DEnumEntry -import org.jetbrains.dokka.model.DFunction -import org.jetbrains.dokka.model.withDescendants -import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.pages.RendererSpecificResourcePage +import org.jetbrains.dokka.pages.RenderingStrategy +import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.configuration import org.jetbrains.dokka.transformers.pages.PageTransformer -abstract class NavigationDataProvider { - open fun navigableChildren(input: RootPageNode): NavigationNode = input.withDescendants() - .first { it is ModulePage || it is MultimoduleRootPage }.let { visit(it as ContentPage) } - - open fun visit(page: ContentPage): NavigationNode = - NavigationNode( - name = page.displayableName, - dri = page.dri.first(), - sourceSets = page.sourceSets(), - children = page.navigableChildren() - ) - - private fun ContentPage.navigableChildren(): List<NavigationNode> { - return if (this !is ClasslikePageNode) { - children - .filterIsInstance<ContentPage>() - .map { visit(it) } - .sortedBy { it.name.toLowerCase() } - } else if (documentables.any { it is DEnum }) { - // no sorting for enum entries, should be the same as in source code - children - .filter { child -> child is WithDocumentables && child.documentables.any { it is DEnumEntry } } - .map { visit(it as ContentPage) } - } else { - emptyList() - } - } - - /** - * Parenthesis is applied in 1 case: - * - page only contains functions (therefore documentable from this page is [DFunction]) - */ - private val ContentPage.displayableName: String - get() = if (this is WithDocumentables && documentables.all { it is DFunction }) { - "$name()" - } else { - name - } -} - open class NavigationPageInstaller(val context: DokkaContext) : NavigationDataProvider(), PageTransformer { - override fun invoke(input: RootPageNode): RootPageNode = input.modified( children = input.children + NavigationPage( @@ -138,6 +94,23 @@ object AssetsInstaller : PageTransformer { "images/copy-icon.svg", "images/copy-successful-icon.svg", "images/theme-toggle.svg", + + // navigation icons + "images/nav-icons/abstract-class.svg", + "images/nav-icons/abstract-class-kotlin.svg", + "images/nav-icons/annotation.svg", + "images/nav-icons/annotation-kotlin.svg", + "images/nav-icons/class.svg", + "images/nav-icons/class-kotlin.svg", + "images/nav-icons/enum.svg", + "images/nav-icons/enum-kotlin.svg", + "images/nav-icons/exception-class.svg", + "images/nav-icons/field-value.svg", + "images/nav-icons/field-variable.svg", + "images/nav-icons/function.svg", + "images/nav-icons/interface.svg", + "images/nav-icons/interface-kotlin.svg", + "images/nav-icons/object.svg", ) override fun invoke(input: RootPageNode) = input.modified( diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/abstract-class-kotlin.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/abstract-class-kotlin.svg new file mode 100644 index 00000000..a2069b8f --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/abstract-class-kotlin.svg @@ -0,0 +1,22 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g id="abstractClassKotlin"> +<path id="Fill 1" fill-rule="evenodd" clip-rule="evenodd" d="M3 3.1055C1.764 4.3685 1 6.0935 1 8.0005C1 9.9065 1.764 11.6315 3 12.8945V3.1055Z" fill="#9AA7B0" fill-opacity="0.8"/> +<path id="Combined Shape" fill-rule="evenodd" clip-rule="evenodd" d="M13 8V3.1055C14.2359 4.36739 14.9999 6.0932 15 8H13Z" fill="#9AA7B0" fill-opacity="0.8"/> +<g id="idea/community/platform/icons/src/nodes/class"> +<mask id="mask0" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="4" y="1" width="8" height="14"> +<path id="Mask" d="M4 1H12V8H8V15H4V1Z" fill="white"/> +</mask> +<g mask="url(#mask0)"> +<g id="class"> +<path id="Fill 1_2" fill-rule="evenodd" clip-rule="evenodd" d="M15 8C15 11.866 11.866 15 8 15C4.134 15 1 11.866 1 8C1 4.134 4.134 1 8 1C11.866 1 15 4.134 15 8Z" fill="#40B6E0" fill-opacity="0.6"/> +<g id="⌘/alphabet/nodes/c"> +<path id="⌘/alphabet/nodes/c_2" fill-rule="evenodd" clip-rule="evenodd" d="M10 9.28253C9.53001 9.74153 9.02801 9.978 8.10001 10C7.06101 10.022 6.00001 9.2794 6.00001 8.0004C6.00001 6.7124 6.97101 6 8.10001 6C9.37251 6 9.90001 6.55426 9.90001 6.55426L10.5162 5.83673C9.82941 5.27017 9.28828 5.0004 8.09821 5.0004C6.34021 5.0004 5.00021 6.3584 5.00021 8.0004C5.00021 9.6824 6.36421 11.0004 8.00221 11.0004C9.29286 11.0004 10.0232 10.5934 10.6162 9.9814L10 9.28253Z" fill="#231F20" fill-opacity="0.7"/> +</g> +</g> +</g> +</g> +<g id="⌘/modifier/kotlin"> +<path id="⌘/modifier/kotlin_2" d="M16 16H9V9H16L12.4 12.4L16 16Z" fill="#B99BF8"/> +</g> +</g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/abstract-class.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/abstract-class.svg new file mode 100644 index 00000000..60182030 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/abstract-class.svg @@ -0,0 +1,20 @@ +<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16"> + <defs> + <rect id="abstractclass-a" width="8" height="14"/> + </defs> + <g fill="none" fill-rule="evenodd"> + <path fill="#9AA7B0" fill-opacity=".8" d="M3 3.1055C1.764 4.3685 1 6.0935 1 8.0005 1 9.9065 1.764 11.6315 3 12.8945L3 3.1055zM13 3.1055L13 12.8945C14.236 11.6315 15 9.9065 15 8.0005 15 6.0935 14.236 4.3675 13 3.1055"/> + <g transform="translate(4 1)"> + <mask id="abstractclass-b" fill="#fff"> + <use xlink:href="#abstractclass-a"/> + </mask> + <g mask="url(#abstractclass-b)"> + <g transform="translate(-4 -1)"> + <path fill="#40B6E0" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/> + <path fill="#231F20" fill-opacity=".7" d="M5,4.28253174 C4.53,4.74153174 4.028,4.978 3.1,5 C2.061,5.022 1,4.2794 1,3.0004 C1,1.7124 1.971,1 3.1,1 C3.94833171,1 4.54833171,1.18475342 4.9,1.55426025 L5.5162,0.836730957 C4.8293999,0.270175195 4.28826904,0.0004 3.0982,0.0004 C1.3402,0.0004 0.0002,1.3584 0.0002,3.0004 C0.0002,4.6824 1.3642,6.0004 3.0022,6.0004 C4.29284668,6.0004 5.0232,5.5934 5.6162,4.9814 C5.2054,4.51548783 5,4.28253174 5,4.28253174 Z" transform="translate(5 5)"/> + </g> + </g> + </g> + </g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/annotation-kotlin.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/annotation-kotlin.svg new file mode 100644 index 00000000..932f1d3d --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/annotation-kotlin.svg @@ -0,0 +1,9 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g id="annotationKotlin"> +<g id="⌘/modifier/kotlin"> +<path id="⌘/modifier/kotlin_2" d="M16 16H9V9H16L12.4 12.4L16 16Z" fill="#B99BF8"/> +</g> +<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M8 15C4.134 15 1 11.866 1 8C1 4.134 4.134 1 8 1C11.866 1 15 4.134 15 8H8V15Z" fill="#62B543" fill-opacity="0.6"/> +<path id="Vector_2" fill-rule="evenodd" clip-rule="evenodd" d="M8.00001 9.32546V9.99479C7.96296 9.99826 7.92599 10 7.88911 10C7.07966 10 6.00011 9.9211 6.00011 8.0001C6.00011 6.32043 7.45594 6.0001 8.00011 6.0001C8.15311 6.0001 9.74511 6.0551 9.82411 6.0791L9.75124 8H8.76699C8.7695 7.96484 8.77154 7.9292 8.77311 7.8931L8.84211 6.6991L8.80011 6.6891C8.68511 6.6621 8.59811 6.6481 8.50011 6.6371C8.40211 6.6271 8.30411 6.6221 8.20211 6.6221C7.97811 6.6221 7.78611 6.6681 7.62811 6.7611C7.47311 6.8511 7.34511 6.9741 7.24611 7.1241C7.15111 7.2721 7.08111 7.4411 7.03911 7.6261C6.99711 7.8091 6.97611 7.9961 6.97611 8.1841C6.97611 8.5861 7.04911 8.8721 7.19711 9.0581C7.34911 9.2481 7.55411 9.3451 7.80511 9.3451C7.87359 9.3451 7.93863 9.33855 8.00001 9.32546ZM11.9819 8H11.0207C11.0512 7.78917 11.0601 7.61595 11.0601 7.5471C11.0601 4.90741 8.70811 4.7451 8.31611 4.7451C7.77111 4.7451 4.94355 4.85089 4.94355 8.0006C4.94355 8.58402 4.94355 11.2461 7.88911 11.2461C7.91058 11.2461 7.94864 11.2438 8.00001 11.2394V11.9994C7.9664 11.9999 7.93243 12.0001 7.89811 12.0001C7.15577 12.0001 4.00211 12.0001 4.00211 8.0006C4.00211 4.0011 7.66743 4.0011 8.31611 4.0011C8.65106 4.0011 12.0001 4.08643 12.0001 7.5571C12.0001 7.71468 11.9938 7.86209 11.9819 8Z" fill="#231F20" fill-opacity="0.7"/> +</g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/annotation.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/annotation.svg new file mode 100644 index 00000000..b80c54b4 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/annotation.svg @@ -0,0 +1,7 @@ +<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. --> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <g fill="none" fill-rule="evenodd"> + <path fill="#62B543" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/> + <path fill="#231F20" fill-opacity=".7" d="M3.6281,2.7611 C3.4731,2.8511 3.3451,2.9741 3.2461,3.1241 C3.1511,3.2721 3.0811,3.4411 3.0391,3.6261 C2.9971,3.8091 2.9761,3.9961 2.9761,4.1841 C2.9761,4.5861 3.0491,4.8721 3.1971,5.0581 C3.3491,5.2481 3.5541,5.3451 3.8051,5.3451 C3.9701,5.3451 4.1151,5.3071 4.2371,5.2311 C4.3571,5.1581 4.4571,5.0531 4.5331,4.9201 C4.6061,4.7931 4.6631,4.6401 4.7011,4.4641 C4.7391,4.2941 4.7641,4.1011 4.7731,3.8931 L4.8421,2.6991 L4.8001,2.6891 C4.6851,2.6621 4.5981,2.6481 4.5001,2.6371 C4.4021,2.6271 4.3041,2.6221 4.2021,2.6221 C3.9781,2.6221 3.7861,2.6681 3.6281,2.7611 Z M0.0021,4.0006 C0.0021,0.0011 3.66741943,0.0011 4.3161,0.0011 C4.65105644,0.0011 8.0001,0.0864290039 8.0001,3.5571 C8.0001,6.0091 6.4751,6 6.1701,6 C5.67331784,5.97 5.31431784,5.7737 5.0931,5.4111 C4.68260397,5.8037 4.28127064,6 3.8891,6 C3.0796519,6 2.0001,5.9211 2.0001,4.0001 C2.0001,2.32043457 3.45593262,2.0001 4.0001,2.0001 C4.1531,2.0001 5.7451,2.0551 5.8241,2.0791 L5.7441,4.1881 C5.6361,4.89276667 5.7991,5.2451 6.2331,5.2451 C6.95605469,5.2451 7.0601,3.7831 7.0601,3.5471 C7.0601,0.907409668 4.7081,0.7451 4.3161,0.7451 C3.7711,0.7451 0.94354248,0.850891113 0.94354248,4.0006 C0.94354248,4.58402311 0.94354248,7.2461 3.8891,7.2461 C4.0901,7.2461 5.7441,7.04302979 6.1621,6.8281 L6.1621,7.5781 C5.8551,7.7031 5.0931,8.0001 3.8981,8.0001 C3.15576172,8.0001 0.0021,8.0001 0.0021,4.0006 Z" transform="translate(4 4)"/> + </g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/class-kotlin.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/class-kotlin.svg new file mode 100644 index 00000000..46a21f65 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/class-kotlin.svg @@ -0,0 +1,9 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g id="classKotlin"> +<g id="⌘/modifier/kotlin"> +<path id="⌘/modifier/kotlin_2" d="M16 16H9V9H16L12.4 12.4L16 16Z" fill="#B99BF8"/> +</g> +<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M8 15C4.134 15 1 11.866 1 8C1 4.134 4.134 1 8 1C11.866 1 15 4.134 15 8H8V15Z" fill="#40B6E0" fill-opacity="0.6"/> +<path id="Vector_2" fill-rule="evenodd" clip-rule="evenodd" d="M8.00001 11.0004C6.36299 10.9992 5.00021 9.68165 5.00021 8.0004C5.00021 6.3584 6.34021 5.0004 8.09821 5.0004C9.28828 5.0004 9.82941 5.27018 10.5162 5.83673L9.90001 6.55426C9.54835 6.18475 8.94835 6 8.10001 6C6.97101 6 6.00001 6.7124 6.00001 8.0004C6.00001 9.23838 6.99405 9.97382 8.00001 9.99976V11.0004V11.0004Z" fill="#231F20" fill-opacity="0.7"/> +</g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/class.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/class.svg new file mode 100644 index 00000000..3f1ad167 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/class.svg @@ -0,0 +1,7 @@ +<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. --> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <g fill="none" fill-rule="evenodd"> + <path fill="#40B6E0" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/> + <path fill="#231F20" fill-opacity=".7" d="M5,4.28253174 C4.53,4.74153174 4.028,4.978 3.1,5 C2.061,5.022 1,4.2794 1,3.0004 C1,1.7124 1.971,1 3.1,1 C3.94833171,1 4.54833171,1.18475342 4.9,1.55426025 L5.5162,0.836730957 C4.8293999,0.270175195 4.28826904,0.0004 3.0982,0.0004 C1.3402,0.0004 0.0002,1.3584 0.0002,3.0004 C0.0002,4.6824 1.3642,6.0004 3.0022,6.0004 C4.29284668,6.0004 5.0232,5.5934 5.6162,4.9814 C5.2054,4.51548783 5,4.28253174 5,4.28253174 Z" transform="translate(5 5)"/> + </g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/enum-kotlin.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/enum-kotlin.svg new file mode 100644 index 00000000..4a854596 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/enum-kotlin.svg @@ -0,0 +1,9 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g id="enumKotlin"> +<g id="⌘/modifier/kotlin"> +<path id="⌘/modifier/kotlin_2" d="M16 16H9V9H16L12.4 12.4L16 16Z" fill="#B99BF8"/> +</g> +<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M8 15C4.134 15 1 11.866 1 8C1 4.134 4.134 1 8 1C11.866 1 15 4.134 15 8H8V15Z" fill="#40B6E0" fill-opacity="0.6"/> +<path id="Vector_2" fill-rule="evenodd" clip-rule="evenodd" d="M8 11H6V5H10V6H7V7H9V8H7V10H8V11Z" fill="#231F20" fill-opacity="0.7"/> +</g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/enum.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/enum.svg new file mode 100644 index 00000000..fa7f2476 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/enum.svg @@ -0,0 +1,7 @@ +<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. --> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <g fill="none" fill-rule="evenodd"> + <path fill="#40B6E0" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/> + <polygon fill="#231F20" fill-opacity=".7" points="4 6 0 6 0 0 4 0 4 1 1 1 1 2 3.5 2 3.5 3 1 3 1 5 4 5" transform="translate(6 5)"/> + </g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/exception-class.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/exception-class.svg new file mode 100644 index 00000000..c0b2bdeb --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/exception-class.svg @@ -0,0 +1,7 @@ +<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. --> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <g fill="none" fill-rule="evenodd"> + <path fill="#40B6E0" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/> + <polygon fill="#231F20" fill-opacity=".7" points="7 13 9 9 4 9 9 3 8 7 12 7"/> + </g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/field-value.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/field-value.svg new file mode 100644 index 00000000..20449c94 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/field-value.svg @@ -0,0 +1,6 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <g fill="none" fill-rule="evenodd"> + <rect width="14" height="14" x="1" y="1" fill="#B99BF8" fill-opacity=".6" rx="3"/> + <path fill="#231F20" fill-opacity=".7" d="M2.2939,6 L-0.0001,0 L1.2,0 C2.3886,3.13933333 2.98856667,4.73933333 2.9999,4.8 L4.8,0 L5.9999,0 L3.7059,6 L2.2939,6 Z" transform="translate(5 5)"/> + </g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/field-variable.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/field-variable.svg new file mode 100644 index 00000000..3b074500 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/field-variable.svg @@ -0,0 +1,6 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <g fill="none" fill-rule="evenodd"> + <path fill="#B99BF8" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/> + <path fill="#231F20" fill-opacity=".7" d="M2.2939,6 L-0.0001,0 L1.2,0 C2.3886,3.13933333 2.98856667,4.73933333 2.9999,4.8 L4.8,0 L5.9999,0 L3.7059,6 L2.2939,6 Z" transform="translate(5 5)"/> + </g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/function.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/function.svg new file mode 100644 index 00000000..f0da64a0 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/function.svg @@ -0,0 +1,7 @@ +<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. --> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <g fill="none" fill-rule="evenodd"> + <path fill="#F98B9E" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/> + <path fill="#231F20" fill-opacity=".7" d="M1,8 L2,8 L2,4 L3.5,4 L3.5,3 L2,3 C1.99687783,2.36169171 1.99509925,2.02835838 1.99466424,2 C1.98704681,1.50341351 2.13289549,1.0728225 2.43221029,0.972167969 C2.91964141,0.808253079 3.56884985,1.02114795 3.68984985,1.06414795 L3.98519897,0.226043701 C3.90948298,0.198825534 3.4559021,0 2.81140137,0 C2.16690063,1.40512602e-16 1.81677246,0.0614013672 1.4818929,0.388793945 C1.16513106,0.698473875 1.01614114,1.22015248 1.00124609,2 C1.00039414,2.04460465 0.999980878,2.95274463 1,3 C1.00000736,3.01819872 0.666674031,3.01819872 0,3 L0,3.972 L1,3.972 L1,8 Z" transform="translate(6 4)"/> + </g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/interface-kotlin.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/interface-kotlin.svg new file mode 100644 index 00000000..bf07a148 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/interface-kotlin.svg @@ -0,0 +1,9 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g id="interfaceKotlin"> +<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M8 15C4.134 15 1 11.866 1 8C1 4.134 4.134 1 8 1C11.866 1 15 4.134 15 8H8V15Z" fill="#62B543" fill-opacity="0.6"/> +<path id="Vector_2" opacity="0.7" d="M8 11H6V10.0065L7.4 10V6H6V5H10V6H8.6V8H8V11Z" fill="#231F20"/> +<g id="⌘/modifier/kotlin"> +<path id="⌘/modifier/kotlin_2" d="M16 16H9V9H16L12.4 12.4L16 16Z" fill="#B99BF8"/> +</g> +</g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/interface.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/interface.svg new file mode 100644 index 00000000..32063ba2 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/interface.svg @@ -0,0 +1,7 @@ +<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. --> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <g fill="none" fill-rule="evenodd"> + <path fill="#62B543" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/> + <polygon fill="#231F20" fill-rule="nonzero" points="8.6 10 8.6 6 10 6 10 5 6 5 6 6 7.4 6 7.4 10 6 10.007 6 11 10 11 10 10" opacity=".7"/> + </g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/object.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/object.svg new file mode 100644 index 00000000..9f427de4 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/nav-icons/object.svg @@ -0,0 +1,9 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g id="objectKotlin"> +<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M8 15C4.134 15 1 11.866 1 8C1 4.134 4.134 1 8 1C11.866 1 15 4.134 15 8H8V15Z" fill="#F4AF3D" fill-opacity="0.6"/> +<path id="Vector_2" fill-rule="evenodd" clip-rule="evenodd" d="M11 8H9.94262C9.94262 6.87293 9.13115 5.94475 7.9918 5.94475C6.85246 5.94475 6.05738 6.85635 6.05738 7.98343V8C6.05738 9.12437 6.86496 10.0508 8 10.0552V11C7.99727 11 7.99454 11 7.9918 11C6.22951 11 5 9.64917 5 8.01657V8C5 6.3674 6.2459 5 8.0082 5C9.77049 5 11 6.35083 11 7.98343V8Z" fill="#231F20" fill-opacity="0.7"/> +<g id="⌘/modifier/kotlin"> +<path id="⌘/modifier/kotlin_2" d="M16 16H9V9H16L12.4 12.4L16 16Z" fill="#B99BF8"/> +</g> +</g> +</svg> diff --git a/plugins/base/src/main/resources/dokka/scripts/navigation-loader.js b/plugins/base/src/main/resources/dokka/scripts/navigation-loader.js index 9c824b91..92464911 100644 --- a/plugins/base/src/main/resources/dokka/scripts/navigation-loader.js +++ b/plugins/base/src/main/resources/dokka/scripts/navigation-loader.js @@ -59,7 +59,10 @@ scrollNavigationToSelectedElement = () => { return } - let isPackageElement = selectedElement.children.length > 1 + let hasIcon = selectedElement.querySelectorAll(":scope > div.overview span.nav-icon").length > 0 + + // for instance enums also have children and are expandable, but are not package/module elements + let isPackageElement = selectedElement.children.length > 1 && !hasIcon if (isPackageElement) { // if package is selected or linked, it makes sense to align it to top // so that you can see all the members it contains diff --git a/plugins/base/src/main/resources/dokka/styles/style.css b/plugins/base/src/main/resources/dokka/styles/style.css index e32ec063..6a9d2a87 100644 --- a/plugins/base/src/main/resources/dokka/styles/style.css +++ b/plugins/base/src/main/resources/dokka/styles/style.css @@ -271,13 +271,13 @@ p.paragraph:first-child, #main { width: 100%; - max-width: calc(100% - 280px); + max-width: calc(100% - 300px); display: flex; flex-direction: column; } #leftColumn { - width: 280px; + width: 300px; border-right: 1px solid var(--border-color); display: flex; flex-direction: column; @@ -448,7 +448,7 @@ code.paragraph { box-sizing: border-box; content: ''; top: 0; - width: 280px; + width: 300px; right: 0; bottom: 0; position: absolute; @@ -502,6 +502,78 @@ code.paragraph { display: none; } +.overview .nav-link-grid { + display: grid; + grid-template-columns: 16px auto; /* first is the icon, then name */ + grid-gap: 6px; + align-items: center; +} + +.nav-icon { + width: 16px; + height: 16px; +} + +.nav-icon.class::before { + content: url("../images/nav-icons/class.svg"); +} + +.nav-icon.class-kt::before { + content: url("../images/nav-icons/class-kotlin.svg"); +} + +.nav-icon.function::before { + content: url("../images/nav-icons/function.svg"); +} + +.nav-icon.enum-class::before { + content: url("../images/nav-icons/enum.svg"); +} + +.nav-icon.enum-class-kt::before { + content: url("../images/nav-icons/enum-kotlin.svg"); +} + +.nav-icon.annotation-class::before { + content: url("../images/nav-icons/annotation.svg"); +} + +.nav-icon.annotation-class-kt::before { + content: url("../images/nav-icons/annotation-kotlin.svg"); +} + +.nav-icon.abstract-class::before { + content: url("../images/nav-icons/abstract-class.svg"); +} + +.nav-icon.abstract-class-kt::before { + content: url("../images/nav-icons/abstract-class-kotlin.svg"); +} + +.nav-icon.exception-class::before { + content: url("../images/nav-icons/exception-class.svg"); +} + +.nav-icon.interface::before { + content: url("../images/nav-icons/interface.svg"); +} + +.nav-icon.interface-kt::before { + content: url("../images/nav-icons/interface-kotlin.svg"); +} + +.nav-icon.object::before { + content: url("../images/nav-icons/object.svg"); +} + +.nav-icon.val::before { + content: url("../images/nav-icons/field-value.svg"); +} + +.nav-icon.var::before { + content: url("../images/nav-icons/field-variable.svg"); +} + .filtered > a, .filtered > .navButton { display: none; } @@ -1118,7 +1190,7 @@ div.runnablesample { #leftColumn { position: fixed; - margin-left: -280px; + margin-left: -300px; transition: margin .2s ease-out; z-index: 4; background: white; @@ -1147,7 +1219,7 @@ div.runnablesample { } #leftColumn.open ~ #main #leftToggler { - margin-left: 280px; + margin-left: 300px; } .icon-toggler::before { diff --git a/plugins/base/src/test/kotlin/enums/JavaEnumTest.kt b/plugins/base/src/test/kotlin/enums/JavaEnumTest.kt deleted file mode 100644 index 369fbe79..00000000 --- a/plugins/base/src/test/kotlin/enums/JavaEnumTest.kt +++ /dev/null @@ -1,66 +0,0 @@ -package enums - -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.dokka.model.DEnum -import org.jetbrains.dokka.model.ObviousMember -import org.junit.jupiter.api.Test -import utils.TestOutputWriterPlugin -import kotlin.test.assertEquals -import kotlin.test.assertNotNull - -class JavaEnumTest : BaseAbstractTest() { - - private val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - @Test - fun `should mark synthetic functions generated for Kotlin as obvious`() { - val writerPlugin = TestOutputWriterPlugin() - testInline( - """ - |/src/main/java/basic/JavaEnum.java - |package testpackage - | - |public enum JavaEnum { - | ONE, TWO - |} - """.trimMargin(), - configuration, - pluginOverrides = listOf(writerPlugin) - ) { - documentablesCreationStage = { modules -> - val pckg = modules.flatMap { it.packages }.single { it.packageName == "testpackage" } - val enum = pckg.children.single { it is DEnum } as DEnum - - // there's two with the same name, one inherited from - // java.lang.Enum and one is synthetic for Kotlin interop - enum.functions.filter { it.name == "valueOf" }.let { valueOfMethods -> - assertEquals(2, valueOfMethods.size) - - val valueOfFromKotlin = valueOfMethods[0] - assertEquals( - "testpackage/JavaEnum/valueOf/#java.lang.String/PointingToDeclaration/", - valueOfFromKotlin.dri.toString() - ) - assertNotNull(valueOfFromKotlin.extra[ObviousMember]) - - val valueOfFromJava = valueOfMethods[1] - assertEquals( - "java.lang/Enum/valueOf/#java.lang.Class<T>#java.lang.String/PointingToDeclaration/", - valueOfFromJava.dri.toString() - ) - assertNotNull(valueOfFromJava.extra[ObviousMember]) - } - - val valuesMethod = enum.functions.single { it.name == "values" } - assertEquals("testpackage/JavaEnum/values/#/PointingToDeclaration/", valuesMethod.dri.toString()) - assertNotNull(valuesMethod.extra[ObviousMember]) - } - } - } -} diff --git a/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt b/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt index 6a59a57e..939163ca 100644 --- a/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt +++ b/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt @@ -2,14 +2,25 @@ package enums import org.jetbrains.dokka.SourceLinkDefinitionImpl import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.model.DEnum +import org.jetbrains.dokka.model.ObviousMember import org.junit.jupiter.api.Test import signatures.renderedContent import utils.TestOutputWriterPlugin import java.net.URL import kotlin.test.assertEquals +import kotlin.test.assertNotNull class JavaEnumsTest : BaseAbstractTest() { + private val basicConfiguration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + // Shouldn't try to give source links to synthetic methods (values, valueOf) if any are present // https://github.com/Kotlin/dokka/issues/2544 @Test @@ -57,4 +68,50 @@ class JavaEnumsTest : BaseAbstractTest() { } } } + + @Test + fun `should mark synthetic functions generated for Kotlin as obvious`() { + val writerPlugin = TestOutputWriterPlugin() + testInline( + """ + |/src/main/java/basic/JavaEnum.java + |package testpackage + | + |public enum JavaEnum { + | ONE, TWO + |} + """.trimMargin(), + basicConfiguration, + pluginOverrides = listOf(writerPlugin) + ) { + documentablesCreationStage = { modules -> + val pckg = modules.flatMap { it.packages }.single { it.packageName == "testpackage" } + val enum = pckg.children.single { it is DEnum } as DEnum + + // there's two with the same name, one inherited from + // java.lang.Enum and one is synthetic for Kotlin interop + enum.functions.filter { it.name == "valueOf" }.let { valueOfMethods -> + assertEquals(2, valueOfMethods.size) + + val valueOfFromKotlin = valueOfMethods[0] + assertEquals( + "testpackage/JavaEnum/valueOf/#java.lang.String/PointingToDeclaration/", + valueOfFromKotlin.dri.toString() + ) + assertNotNull(valueOfFromKotlin.extra[ObviousMember]) + + val valueOfFromJava = valueOfMethods[1] + assertEquals( + "java.lang/Enum/valueOf/#java.lang.Class<T>#java.lang.String/PointingToDeclaration/", + valueOfFromJava.dri.toString() + ) + assertNotNull(valueOfFromJava.extra[ObviousMember]) + } + + val valuesMethod = enum.functions.single { it.name == "values" } + assertEquals("testpackage/JavaEnum/values/#/PointingToDeclaration/", valuesMethod.dri.toString()) + assertNotNull(valuesMethod.extra[ObviousMember]) + } + } + } } diff --git a/plugins/base/src/test/kotlin/enums/KotlinEnumTest.kt b/plugins/base/src/test/kotlin/enums/KotlinEnumTest.kt deleted file mode 100644 index 83430869..00000000 --- a/plugins/base/src/test/kotlin/enums/KotlinEnumTest.kt +++ /dev/null @@ -1,408 +0,0 @@ -package enums - -import matchers.content.* -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.dokka.model.* -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance -import org.jsoup.Jsoup -import org.jsoup.nodes.Element -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test -import signatures.renderedContent -import utils.TestOutputWriter -import utils.TestOutputWriterPlugin - -class KotlinEnumTest : BaseAbstractTest() { - - @Test - fun `should preserve enum source ordering for documentables`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - val writerPlugin = TestOutputWriterPlugin() - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | ZERO, - | ONE, - | TWO, - | THREE, - | FOUR, - | FIVE, - | SIX, - | SEVEN, - | EIGHT, - | NINE - |} - """.trimMargin(), - configuration, - pluginOverrides = listOf(writerPlugin) - ) { - documentablesTransformationStage = { module -> - val testPackage = module.packages[0] - assertEquals("testpackage", testPackage.name) - - val testEnum = testPackage.classlikes[0] as DEnum - assertEquals("TestEnum", testEnum.name) - - val enumEntries = testEnum.entries - assertEquals(10, enumEntries.count()) - - assertEquals("ZERO", enumEntries[0].name) - assertEquals("ONE", enumEntries[1].name) - assertEquals("TWO", enumEntries[2].name) - assertEquals("THREE", enumEntries[3].name) - assertEquals("FOUR", enumEntries[4].name) - assertEquals("FIVE", enumEntries[5].name) - assertEquals("SIX", enumEntries[6].name) - assertEquals("SEVEN", enumEntries[7].name) - assertEquals("EIGHT", enumEntries[8].name) - assertEquals("NINE", enumEntries[9].name) - } - } - } - - @Test - fun `should preserve enum source ordering for generated pages`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - val writerPlugin = TestOutputWriterPlugin() - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | ZERO, - | ONE, - | TWO, - | THREE, - | FOUR, - | FIVE, - | SIX, - | SEVEN, - | EIGHT, - | NINE - |} - """.trimMargin(), - configuration, - pluginOverrides = listOf(writerPlugin) - ) { - pagesGenerationStage = { rootPage -> - val packagePage = rootPage.children[0] - assertEquals("testpackage", packagePage.name) - - val testEnumNode = packagePage.children[0] - assertEquals("TestEnum", testEnumNode.name) - - val enumEntries = testEnumNode.children - assertEquals(10, enumEntries.size) - - assertEquals("ZERO", enumEntries[0].name) - assertEquals("ONE", enumEntries[1].name) - assertEquals("TWO", enumEntries[2].name) - assertEquals("THREE", enumEntries[3].name) - assertEquals("FOUR", enumEntries[4].name) - assertEquals("FIVE", enumEntries[5].name) - assertEquals("SIX", enumEntries[6].name) - assertEquals("SEVEN", enumEntries[7].name) - assertEquals("EIGHT", enumEntries[8].name) - assertEquals("NINE", enumEntries[9].name) - } - } - } - - @Test - fun `should preserve enum source ordering for rendered entries`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - val writerPlugin = TestOutputWriterPlugin() - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | ZERO, - | ONE, - | TWO, - | THREE, - | FOUR, - | FIVE, - | SIX, - | SEVEN, - | EIGHT, - | NINE - |} - """.trimMargin(), - configuration, - pluginOverrides = listOf(writerPlugin) - ) { - renderingStage = { _, _ -> - val enumEntriesOnPage = writerPlugin.writer.renderedContent("root/testpackage/-test-enum/index.html") - .select("div.table[data-togglable=Entries]") - .select("div.table-row") - .select("div.keyValue") - .select("div.title") - .select("a") - - val enumEntries = enumEntriesOnPage.map { it.text() } - assertEquals(10, enumEntries.size) - - assertEquals("ZERO", enumEntries[0]) - assertEquals("ONE", enumEntries[1]) - assertEquals("TWO", enumEntries[2]) - assertEquals("THREE", enumEntries[3]) - assertEquals("FOUR", enumEntries[4]) - assertEquals("FIVE", enumEntries[5]) - assertEquals("SIX", enumEntries[6]) - assertEquals("SEVEN", enumEntries[7]) - assertEquals("EIGHT", enumEntries[8]) - assertEquals("NINE", enumEntries[9]) - } - } - } - - @Test - fun `should preserve enum source ordering for navigation menu`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - val writerPlugin = TestOutputWriterPlugin() - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | ZERO, - | ONE, - | TWO, - | THREE, - | FOUR, - | FIVE, - | SIX, - | SEVEN, - | EIGHT, - | NINE - |} - """.trimMargin(), - configuration, - pluginOverrides = listOf(writerPlugin) - ) { - renderingStage = { _, _ -> - val sideMenu = writerPlugin.writer.navigationHtml().select("div.sideMenuPart") - - assertEquals("ZERO", sideMenu.select("#root-nav-submenu-0-0-0").text()) - assertEquals("ONE", sideMenu.select("#root-nav-submenu-0-0-1").text()) - assertEquals("TWO", sideMenu.select("#root-nav-submenu-0-0-2").text()) - assertEquals("THREE", sideMenu.select("#root-nav-submenu-0-0-3").text()) - assertEquals("FOUR", sideMenu.select("#root-nav-submenu-0-0-4").text()) - assertEquals("FIVE", sideMenu.select("#root-nav-submenu-0-0-5").text()) - assertEquals("SIX", sideMenu.select("#root-nav-submenu-0-0-6").text()) - assertEquals("SEVEN", sideMenu.select("#root-nav-submenu-0-0-7").text()) - assertEquals("EIGHT", sideMenu.select("#root-nav-submenu-0-0-8").text()) - assertEquals("NINE", sideMenu.select("#root-nav-submenu-0-0-9").text()) - } - } - } - - fun TestOutputWriter.navigationHtml(): Element = contents.getValue("navigation.html").let { Jsoup.parse(it) } - - @Test - fun `should handle companion object within enum`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | E1, - | E2; - | companion object {} - |} - """.trimMargin(), - configuration - ) { - documentablesTransformationStage = { m -> - m.packages.let { p -> - assertTrue(p.isNotEmpty(), "Package list cannot be empty") - p.first().classlikes.let { c -> - assertTrue(c.isNotEmpty(), "Classlikes list cannot be empty") - - val enum = c.first() as DEnum - assertNotNull(enum.companion) - } - } - } - } - } - - - @Test - fun `should contain synthetic values and valueOf functions`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | E1, - | E2; - |} - """.trimMargin(), - configuration - ) { - // stage is important because they will get filtered out later on - documentablesCreationStage = { modules -> - val pckg = modules.flatMap { it.packages }.single { it.packageName == "testpackage" } - val enum = pckg.children.single { it is DEnum } as DEnum - - val valueOf = enum.functions.single { it.name == "valueOf" } - assertEquals("testpackage/TestEnum/valueOf/#kotlin.String/PointingToDeclaration/", valueOf.dri.toString()) - assertNotNull(valueOf.extra[ObviousMember]) - - val values = enum.functions.single { it.name == "values" } - assertEquals("testpackage/TestEnum/values/#/PointingToDeclaration/", values.dri.toString()) - assertNotNull(values.extra[ObviousMember]) - } - } - } - - @Test - fun enumWithMethods() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - testInline( - """ - |/src/main/kotlin/basic/TestEnum.kt - |package testpackage - | - | - |interface Sample { - | fun toBeImplemented(): String - |} - | - |enum class TestEnum: Sample { - | E1 { - | override fun toBeImplemented(): String = "e1" - | } - |} - """.trimMargin(), - configuration - ) { - documentablesTransformationStage = { m -> - m.packages.let { p -> - p.first().classlikes.let { c -> - val enum = c.first { it is DEnum } as DEnum - val first = enum.entries.first() - - assertNotNull(first.functions.find { it.name == "toBeImplemented" }) - } - } - } - } - } - - @Test - fun enumWithAnnotationsOnEntries() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - testInline( - """ - |/src/main/kotlin/basic/TestEnum.kt - |package testpackage - | - |enum class TestEnum { - | /** - | Sample docs for E1 - | **/ - | @SinceKotlin("1.3") // This annotation is transparent due to lack of @MustBeDocumented annotation - | E1 - |} - """.trimMargin(), - configuration - ) { - pagesTransformationStage = { m -> - val entryNode = m.children.first { it.name == "testpackage" }.children.first { it.name == "TestEnum" }.children.firstIsInstance<ClasslikePageNode>() - val signature = (entryNode.content as ContentGroup).dfs { it is ContentGroup && it.dci.toString() == "[testpackage/TestEnum.E1///PointingToDeclaration/{\"org.jetbrains.dokka.links.EnumEntryDRIExtra\":{\"key\":\"org.jetbrains.dokka.links.EnumEntryDRIExtra\"}}][Cover]" } as ContentGroup - - signature.assertNode { - header(1) { +"E1" } - platformHinted { - group { - group { - link { +"E1" } - } - } - group { - group { - group { - +"Sample docs for E1" - } - } - } - } - } - } - } - } -} diff --git a/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt b/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt new file mode 100644 index 00000000..f2c1fca8 --- /dev/null +++ b/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt @@ -0,0 +1,286 @@ +package renderers.html + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jsoup.Jsoup +import org.jsoup.nodes.Element +import org.jsoup.select.Elements +import org.junit.jupiter.api.Test +import utils.TestOutputWriter +import utils.TestOutputWriterPlugin +import kotlin.test.assertEquals + +class NavigationIconTest : BaseAbstractTest() { + + private val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + @Test + fun `should include all navigation icons`() { + val source = """ + |/src/main/kotlin/com/example/Empty.kt + |package com.example + | + |class Empty {} + """ + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + val navIconAssets = writerPlugin.writer.contents + .filterKeys { it.startsWith("images/nav-icons") } + .keys.sorted() + + assertEquals(15, navIconAssets.size) + assertEquals("images/nav-icons/abstract-class-kotlin.svg", navIconAssets[0]) + assertEquals("images/nav-icons/abstract-class.svg", navIconAssets[1]) + assertEquals("images/nav-icons/annotation-kotlin.svg", navIconAssets[2]) + assertEquals("images/nav-icons/annotation.svg", navIconAssets[3]) + assertEquals("images/nav-icons/class-kotlin.svg", navIconAssets[4]) + assertEquals("images/nav-icons/class.svg", navIconAssets[5]) + assertEquals("images/nav-icons/enum-kotlin.svg", navIconAssets[6]) + assertEquals("images/nav-icons/enum.svg", navIconAssets[7]) + assertEquals("images/nav-icons/exception-class.svg", navIconAssets[8]) + assertEquals("images/nav-icons/field-value.svg", navIconAssets[9]) + assertEquals("images/nav-icons/field-variable.svg", navIconAssets[10]) + assertEquals("images/nav-icons/function.svg", navIconAssets[11]) + assertEquals("images/nav-icons/interface-kotlin.svg", navIconAssets[12]) + assertEquals("images/nav-icons/interface.svg", navIconAssets[13]) + assertEquals("images/nav-icons/object.svg", navIconAssets[14]) + } + } + } + + @Test + fun `should add icon styles to kotlin class navigation item`() { + assertNavigationIcon( + source = kotlinSource("class Clazz {}"), + expectedIconClass = "class-kt", + expectedNavLinkText = "Clazz" + ) + } + + @Test + fun `should add icon styles to java class navigation item`() { + assertNavigationIcon( + source = javaSource( + className = "JavaClazz", + source = "public class JavaClazz {}" + ), + expectedIconClass = "class", + expectedNavLinkText = "JavaClazz" + ) + } + + @Test + fun `should add icon styles to kotlin abstract class navigation item`() { + assertNavigationIcon( + source = kotlinSource("abstract class AbstractClazz {}"), + expectedIconClass = "abstract-class-kt", + expectedNavLinkText = "AbstractClazz" + ) + } + + @Test + fun `should add icon styles to java abstract class navigation item`() { + assertNavigationIcon( + source = javaSource( + className = "AbstractJavaClazz", + source = "public abstract class AbstractJavaClazz {}" + ), + expectedIconClass = "abstract-class", + expectedNavLinkText = "AbstractJavaClazz" + ) + } + + @Test + fun `should add icon styles to kotlin enum navigation item`() { + assertNavigationIcon( + source = kotlinSource("enum class KotlinEnum {}"), + expectedIconClass = "enum-class-kt", + expectedNavLinkText = "KotlinEnum" + ) + } + + @Test + fun `should add icon styles to java enum class navigation item`() { + assertNavigationIcon( + source = javaSource( + className = "JavaEnum", + source = "public enum JavaEnum {}" + ), + expectedIconClass = "enum-class", + expectedNavLinkText = "JavaEnum" + ) + } + + @Test + fun `should add icon styles to kotlin annotation navigation item`() { + assertNavigationIcon( + source = kotlinSource("annotation class KotlinAnnotation"), + expectedIconClass = "annotation-class-kt", + expectedNavLinkText = "KotlinAnnotation" + ) + } + + @Test + fun `should add icon styles to java annotation navigation item`() { + assertNavigationIcon( + source = javaSource( + className = "JavaAnnotation", + source = "public @interface JavaAnnotation {}" + ), + expectedIconClass = "annotation-class", + expectedNavLinkText = "JavaAnnotation" + ) + } + + + @Test + fun `should add icon styles to kotlin interface navigation item`() { + assertNavigationIcon( + source = kotlinSource("interface KotlinInterface"), + expectedIconClass = "interface-kt", + expectedNavLinkText = "KotlinInterface" + ) + } + + @Test + fun `should add icon styles to java interface navigation item`() { + assertNavigationIcon( + source = javaSource( + className = "JavaInterface", + source = "public interface JavaInterface {}" + ), + expectedIconClass = "interface", + expectedNavLinkText = "JavaInterface" + ) + } + + @Test + fun `should add icon styles to kotlin function navigation item`() { + assertNavigationIcon( + source = kotlinSource("fun ktFunction() {}"), + expectedIconClass = "function", + expectedNavLinkText = "ktFunction()" + ) + } + + @Test + fun `should add icon styles to kotlin exception class navigation item`() { + assertNavigationIcon( + source = kotlinSource("class KotlinException : Exception() {}"), + expectedIconClass = "exception-class", + expectedNavLinkText = "KotlinException" + ) + } + + @Test + fun `should add icon styles to kotlin object navigation item`() { + assertNavigationIcon( + source = kotlinSource("object KotlinObject {}"), + expectedIconClass = "object", + expectedNavLinkText = "KotlinObject" + ) + } + + @Test + fun `should add icon styles to kotlin val navigation item`() { + assertNavigationIcon( + source = kotlinSource("val value: String? = null"), + expectedIconClass = "val", + expectedNavLinkText = "value" + ) + } + + @Test + fun `should add icon styles to kotlin var navigation item`() { + assertNavigationIcon( + source = kotlinSource("var variable: String? = null"), + expectedIconClass = "var", + expectedNavLinkText = "variable" + ) + } + + private fun kotlinSource(source: String): String { + return """ + |/src/main/kotlin/com/example/Example.kt + |package com.example + | + |$source + """.trimIndent() + } + + private fun javaSource(className: String, source: String): String { + return """ + |/src/main/java/com/example/$className.java + |package com.example; + | + |$source + """.trimIndent() + } + + private fun assertNavigationIcon(source: String, expectedIconClass: String, expectedNavLinkText: String) { + val writerPlugin = TestOutputWriterPlugin() + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + val content = writerPlugin.writer.navigationHtml().select("div.sideMenuPart") + val navigationGrid = content.selectNavigationGrid() + + val classNames = navigationGrid.child(0).classNames().toList() + assertEquals("nav-link-child", classNames[0]) + assertEquals("nav-icon", classNames[1]) + assertEquals(expectedIconClass, classNames[2]) + + val navLinkText = navigationGrid.child(1).text() + assertEquals(expectedNavLinkText, navLinkText) + } + } + } + + @Test + fun `should not generate nav link grids or icons for packages and modules`() { + val writerPlugin = TestOutputWriterPlugin() + testInline( + """ + |/src/main/kotlin/com/example/Example.kt + |package com.example + | + |class Example {} + """.trimIndent(), + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + val content = writerPlugin.writer.navigationHtml().select("div.sideMenuPart") + + assertEquals(3, content.size) + assertEquals("root-nav-submenu", content[0].id()) + assertEquals("root-nav-submenu-0", content[1].id()) + assertEquals("root-nav-submenu-0-0", content[2].id()) + + // there's 3 nav items, but only one icon + val navLinkGrids = content.select("span.nav-icon") + assertEquals(1, navLinkGrids.size) + } + } + } + + private fun TestOutputWriter.navigationHtml(): Element = contents.getValue("navigation.html").let { Jsoup.parse(it) } + + private fun Elements.selectNavigationGrid(): Element { + return this.select("div.overview").select("span.nav-link-grid").single() + } +} |