aboutsummaryrefslogtreecommitdiff
path: root/plugins/javadoc/src
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/javadoc/src')
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/JavadocDocumentableToPageTranslator.kt18
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt238
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt53
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt126
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProviderFactory.kt11
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt173
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocIndexExtra.kt10
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt436
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/htmlPreprocessors.kt68
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/pages.kt17
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt63
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt222
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt190
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/renderer/SearchScriptsCreator.kt261
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt201
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/translators/documentables/JavadocPageContentBuilder.kt80
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/utils.kt8
-rw-r--r--plugins/javadoc/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin1
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/external/jquery/jquery.js10364
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-bg_glass_55_fbf9ee_1x400.pngbin0 -> 335 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-bg_glass_65_dadada_1x400.pngbin0 -> 262 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-bg_glass_75_dadada_1x400.pngbin0 -> 262 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-bg_glass_75_e6e6e6_1x400.pngbin0 -> 262 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-bg_glass_95_fef1ec_1x400.pngbin0 -> 332 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-bg_highlight-soft_75_cccccc_1x100.pngbin0 -> 280 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-icons_222222_256x240.pngbin0 -> 6922 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-icons_2e83ff_256x240.pngbin0 -> 4549 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-icons_454545_256x240.pngbin0 -> 6992 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-icons_888888_256x240.pngbin0 -> 6999 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/images/ui-icons_cd0a0a_256x240.pngbin0 -> 4549 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/jquery-3.3.1.js10364
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/jquery-migrate-3.0.1.js628
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/jquery-ui.css582
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/jquery-ui.js2659
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/jquery-ui.min.css7
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/jquery-ui.min.js6
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/jquery-ui.structure.css156
-rw-r--r--plugins/javadoc/src/main/resources/static_res/jquery/jquery-ui.structure.min.css5
-rw-r--r--plugins/javadoc/src/main/resources/static_res/resources/glass.pngbin0 -> 499 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/resources/x.pngbin0 -> 394 bytes
-rw-r--r--plugins/javadoc/src/main/resources/static_res/search.js208
-rw-r--r--plugins/javadoc/src/main/resources/static_res/stylesheet.css879
-rw-r--r--plugins/javadoc/src/main/resources/views/class.korte297
-rw-r--r--plugins/javadoc/src/main/resources/views/components/base.korte26
-rw-r--r--plugins/javadoc/src/main/resources/views/components/bottomNavbar.korte20
-rw-r--r--plugins/javadoc/src/main/resources/views/components/head.korte17
-rw-r--r--plugins/javadoc/src/main/resources/views/components/indexPage.korte30
-rw-r--r--plugins/javadoc/src/main/resources/views/components/indexTable.korte18
-rw-r--r--plugins/javadoc/src/main/resources/views/components/navList.korte25
-rw-r--r--plugins/javadoc/src/main/resources/views/components/pageStart.korte37
-rw-r--r--plugins/javadoc/src/main/resources/views/components/subNav.korte30
-rw-r--r--plugins/javadoc/src/main/resources/views/components/topNavbar.korte24
-rw-r--r--plugins/javadoc/src/main/resources/views/listPage.korte13
-rw-r--r--plugins/javadoc/src/main/resources/views/tabPage.korte4
-rw-r--r--plugins/javadoc/src/main/resources/views/treePage.korte48
-rw-r--r--plugins/javadoc/src/test/kotlin/javadoc/AbstractJavadocTemplateMapTest.kt122
-rw-r--r--plugins/javadoc/src/test/kotlin/javadoc/JavadocAllClassesTemplateMapTest.kt49
-rw-r--r--plugins/javadoc/src/test/kotlin/javadoc/JavadocClasslikeTemplateMapTest.kt331
-rw-r--r--plugins/javadoc/src/test/kotlin/javadoc/JavadocModuleTemplateMapTest.kt78
-rw-r--r--plugins/javadoc/src/test/kotlin/javadoc/JavadocPackageTemplateMapTest.kt123
-rw-r--r--plugins/javadoc/src/test/kotlin/javadoc/JavadocTest.kt69
-rw-r--r--plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt128
-rw-r--r--plugins/javadoc/src/test/kotlin/javadoc/search/JavadocIndexSearchTest.kt59
-rw-r--r--plugins/javadoc/src/test/resources/javadoc/test/main/java/adaptation/Adaptation.kt50
64 files changed, 29632 insertions, 0 deletions
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocDocumentableToPageTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocDocumentableToPageTranslator.kt
new file mode 100644
index 00000000..840bdc55
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocDocumentableToPageTranslator.kt
@@ -0,0 +1,18 @@
+package javadoc
+
+import org.jetbrains.dokka.base.signatures.SignatureProvider
+import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.pages.ModulePageNode
+import org.jetbrains.dokka.pages.RootPageNode
+import org.jetbrains.dokka.transformers.documentation.DocumentableToPageTranslator
+import org.jetbrains.dokka.utilities.DokkaLogger
+
+class JavadocDocumentableToPageTranslator(
+ private val commentsToContentConverter: CommentsToContentConverter,
+ private val signatureProvider: SignatureProvider,
+ private val logger: DokkaLogger
+) : DocumentableToPageTranslator {
+ override fun invoke(module: DModule): RootPageNode =
+ JavadocPageCreator(commentsToContentConverter, signatureProvider, logger).pageForModule(module)
+} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt
new file mode 100644
index 00000000..7420f78e
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt
@@ -0,0 +1,238 @@
+package javadoc
+
+import javadoc.pages.*
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.Platform
+import org.jetbrains.dokka.base.signatures.SignatureProvider
+import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
+import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.doc.Description
+import org.jetbrains.dokka.model.doc.Index
+import org.jetbrains.dokka.model.doc.Param
+import org.jetbrains.dokka.model.doc.TagWrapper
+import org.jetbrains.dokka.model.properties.PropertyContainer
+import org.jetbrains.dokka.model.properties.WithExtraProperties
+import org.jetbrains.dokka.pages.*
+import org.jetbrains.dokka.utilities.DokkaLogger
+import kotlin.reflect.KClass
+
+open class JavadocPageCreator(
+ commentsToContentConverter: CommentsToContentConverter,
+ private val signatureProvider: SignatureProvider,
+ val logger: DokkaLogger
+) {
+
+ fun pageForModule(m: DModule): JavadocModulePageNode =
+ JavadocModulePageNode(
+ name = m.name.ifEmpty { "root" },
+ content = contentForModule(m),
+ children = m.packages.map { pageForPackage(it) },
+ dri = setOf(m.dri)
+ )
+
+ fun pageForPackage(p: DPackage) =
+ JavadocPackagePageNode(p.name, contentForPackage(p), setOf(p.dri), p,
+ p.classlikes.mapNotNull { pageForClasslike(it) } // TODO: nested classlikes
+ )
+
+ fun pageForClasslike(c: DClasslike): JavadocClasslikePageNode? =
+ c.highestJvmSourceSet?.let { jvm ->
+ JavadocClasslikePageNode(
+ name = c.name.orEmpty(),
+ content = contentForClasslike(c),
+ dri = setOf(c.dri),
+ signature = signatureForNode(c, jvm),
+ description = c.descriptionToContentNodes(),
+ constructors = (c as? WithConstructors)?.constructors?.mapNotNull { it.toJavadocFunction() }.orEmpty(),
+ methods = c.functions.mapNotNull { it.toJavadocFunction() },
+ entries = (c as? DEnum)?.entries?.map {
+ JavadocEntryNode(
+ it.dri,
+ it.name,
+ signatureForNode(it, jvm),
+ it.descriptionToContentNodes(jvm),
+ PropertyContainer.withAll(it.indexesInDocumentation())
+ )
+ }.orEmpty(),
+ classlikes = c.classlikes.mapNotNull { pageForClasslike(it) },
+ properties = c.properties.map {
+ JavadocPropertyNode(
+ it.dri,
+ it.name,
+ signatureForNode(it, jvm),
+ it.descriptionToContentNodes(jvm),
+ PropertyContainer.withAll(it.indexesInDocumentation())
+ )
+ },
+ documentable = c,
+ extra = ((c as? WithExtraProperties<Documentable>)?.extra ?: PropertyContainer.empty()) + c.indexesInDocumentation()
+ )
+ }
+
+ private fun contentForModule(m: DModule): JavadocContentNode =
+ JavadocContentGroup(
+ setOf(m.dri),
+ JavadocContentKind.OverviewSummary,
+ m.jvmSourceSets.toSet()
+ ) {
+ title(m.name, m.brief(), "0.0.1", dri = setOf(m.dri), kind = ContentKind.Main)
+ leafList(setOf(m.dri),
+ ContentKind.Packages, JavadocList(
+ "Packages", "Package",
+ m.packages.sortedBy { it.name }.map { p ->
+ RowJavadocListEntry(
+ LinkJavadocListEntry(p.name, setOf(p.dri), JavadocContentKind.PackageSummary, sourceSets),
+ p.brief()
+ )
+ }
+ ))
+ }
+
+ private fun contentForPackage(p: DPackage): JavadocContentNode =
+ JavadocContentGroup(
+ setOf(p.dri),
+ JavadocContentKind.PackageSummary,
+ p.jvmSourceSets.toSet()
+ ) {
+ title(p.name, p.brief(), "0.0.1", dri = setOf(p.dri), kind = ContentKind.Packages)
+ val rootList = p.classlikes.groupBy { it::class }.map { (key, value) ->
+ JavadocList(key.tabTitle, key.colTitle, value.map { c ->
+ RowJavadocListEntry(
+ LinkJavadocListEntry(c.name ?: "", setOf(c.dri), JavadocContentKind.Class, sourceSets),
+ c.brief()
+ )
+ })
+ }
+ rootList(setOf(p.dri), JavadocContentKind.Class, rootList)
+ }
+
+ private val KClass<out DClasslike>.colTitle: String
+ get() = when(this) {
+ DClass::class -> "Class"
+ DObject::class -> "Object"
+ DAnnotation::class -> "Annotation"
+ DEnum::class -> "Enum"
+ DInterface::class -> "Interface"
+ else -> ""
+ }
+
+ private val KClass<out DClasslike>.tabTitle: String
+ get() = "$colTitle Summary"
+
+ private fun contentForClasslike(c: DClasslike): JavadocContentNode =
+ JavadocContentGroup(
+ setOf(c.dri),
+ JavadocContentKind.Class,
+ c.jvmSourceSets.toSet()
+ ) {
+ title(
+ c.name.orEmpty(),
+ c.brief(),
+ "0.0.1",
+ parent = c.dri.packageName,
+ dri = setOf(c.dri),
+ kind = JavadocContentKind.Class
+ )
+ }
+
+ private fun DFunction.toJavadocFunction() = highestJvmSourceSet?.let { jvm ->
+ JavadocFunctionNode(
+ name = name,
+ dri = dri,
+ signature = signatureForNode(this, jvm),
+ brief = brief(jvm),
+ parameters = parameters.mapNotNull {
+ val signature = signatureForNode(it, jvm)
+ signature.modifiers?.let { type ->
+ JavadocParameterNode(
+ name = it.name.orEmpty(),
+ type = type,
+ description = it.brief(),
+ typeBound = it.type,
+ dri = it.dri,
+ extra = PropertyContainer.withAll(it.indexesInDocumentation())
+ )
+ }
+ },
+ extra = extra + indexesInDocumentation()
+ )
+ }
+
+ private val Documentable.jvmSourceSets
+ get() = sourceSets.filter { it.analysisPlatform == Platform.jvm }
+
+ private val Documentable.highestJvmSourceSet
+ get() = jvmSourceSets.let { sources ->
+ sources.firstOrNull { it != expectPresentInSet } ?: sources.firstOrNull()
+ }
+
+ private val firstSentenceRegex = Regex("^((?:[^.?!]|[.!?](?!\\s))*[.!?])")
+
+ private inline fun <reified T : TagWrapper> Documentable.findNodeInDocumentation(sourceSetData: DokkaSourceSet?): T? =
+ documentation[sourceSetData]?.firstChildOfTypeOrNull<T>()
+
+ private fun Documentable.descriptionToContentNodes(sourceSet: DokkaSourceSet? = highestJvmSourceSet) =
+ contentNodesFromType<Description>(sourceSet)
+
+ private fun DParameter.paramsToContentNodes(sourceSet: DokkaSourceSet? = highestJvmSourceSet) =
+ contentNodesFromType<Param>(sourceSet)
+
+ private inline fun <reified T : TagWrapper> Documentable.contentNodesFromType(sourceSet: DokkaSourceSet?) =
+ findNodeInDocumentation<T>(sourceSet)?.let {
+ DocTagToContentConverter.buildContent(
+ it.root,
+ DCI(setOf(dri), JavadocContentKind.OverviewSummary),
+ sourceSets.toSet()
+ )
+ }.orEmpty()
+
+ fun List<ContentNode>.nodeForJvm(jvm: DokkaSourceSet): ContentNode =
+ first { it.sourceSets.contains(jvm) }
+
+ private fun Documentable.brief(sourceSet: DokkaSourceSet? = highestJvmSourceSet): List<ContentNode> =
+ briefFromContentNodes(descriptionToContentNodes(sourceSet))
+
+ private fun briefFromContentNodes(description: List<ContentNode>): List<ContentNode> {
+ val contents = mutableListOf<ContentNode>()
+ for (node in description) {
+ if (node is ContentText && firstSentenceRegex.containsMatchIn(node.text)) {
+ contents.add(node.copy(text = firstSentenceRegex.find(node.text)?.value.orEmpty()))
+ break
+ } else {
+ contents.add(node)
+ }
+ }
+ return contents
+ }
+
+ private fun DParameter.brief(sourceSet: DokkaSourceSet? = highestJvmSourceSet): List<ContentNode> =
+ briefFromContentNodes(paramsToContentNodes(sourceSet).dropWhile { it is ContentDRILink })
+
+ private fun ContentNode.asJavadocNode(): JavadocSignatureContentNode =
+ (this as ContentGroup).firstChildOfTypeOrNull<JavadocSignatureContentNode>()
+ ?: throw IllegalStateException("No content for javadoc signature found")
+
+ private fun signatureForNode(documentable: Documentable, sourceSet: DokkaSourceSet): JavadocSignatureContentNode =
+ signatureProvider.signature(documentable).nodeForJvm(sourceSet).asJavadocNode()
+
+ private fun Documentable.indexesInDocumentation(): JavadocIndexExtra {
+ val indexes = documentation[highestJvmSourceSet]?.withDescendants()?.filterIsInstance<Index>()?.toList().orEmpty()
+ return JavadocIndexExtra(
+ indexes.map {
+ ContentGroup(
+ children = DocTagToContentConverter.buildContent(
+ it,
+ DCI(setOf(dri), JavadocContentKind.OverviewSummary),
+ sourceSets.toSet()
+ ),
+ dci = DCI(setOf(dri), JavadocContentKind.OverviewSummary),
+ sourceSets = sourceSets.toSet(),
+ style = emptySet(),
+ extra = PropertyContainer.empty()
+ )
+ }
+ )
+ }
+}
+
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt
new file mode 100644
index 00000000..8283bd78
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt
@@ -0,0 +1,53 @@
+package org.jetbrains.dokka.javadoc
+
+import javadoc.JavadocDocumentableToPageTranslator
+import javadoc.location.JavadocLocationProviderFactory
+import javadoc.renderer.KorteJavadocRenderer
+import javadoc.signatures.JavadocSignatureProvider
+import org.jetbrains.dokka.CoreExtensions
+import org.jetbrains.dokka.base.DokkaBase
+import org.jetbrains.dokka.kotlinAsJava.KotlinAsJavaPlugin
+import org.jetbrains.dokka.plugability.DokkaPlugin
+import org.jetbrains.dokka.plugability.querySingle
+
+class JavadocPlugin : DokkaPlugin() {
+
+ val dokkaBasePlugin by lazy { plugin<DokkaBase>() }
+ val kotinAsJavaPlugin by lazy { plugin<KotlinAsJavaPlugin>() }
+
+ val locationProviderFactory by extensionPoint<JavadocLocationProviderFactory>()
+
+ val dokkaJavadocPlugin by extending {
+ (CoreExtensions.renderer
+ providing { ctx -> KorteJavadocRenderer(dokkaBasePlugin.querySingle { outputWriter }, ctx, "views") }
+ override dokkaBasePlugin.htmlRenderer)
+ }
+
+ val pageTranslator by extending {
+ CoreExtensions.documentableToPageTranslator providing { context ->
+ JavadocDocumentableToPageTranslator(
+ dokkaBasePlugin.querySingle { commentsToContentConverter },
+ dokkaBasePlugin.querySingle { signatureProvider },
+ context.logger
+ )
+ } override dokkaBasePlugin.documentableToPageTranslator
+ }
+
+ val javadocLocationProviderFactory by extending {
+ locationProviderFactory providing { context ->
+ JavadocLocationProviderFactory(context)
+ }
+ }
+
+ val javadocSignatureProvider by extending {
+ val dokkaBasePlugin = plugin<DokkaBase>()
+ dokkaBasePlugin.signatureProvider providing { ctx ->
+ JavadocSignatureProvider(
+ ctx.single(
+ dokkaBasePlugin.commentsToContentConverter
+ ), ctx.logger
+ )
+ } override kotinAsJavaPlugin.javaSignatureProvider
+ }
+}
+
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt b/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt
new file mode 100644
index 00000000..49278b06
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt
@@ -0,0 +1,126 @@
+package javadoc.location
+
+import javadoc.pages.*
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.base.resolvers.local.BaseLocationProvider
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.links.Nullable
+import org.jetbrains.dokka.links.parent
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.pages.ContentPage
+import org.jetbrains.dokka.pages.PageNode
+import org.jetbrains.dokka.pages.RootPageNode
+import org.jetbrains.dokka.plugability.DokkaContext
+import java.util.*
+
+class JavadocLocationProvider(pageRoot: RootPageNode, dokkaContext: DokkaContext) :
+ BaseLocationProvider(dokkaContext) {
+
+ private val pathIndex = IdentityHashMap<PageNode, List<String>>().apply {
+ fun registerPath(page: PageNode, prefix: List<String> = emptyList()) {
+ val newPrefix = prefix + page.takeIf { it is JavadocPackagePageNode }?.name.orEmpty()
+ val path = (prefix + when (page) {
+ is AllClassesPage -> listOf("allclasses")
+ is TreeViewPage -> if (page.classes == null)
+ listOf("overview-tree")
+ else
+ listOf("package-tree")
+ is ContentPage -> if (page.dri.isNotEmpty() && page.dri.first().classNames != null)
+ listOfNotNull(page.dri.first().classNames)
+ else if (page is JavadocPackagePageNode)
+ listOf(page.name, "package-summary")
+ else
+ listOf("index")
+ else -> emptyList()
+ }).filterNot { it.isEmpty() }
+
+ put(page, path)
+ page.children.forEach { registerPath(it, newPrefix) }
+
+ }
+ put(pageRoot, listOf("index"))
+ pageRoot.children.forEach { registerPath(it) }
+ }
+
+ private val nodeIndex = HashMap<DRI, PageNode>().apply {
+ fun registerNode(node: PageNode) {
+ if (node is ContentPage) put(node.dri.first(), node)
+ node.children.forEach(::registerNode)
+ }
+ registerNode(pageRoot)
+ }
+
+ private operator fun IdentityHashMap<PageNode, List<String>>.get(dri: DRI) = this[nodeIndex[dri]]
+
+ private fun List<String>.relativeTo(context: List<String>): String {
+ val contextPath = context.dropLast(1)
+ val commonPathElements = zip(contextPath).takeWhile { (a, b) -> a == b }.count()
+ return (List(contextPath.size - commonPathElements) { ".." } + this.drop(commonPathElements)).joinToString("/")
+ }
+
+ private fun JavadocClasslikePageNode.findAnchorableByDRI(dri: DRI): AnchorableJavadocNode? =
+ (constructors + methods + entries + properties).firstOrNull { it.dri == dri }
+
+ override fun resolve(dri: DRI, sourceSets: Set<DokkaSourceSet>, context: PageNode?): String {
+ return nodeIndex[dri]?.let { resolve(it, context) }
+ ?: nodeIndex[dri.parent]?.let {
+ val anchor = when (val anchorElement = (it as? JavadocClasslikePageNode)?.findAnchorableByDRI(dri)) {
+ is JavadocFunctionNode -> anchorElement.getAnchor()
+ is JavadocEntryNode -> anchorElement.name
+ is JavadocPropertyNode -> anchorElement.name
+ else -> anchorForDri(dri)
+ }
+ "${resolve(it, context, skipExtension = true)}.html#$anchor"
+ }
+ ?: getExternalLocation(dri, sourceSets)
+ }
+
+ private fun JavadocFunctionNode.getAnchor(): String =
+ "$name(${parameters.joinToString(",") {
+ when (val bound = if (it.typeBound is org.jetbrains.dokka.model.Nullable) it.typeBound.inner else it.typeBound) {
+ is TypeConstructor -> bound.dri.classNames.orEmpty()
+ is OtherParameter -> bound.name
+ is PrimitiveJavaType -> bound.name
+ is UnresolvedBound -> bound.name
+ is JavaObject -> "Object"
+ else -> bound.toString()
+ }
+ }})"
+
+ fun anchorForFunctionNode(node: JavadocFunctionNode) = node.getAnchor()
+
+ private fun anchorForDri(dri: DRI): String =
+ dri.callable?.let { callable ->
+ "${callable.name}(${callable.params.joinToString(",") {
+ ((it as? Nullable)?.wrapped ?: it).toString()
+ }})"
+ } ?: dri.classNames.orEmpty()
+
+ override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean): String =
+ pathIndex[node]?.relativeTo(pathIndex[context].orEmpty())?.let {
+ if (skipExtension) it.removeSuffix(".html") else it
+ } ?: run {
+ throw IllegalStateException("Path for ${node::class.java.canonicalName}:${node.name} not found")
+ }
+
+ fun resolve(link: LinkJavadocListEntry, contextRoot: PageNode? = null, skipExtension: Boolean = true) =
+ pathIndex[link.dri.first()]?.let {
+ when (link.kind) {
+ JavadocContentKind.Class -> it
+ JavadocContentKind.OverviewSummary -> it.dropLast(1) + "index"
+ JavadocContentKind.PackageSummary -> it.dropLast(1) + "package-summary"
+ JavadocContentKind.AllClasses -> it.dropLast(1) + "allclasses"