aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Doległo <kamilok1965@interia.pl>2020-08-11 21:47:26 +0200
committerSebastian Sellmair <34319766+sellmair@users.noreply.github.com>2020-08-19 13:34:10 +0200
commit852a6ce6c0f43c9b2044320dcceb4c6cc0a3b302 (patch)
treefb95be79e816769ca5305cf3a601348549000c6d
parent822653f017fa58352148e1c586690debb6773965 (diff)
downloaddokka-852a6ce6c0f43c9b2044320dcceb4c6cc0a3b302.tar.gz
dokka-852a6ce6c0f43c9b2044320dcceb4c6cc0a3b302.tar.bz2
dokka-852a6ce6c0f43c9b2044320dcceb4c6cc0a3b302.zip
Refactor location providers
-rw-r--r--integration-tests/build.gradle.kts11
-rw-r--r--integration-tests/gradle/projects/it-multiplatform-0/build.gradle.kts13
-rw-r--r--integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt25
-rw-r--r--plugins/base/src/main/kotlin/DokkaBase.kt24
-rw-r--r--plugins/base/src/main/kotlin/renderers/PackageListService.kt9
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt9
-rw-r--r--plugins/base/src/main/kotlin/renderers/preprocessors.kt5
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/DefaultExternalLocationProvider.kt22
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/DefaultExternalLocationProviderFactory.kt20
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/DokkaExternalLocationProviderFactory.kt35
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProvider.kt7
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactory.kt25
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactoryWithCache.kt17
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/JavadocExternalLocationProviderFactory.kt37
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt31
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProviderFactory.kt25
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/BaseLocationProvider.kt141
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt232
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt103
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProviderFactory.kt (renamed from plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProviderFactory.kt)17
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt8
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/LocationProviderFactory.kt7
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt6
-rw-r--r--plugins/base/src/main/kotlin/resolvers/shared/ExternalDocumentationInfo.kt5
-rw-r--r--plugins/base/src/main/kotlin/resolvers/shared/LinkFormat.kt6
-rw-r--r--plugins/base/src/main/kotlin/resolvers/shared/PackageList.kt42
-rw-r--r--plugins/base/src/main/kotlin/resolvers/shared/RecognizedLinkFormat.kt18
-rw-r--r--plugins/base/src/main/kotlin/resolvers/shared/utils.kt36
-rw-r--r--plugins/base/src/test/kotlin/locationProvider/DefaultLocationProviderTest.kt4
-rw-r--r--plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt10
-rw-r--r--plugins/build.gradle.kts6
-rw-r--r--plugins/gfm/src/main/kotlin/GfmPlugin.kt14
-rw-r--r--plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt6
-rw-r--r--plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProvider.kt34
-rw-r--r--plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProviderFactory.kt1
-rw-r--r--plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToHtmlTranslator.kt7
-rw-r--r--plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/SearchScriptsCreator.kt6
-rw-r--r--plugins/jekyll/src/main/kotlin/JekyllPlugin.kt7
38 files changed, 508 insertions, 523 deletions
diff --git a/integration-tests/build.gradle.kts b/integration-tests/build.gradle.kts
index aaa8b153..a41269b9 100644
--- a/integration-tests/build.gradle.kts
+++ b/integration-tests/build.gradle.kts
@@ -1,3 +1,6 @@
+import org.gradle.api.tasks.testing.logging.TestExceptionFormat
+import org.gradle.api.tasks.testing.logging.TestLogEvent
+
subprojects {
sourceSets {
create("integrationTest") {
@@ -38,6 +41,14 @@ subprojects {
?: System.getenv("DOKKA_INTEGRATION_TEST_IS_EXHAUSTIVE")?.toBoolean()
?: false.toString()
)
+
+ testLogging {
+ exceptionFormat = TestExceptionFormat.FULL
+ events(TestLogEvent.SKIPPED, TestLogEvent.FAILED)
+ showExceptions = true
+ showCauses = true
+ showStackTraces = true
+ }
}
tasks.check {
diff --git a/integration-tests/gradle/projects/it-multiplatform-0/build.gradle.kts b/integration-tests/gradle/projects/it-multiplatform-0/build.gradle.kts
index a8d7b837..27283fa2 100644
--- a/integration-tests/gradle/projects/it-multiplatform-0/build.gradle.kts
+++ b/integration-tests/gradle/projects/it-multiplatform-0/build.gradle.kts
@@ -1,3 +1,6 @@
+import org.jetbrains.dokka.gradle.DokkaTask
+import java.net.URL
+
plugins {
kotlin("multiplatform")
id("org.jetbrains.dokka")
@@ -18,3 +21,13 @@ kotlin {
}
}
}
+
+tasks.withType<DokkaTask> {
+ dokkaSourceSets {
+ configureEach {
+ externalDocumentationLink {
+ url = URL("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/")
+ }
+ }
+ }
+}
diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt
index 6d71f161..c24ca75b 100644
--- a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt
+++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt
@@ -62,6 +62,13 @@ class Android0GradleIntegrationTest(override val versions: BuildVersions) : Abst
"Expected html files in html output directory"
)
+ htmlOutputDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinksIgnoringKnown(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoEmptyLinks(file)
+ }
+
assertTrue(
htmlOutputDir.allHtmlFiles().any { file ->
"https://developer.android.com/reference/android/content/Context.html" in file.readText()
@@ -81,4 +88,22 @@ class Android0GradleIntegrationTest(override val versions: BuildVersions) : Abst
assertNoHrefToMissingLocalFileOrDirectory(file)
}
}
+
+ // TODO: use [assertNoUnresolvedLinks] instead when https://github.com/Kotlin/dokka/issues/1306 is closed
+ private fun assertNoUnresolvedLinksIgnoringKnown(file: File) {
+ val knownUnresolvedDRIs = setOf(
+ "it.android/IntegrationTestActivity/findViewById/#kotlin.Int/PointingToGenericParameters(0)/",
+ "it.android/IntegrationTestActivity/getExtraData/#java.lang.Class[TypeParam(bounds=[androidx.core.app.ComponentActivity.ExtraData])]/PointingToGenericParameters(0)/",
+ "it.android/IntegrationTestActivity/getSystemService/#java.lang.Class[TypeParam(bounds=[kotlin.Any])]/PointingToGenericParameters(0)/",
+ "it.android/IntegrationTestActivity/requireViewById/#kotlin.Int/PointingToGenericParameters(0)/"
+ )
+ val fileText = file.readText()
+ val regex = Regex("""data-unresolved-link="\[(.+?(?=]"))""")
+ val match = regex.findAll(fileText).map { it.groups[1]!!.value }
+
+ assertTrue(
+ match.filterNot { it in knownUnresolvedDRIs }.toList().isEmpty(),
+ "Unexpected unresolved link in ${file.path}\n" + fileText
+ )
+ }
}
diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt
index cf268ec1..e74bc6d9 100644
--- a/plugins/base/src/main/kotlin/DokkaBase.kt
+++ b/plugins/base/src/main/kotlin/DokkaBase.kt
@@ -7,15 +7,15 @@ import org.jetbrains.dokka.analysis.KotlinAnalysis
import org.jetbrains.dokka.base.allModulePage.MultimodulePageCreator
import org.jetbrains.dokka.base.renderers.*
import org.jetbrains.dokka.base.renderers.html.*
+import org.jetbrains.dokka.base.resolvers.external.ExternalLocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.external.javadoc.JavadocExternalLocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.shared.RecognizedLinkFormat
import org.jetbrains.dokka.base.signatures.KotlinSignatureProvider
import org.jetbrains.dokka.base.signatures.SignatureProvider
-import org.jetbrains.dokka.base.resolvers.external.*
-import org.jetbrains.dokka.base.resolvers.local.DefaultLocationProviderFactory
-import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory
import org.jetbrains.dokka.base.transformers.documentables.*
-import org.jetbrains.dokka.base.transformers.documentables.DefaultDocumentableMerger
-import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationTransformer
-import org.jetbrains.dokka.base.transformers.documentables.ReportUndocumentedTransformer
import org.jetbrains.dokka.base.transformers.pages.annotations.SinceKotlinTransformer
import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter
@@ -154,15 +154,15 @@ class DokkaBase : DokkaPlugin() {
}
val locationProvider by extending {
- locationProviderFactory providing ::DefaultLocationProviderFactory
+ locationProviderFactory providing ::DokkaLocationProviderFactory
}
val javadocLocationProvider by extending {
- externalLocationProviderFactory with JavadocExternalLocationProviderFactory()
+ externalLocationProviderFactory providing ::JavadocExternalLocationProviderFactory
}
val dokkaLocationProvider by extending {
- externalLocationProviderFactory with DokkaExternalLocationProviderFactory()
+ externalLocationProviderFactory providing ::DefaultExternalLocationProviderFactory
}
val fileWriter by extending {
@@ -210,11 +210,7 @@ class DokkaBase : DokkaPlugin() {
val packageListCreator by extending {
htmlPreprocessors providing {
- PackageListCreator(
- it,
- "html",
- "html"
- )
+ PackageListCreator(it, RecognizedLinkFormat.DokkaHtml)
} order { after(rootCreator) }
}
diff --git a/plugins/base/src/main/kotlin/renderers/PackageListService.kt b/plugins/base/src/main/kotlin/renderers/PackageListService.kt
index 0cf84ddd..42c8d66e 100644
--- a/plugins/base/src/main/kotlin/renderers/PackageListService.kt
+++ b/plugins/base/src/main/kotlin/renderers/PackageListService.kt
@@ -39,9 +39,9 @@ class PackageListService(val context: DokkaContext) {
visit(module, setOf())
return buildString {
- appendln("\$dokka.format:${format}")
- appendln("\$dokka.linkExtension:${linkExtension}")
- nonStandardLocations.map { (signature, location) -> "\$dokka.location:$signature\u001f$location" }
+ appendLine("$DOKKA_PARAM_PREFIX.format:${format}")
+ appendLine("$DOKKA_PARAM_PREFIX.linkExtension:${linkExtension}")
+ nonStandardLocations.map { (signature, location) -> "$DOKKA_PARAM_PREFIX.location:$signature\u001f$location" }
.sorted().joinTo(this, separator = "\n", postfix = "\n")
packages.sorted().joinTo(this, separator = "\n", postfix = "\n")
@@ -49,4 +49,7 @@ class PackageListService(val context: DokkaContext) {
}
+ companion object {
+ const val DOKKA_PARAM_PREFIX = "\$dokka"
+ }
} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
index e3d54e49..d9833e43 100644
--- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
@@ -21,6 +21,7 @@ import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.plugin
import org.jetbrains.dokka.plugability.query
import org.jetbrains.dokka.plugability.querySingle
+import org.jetbrains.dokka.utilities.htmlEscape
import java.io.File
import java.net.URI
@@ -550,7 +551,7 @@ open class HtmlRenderer(
platforms: List<DisplaySourceSet>,
from: PageNode? = null,
block: FlowContent.() -> Unit
- ) = buildLink(locationProvider.resolve(to, platforms.toSet(), from).orEmpty(), block)
+ ) = buildLink(locationProvider.resolve(to, platforms.toSet(), from)!!, block)
override fun buildError(node: ContentNode) {
context.logger.error("Unknown ContentNode type: $node")
@@ -573,7 +574,7 @@ open class HtmlRenderer(
buildText(node.children, pageContext, sourceSetRestriction)
}
} ?: span {
- attributes["data-unresolved-link"] = "true"
+ attributes["data-unresolved-link"] = node.address.toString().htmlEscape()
buildText(node.children, pageContext, sourceSetRestriction)
}
@@ -625,7 +626,7 @@ open class HtmlRenderer(
}
}
- private fun PageNode.root(path: String) = locationProvider.resolveRoot(this) + path
+ private fun PageNode.root(path: String) = locationProvider.pathToRoot(this) + path
override fun buildPage(page: ContentPage, content: (FlowContent, ContentPage) -> Unit): String =
buildHtml(page, page.embeddedResources) {
@@ -658,7 +659,7 @@ open class HtmlRenderer(
else -> unsafe { +it }
}
}
- script { unsafe { +"""var pathToRoot = "${locationProvider.resolveRoot(page)}";""" } }
+ script { unsafe { +"""var pathToRoot = "${locationProvider.pathToRoot(page)}";""" } }
}
body {
div {
diff --git a/plugins/base/src/main/kotlin/renderers/preprocessors.kt b/plugins/base/src/main/kotlin/renderers/preprocessors.kt
index bf2a9eb4..b07db2bd 100644
--- a/plugins/base/src/main/kotlin/renderers/preprocessors.kt
+++ b/plugins/base/src/main/kotlin/renderers/preprocessors.kt
@@ -1,5 +1,6 @@
package org.jetbrains.dokka.base.renderers
+import org.jetbrains.dokka.base.resolvers.shared.LinkFormat
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.transformers.pages.PageTransformer
@@ -10,7 +11,7 @@ object RootCreator : PageTransformer {
}
-class PackageListCreator(val context: DokkaContext, val format: String, val linkExtension: String) : PageTransformer {
+class PackageListCreator(val context: DokkaContext, val format: LinkFormat) : PageTransformer {
override fun invoke(input: RootPageNode) =
input.modified(children = input.children.map {
it.takeUnless { it is ModulePageNode }
@@ -22,6 +23,6 @@ class PackageListCreator(val context: DokkaContext, val format: String, val link
RendererSpecificResourcePage(
"${pageNode.name}/package-list",
emptyList(),
- RenderingStrategy.Write(PackageListService(context).formatPackageList(pageNode, format, linkExtension))
+ RenderingStrategy.Write(PackageListService(context).formatPackageList(pageNode, format.formatName, format.linkExtension))
)
}
diff --git a/plugins/base/src/main/kotlin/resolvers/external/DefaultExternalLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/external/DefaultExternalLocationProvider.kt
new file mode 100644
index 00000000..5e22206b
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/external/DefaultExternalLocationProvider.kt
@@ -0,0 +1,22 @@
+package org.jetbrains.dokka.base.resolvers.external
+
+import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProvider.Companion.identifierToFilename
+import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentationInfo
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.plugability.DokkaContext
+
+open class DefaultExternalLocationProvider(
+ val externalDocumentationInfo: ExternalDocumentationInfo,
+ val extension: String,
+ val dokkaContext: DokkaContext
+) : ExternalLocationProvider {
+ override fun resolve(dri: DRI): String? { // TODO: classes without packages?
+ val docURL = externalDocumentationInfo.documentationURL.toString().removeSuffix("/") + "/"
+ val classNamesChecked = dri.classNames ?: return "$docURL${dri.packageName ?: ""}/index$extension"
+ val classLink = (listOfNotNull(dri.packageName) + classNamesChecked.split('.'))
+ .joinToString("/", transform = ::identifierToFilename)
+
+ val callableChecked = dri.callable ?: return "$docURL$classLink/index$extension"
+ return "$docURL$classLink/" + identifierToFilename(callableChecked.name) + extension
+ }
+}
diff --git a/plugins/base/src/main/kotlin/resolvers/external/DefaultExternalLocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/external/DefaultExternalLocationProviderFactory.kt
new file mode 100644
index 00000000..a6e09bac
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/external/DefaultExternalLocationProviderFactory.kt
@@ -0,0 +1,20 @@
+package org.jetbrains.dokka.base.resolvers.external
+
+import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentationInfo
+import org.jetbrains.dokka.base.resolvers.shared.RecognizedLinkFormat
+import org.jetbrains.dokka.plugability.DokkaContext
+
+class DefaultExternalLocationProviderFactory(val context: DokkaContext) :
+ ExternalLocationProviderFactory by ExternalLocationProviderFactoryWithCache(
+ object : ExternalLocationProviderFactory {
+ override fun getExternalLocationProvider(docInfo: ExternalDocumentationInfo): ExternalLocationProvider? =
+ when (docInfo.packageList.linkFormat) {
+ RecognizedLinkFormat.KotlinWebsiteHtml,
+ RecognizedLinkFormat.DokkaOldHtml,
+ RecognizedLinkFormat.DokkaHtml -> DefaultExternalLocationProvider(docInfo, ".html", context)
+ RecognizedLinkFormat.DokkaGFM,
+ RecognizedLinkFormat.DokkaJekyll -> DefaultExternalLocationProvider(docInfo, ".md", context)
+ else -> null
+ }
+ }
+ ) \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/resolvers/external/DokkaExternalLocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/external/DokkaExternalLocationProviderFactory.kt
deleted file mode 100644
index ff9186f7..00000000
--- a/plugins/base/src/main/kotlin/resolvers/external/DokkaExternalLocationProviderFactory.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.jetbrains.dokka.base.resolvers.external
-
-import org.jetbrains.dokka.base.resolvers.local.identifierToFilename
-import org.jetbrains.dokka.links.DRI
-
-
-class DokkaExternalLocationProviderFactory : ExternalLocationProviderFactory by ExternalLocationProviderFactoryWithCache(
- object : ExternalLocationProviderFactory {
- override fun getExternalLocationProvider(param: String): ExternalLocationProvider? =
- when (param) {
- "kotlin-website-html", "html" -> DokkaExternalLocationProvider(param, ".html")
- "markdown" -> DokkaExternalLocationProvider(param, ".md")
- else -> null
- }
- }
-)
-
-class DokkaExternalLocationProvider(override val param: String, val extension: String) : ExternalLocationProvider {
-
- override fun DRI.toLocation(): String { // TODO: classes without packages?
-
- val classNamesChecked = classNames ?: return "${packageName ?: ""}/index$extension"
-
- val classLink = (listOfNotNull(packageName) + classNamesChecked.split('.')).joinToString(
- "/",
- transform = ::identifierToFilename
- )
-
- val callableChecked = callable ?: return "$classLink/index$extension"
-
- return "$classLink/${identifierToFilename(
- callableChecked.name
- )}$extension"
- }
-}
diff --git a/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProvider.kt
new file mode 100644
index 00000000..51df1504
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProvider.kt
@@ -0,0 +1,7 @@
+package org.jetbrains.dokka.base.resolvers.external
+
+import org.jetbrains.dokka.links.DRI
+
+interface ExternalLocationProvider {
+ fun resolve(dri: DRI): String?
+}
diff --git a/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactory.kt
index 83de9911..10d9fffa 100644
--- a/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactory.kt
+++ b/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactory.kt
@@ -1,26 +1,7 @@
package org.jetbrains.dokka.base.resolvers.external
-import org.jetbrains.dokka.links.DRI
-import java.util.concurrent.ConcurrentHashMap
-
-
-interface ExternalLocationProvider {
-
- val param: String
- fun DRI.toLocation(): String
-}
+import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentationInfo
interface ExternalLocationProviderFactory {
-
- fun getExternalLocationProvider(param: String): ExternalLocationProvider?
-}
-
-class ExternalLocationProviderFactoryWithCache(val ext: ExternalLocationProviderFactory) : ExternalLocationProviderFactory {
-
- private val locationProviders = ConcurrentHashMap<String, CacheWrapper>()
-
- override fun getExternalLocationProvider(param: String): ExternalLocationProvider? =
- locationProviders.getOrPut(param) { CacheWrapper(ext.getExternalLocationProvider(param)) }.provider
-}
-
-private class CacheWrapper(val provider: ExternalLocationProvider?) \ No newline at end of file
+ fun getExternalLocationProvider(docInfo: ExternalDocumentationInfo): ExternalLocationProvider?
+} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactoryWithCache.kt b/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactoryWithCache.kt
new file mode 100644
index 00000000..4fa1f391
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactoryWithCache.kt
@@ -0,0 +1,17 @@
+package org.jetbrains.dokka.base.resolvers.external
+
+import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentationInfo
+import org.jetbrains.dokka.base.resolvers.shared.PackageList
+import java.util.concurrent.ConcurrentHashMap
+
+class ExternalLocationProviderFactoryWithCache(val ext: ExternalLocationProviderFactory) :
+ ExternalLocationProviderFactory {
+
+ private val locationProviders = ConcurrentHashMap<ExternalDocumentationInfo, CacheWrapper>()
+
+ override fun getExternalLocationProvider(docInfo: ExternalDocumentationInfo): ExternalLocationProvider? =
+ locationProviders.getOrPut(docInfo) { CacheWrapper(ext.getExternalLocationProvider(docInfo)) }.provider
+
+ private class CacheWrapper(val provider: ExternalLocationProvider?)
+}
+
diff --git a/plugins/base/src/main/kotlin/resolvers/external/JavadocExternalLocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/external/JavadocExternalLocationProviderFactory.kt
deleted file mode 100644
index c52c9bbb..00000000
--- a/plugins/base/src/main/kotlin/resolvers/external/JavadocExternalLocationProviderFactory.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.jetbrains.dokka.base.resolvers.external
-
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.utilities.htmlEscape
-
-class JavadocExternalLocationProviderFactory : ExternalLocationProviderFactory by ExternalLocationProviderFactoryWithCache(
- object : ExternalLocationProviderFactory {
- override fun getExternalLocationProvider(param: String): ExternalLocationProvider? =
- when(param) {
- "javadoc1" -> JavadocExternalLocationProvider(param, "()", ", ") // Covers JDK 1 - 7
- "javadoc8" -> JavadocExternalLocationProvider(param, "--", "-") // Covers JDK 8 - 9
- "javadoc10" -> JavadocExternalLocationProvider(param, "()", ",") // Covers JDK 10
- else -> null
- }
- }
-)
-
-class JavadocExternalLocationProvider(override val param: String, val brackets: String, val separator: String) : ExternalLocationProvider {
-
- override fun DRI.toLocation(): String {
-
- val packageLink = packageName?.replace(".", "/")
- if (classNames == null) {
- return "$packageLink/package-summary.html".htmlEscape()
- }
- val classLink = if (packageLink == null) "$classNames.html" else "$packageLink/$classNames.html"
- val callableChecked = callable ?: return classLink.htmlEscape()
-
- val callableLink = "$classLink#" +
- callableChecked.name +
- "${brackets.first()}" +
- callableChecked.params.joinToString(separator) +
- "${brackets.last()}"
-
- return callableLink.htmlEscape()
- }
-} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt
new file mode 100644
index 00000000..d42b5b5c
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt
@@ -0,0 +1,31 @@
+package org.jetbrains.dokka.base.resolvers.external.javadoc
+
+import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProvider
+import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentationInfo
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.utilities.htmlEscape
+
+class JavadocExternalLocationProvider(
+ externalDocumentationInfo: ExternalDocumentationInfo,
+ val brackets: String,
+ val separator: String,
+ dokkaContext: DokkaContext
+) : DefaultExternalLocationProvider(externalDocumentationInfo, ".html", dokkaContext) {
+
+ override fun resolve(dri: DRI): String? {
+ val docURL = externalDocumentationInfo.documentationURL.toString().removeSuffix("/") + "/"
+ val packageLink = dri.packageName?.replace(".", "/")
+ if (dri.classNames == null) {
+ return "$docURL$packageLink/package-summary$extension".htmlEscape()
+ }
+ val classLink = if (packageLink == null) "${dri.classNames}$extension" else "$packageLink/${dri.classNames}$extension"
+ val callableChecked = dri.callable ?: return "$docURL$classLink".htmlEscape()
+
+ return ("$docURL$classLink#" +
+ callableChecked.name +
+ "${brackets.first()}" +
+ callableChecked.params.joinToString(separator) +
+ "${brackets.last()}").htmlEscape()
+ }
+} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProviderFactory.kt
new file mode 100644
index 00000000..1cfd73a8
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProviderFactory.kt
@@ -0,0 +1,25 @@
+package org.jetbrains.dokka.base.resolvers.external.javadoc
+
+import org.jetbrains.dokka.base.resolvers.external.ExternalLocationProvider
+import org.jetbrains.dokka.base.resolvers.external.ExternalLocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.external.ExternalLocationProviderFactoryWithCache
+import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentationInfo
+import org.jetbrains.dokka.base.resolvers.shared.RecognizedLinkFormat
+import org.jetbrains.dokka.plugability.DokkaContext
+
+class JavadocExternalLocationProviderFactory(val context: DokkaContext) :
+ ExternalLocationProviderFactory by ExternalLocationProviderFactoryWithCache(
+ object : ExternalLocationProviderFactory {
+ override fun getExternalLocationProvider(docInfo: ExternalDocumentationInfo): ExternalLocationProvider? =
+ when (docInfo.packageList.linkFormat) {
+ RecognizedLinkFormat.Javadoc1 ->
+ JavadocExternalLocationProvider(docInfo, "()", ", ", context) // Covers JDK 1 - 7
+ RecognizedLinkFormat.Javadoc8,
+ RecognizedLinkFormat.DokkaJavadoc ->
+ JavadocExternalLocationProvider(docInfo, "--", "-", context) // Covers JDK 8 - 9
+ RecognizedLinkFormat.Javadoc10 ->
+ JavadocExternalLocationProvider(docInfo, "()", ",", context) // Covers JDK 10
+ else -> null
+ }
+ }
+ ) \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/resolvers/local/BaseLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/BaseLocationProvider.kt
deleted file mode 100644
index 06730641..00000000
--- a/plugins/base/src/main/kotlin/resolvers/local/BaseLocationProvider.kt
+++ /dev/null
@@ -1,141 +0,0 @@
-package org.jetbrains.dokka.base.resolvers.local
-
-import org.jetbrains.dokka.DokkaConfiguration
-import org.jetbrains.dokka.base.DokkaBase
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.model.DisplaySourceSet
-import org.jetbrains.dokka.model.sourceSetIDs
-import org.jetbrains.dokka.plugability.DokkaContext
-import org.jetbrains.dokka.plugability.plugin
-import org.jetbrains.dokka.plugability.query
-import java.net.HttpURLConnection
-import java.net.URL
-import java.net.URLConnection
-import java.util.concurrent.locks.ReentrantReadWriteLock
-import kotlin.concurrent.read
-import kotlin.concurrent.write
-
-abstract class BaseLocationProvider(protected val dokkaContext: DokkaContext) : LocationProvider {
-
- protected val externalLocationProviderFactories =
- dokkaContext.plugin<DokkaBase>().query { externalLocationProviderFactory }
- private val cache: MutableMap<URL, DefaultLocationProvider.LocationInfo> = mutableMapOf()
- private val lock = ReentrantReadWriteLock()
-
- protected fun getExternalLocation(
- dri: DRI,
- sourceSets: Set<DisplaySourceSet>
- ): String? {
- val jdkToExternalDocumentationLinks = dokkaContext.configuration.sourceSets
- .filter { sourceSet -> sourceSet.sourceSetID in sourceSets.sourceSetIDs }
- .groupBy({ it.jdkVersion }, { it.externalDocumentationLinks })
- .map { it.key to it.value.flatten().distinct() }.toMap()
-
- val toResolve: MutableMap<Int, MutableList<DokkaConfiguration.ExternalDocumentationLink>> = mutableMapOf()
- for ((jdk, links) in jdkToExternalDocumentationLinks) {
- for (link in links) {
- val info = lock.read { cache[link.packageListUrl] }
- if (info == null) {
- toResolve.getOrPut(jdk) { mutableListOf() }.add(link)
- } else if (info.packages.contains(dri.packageName)) {
- return link.url.toExternalForm() + getLink(dri, info)
- }
- }
- }
- // Not in cache, resolve packageLists
- for ((jdk, links) in toResolve) {
- for (link in links) {
- if (dokkaContext.configuration.offlineMode && link.packageListUrl.protocol.toLowerCase() != "file")
- continue
- val locationInfo =
- loadPackageList(jdk, link.packageListUrl)
- if (locationInfo.packages.contains(dri.packageName)) {
- return link.url.toExternalForm() + getLink(dri, locationInfo)
- }
- }
- toResolve.remove(jdk)
- }
- return null
- }
-
- private fun getLink(dri: DRI, locationInfo: DefaultLocationProvider.LocationInfo): String =
- locationInfo.locations[dri.packageName + "." + dri.classNames]
- ?: // Not sure if it can be here, previously it shadowed only kotlin/dokka related sources, here it shadows both dokka/javadoc, cause I cannot distinguish what LocationProvider has been hypothetically chosen
- if (locationInfo.externalLocationProvider != null)
- with(locationInfo.externalLocationProvider) {
- dri.toLocation()
- }
- else
- throw IllegalStateException("Have not found any convenient ExternalLocationProvider for $dri DRI!")
-
- private fun loadPackageList(jdk: Int, url: URL): DefaultLocationProvider.LocationInfo = lock.write {
- val packageListStream = url.doOpenConnectionToReadContent().getInputStream()
- val (params, packages) =
- packageListStream
- .bufferedReader()
- .useLines { lines -> lines.partition { it.startsWith(DOKKA_PARAM_PREFIX) } }
-
- val paramsMap = params.asSequence()
- .map { it.removePrefix(DOKKA_PARAM_PREFIX).split(":", limit = 2) }
- .groupBy({ (key, _) -> key }, { (_, value) -> value })
-
- val format = paramsMap["format"]?.singleOrNull() ?: when {
- jdk < 8 -> "javadoc1" // Covers JDK 1 - 7
- jdk < 10 -> "javadoc8" // Covers JDK 8 - 9
- else -> "javadoc10" // Covers JDK 10+
- }
-
- val locations = paramsMap["location"].orEmpty()
- .map { it.split("\u001f", limit = 2) }
- .map { (key, value) -> key to value }
- .toMap()
-
- val externalLocationProvider =
- externalLocationProviderFactories.asSequence().map { it.getExternalLocationProvider(format) }
- .filterNotNull().take(1).firstOrNull()
-
- val info = DefaultLocationProvider.LocationInfo(
- externalLocationProvider,
- packages.toSet(),
- locations
- )
- cache[url] = info
- return info
- }
-
- private fun URL.doOpenConnectionToReadContent(timeout: Int = 10000, redirectsAllowed: Int = 16): URLConnection {
- val connection = this.openConnection().apply {
- connectTimeout = timeout
- readTimeout = timeout
- }
-
- when (connection) {
- is HttpURLConnection -> {
- return when (connection.responseCode) {
- in 200..299 -> {
- connection
- }
- HttpURLConnection.HTTP_MOVED_PERM,
- HttpURLConnection.HTTP_MOVED_TEMP,
- HttpURLConnection.HTTP_SEE_OTHER -> {
- if (redirectsAllowed > 0) {
- val newUrl = connection.getHeaderField("Location")
- URL(newUrl).doOpenConnectionToReadContent(timeout, redirectsAllowed - 1)
- } else {
- throw RuntimeException("Too many redirects")
- }
- }
- else -> {
- throw RuntimeException("Unhandled http code: ${connection.responseCode}")
- }
- }
- }
- else -> return connection
- }
- }
-
- companion object {
- const val DOKKA_PARAM_PREFIX = "\$dokka."
- }
-
-}
diff --git a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt
index 1c27959f..1e20dc7e 100644
--- a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt
+++ b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt
@@ -1,217 +1,51 @@
package org.jetbrains.dokka.base.resolvers.local
-import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
import org.jetbrains.dokka.base.resolvers.external.ExternalLocationProvider
+import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentationInfo
+import org.jetbrains.dokka.base.resolvers.shared.PackageList
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.DisplaySourceSet
import org.jetbrains.dokka.model.withDescendants
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.plugability.DokkaContext
-import java.net.HttpURLConnection
-import java.net.URL
-import java.net.URLConnection
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.query
import java.util.*
-private const val PAGE_WITH_CHILDREN_SUFFIX = "index"
-
-open class DefaultLocationProvider(
+abstract class DefaultLocationProvider(
protected val pageGraphRoot: RootPageNode,
- dokkaContext: DokkaContext
-) : BaseLocationProvider(dokkaContext) {
- protected open val extension = ".html"
-
- protected val pagesIndex: Map<DRI, ContentPage> = pageGraphRoot.withDescendants().filterIsInstance<ContentPage>()
- .map { it.dri.map { dri -> dri to it } }.flatten()
- .groupingBy { it.first }
- .aggregate { dri, _, (_, page), first ->
- if (first) page else throw AssertionError("Multiple pages associated with dri: $dri")
- }
-
- protected val anchorsIndex = pageGraphRoot.withDescendants().filterIsInstance<ContentPage>()
- .flatMap { page ->
- page.content.withDescendants()
- .filter { it.extra[SymbolAnchorHint] != null }
- .mapNotNull { it.dci.dri.singleOrNull() }
- .distinct()
- .map { it to page }
- }.toMap()
-
-
- protected val pathsIndex: Map<PageNode, List<String>> = IdentityHashMap<PageNode, List<String>>().apply {
- fun registerPath(page: PageNode, prefix: List<String>) {
- val newPrefix = prefix + page.pathName
- put(page, newPrefix)
- page.children.forEach { registerPath(it, newPrefix) }
- }
- put(pageGraphRoot, emptyList())
- pageGraphRoot.children.forEach { registerPath(it, emptyList()) }
- }
-
- override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean) =
- pathTo(node, context) + if (!skipExtension) extension else ""
-
- override fun resolve(dri: DRI, sourceSets: Set<DisplaySourceSet>, context: PageNode?) =
- pagesIndex[dri]?.let { resolve(it, context) }
- ?: anchorsIndex[dri]?.let { resolve(it, context) + "#$dri" }
- // Not found in PageGraph, that means it's an external link
- ?: getExternalLocation(dri, sourceSets)
-
- override fun resolveRoot(node: PageNode): String =
- pathTo(pageGraphRoot, node).removeSuffix(PAGE_WITH_CHILDREN_SUFFIX)
-
- override fun ancestors(node: PageNode): List<PageNode> =
- generateSequence(node) { it.parent() }.toList()
-
- protected open fun pathTo(node: PageNode, context: PageNode?): String {
- fun pathFor(page: PageNode) = pathsIndex[page] ?: throw AssertionError(
- "${page::class.simpleName}(${page.name}) does not belong to current page graph so it is impossible to compute its path"
- )
-
- val contextNode =
- if (context !is ClasslikePageNode && context?.children?.isEmpty() == true && context.parent() != null) context.parent() else context
- val nodePath = pathFor(node)
- val contextPath = contextNode?.let { pathFor(it) }.orEmpty()
-
- val commonPathElements = nodePath.asSequence().zip(contextPath.asSequence())
- .takeWhile { (a, b) -> a == b }.count()
-
- return (List(contextPath.size - commonPathElements) { ".." } + nodePath.drop(commonPathElements) +
- if (node is ClasslikePageNode || node.children.isNotEmpty())
- listOf(PAGE_WITH_CHILDREN_SUFFIX)
- else
- emptyList()
- ).joinToString("/")
- }
-
- private fun PageNode.parent() = pageGraphRoot.parentMap[this]
-
- private val cache: MutableMap<URL, LocationInfo> = mutableMapOf()
-
- private fun getLocation(
- dri: DRI,
- jdkToExternalDocumentationLinks: Map<Int, List<DokkaConfiguration.ExternalDocumentationLink>>
- ): String {
- val toResolve: MutableMap<Int, MutableList<DokkaConfiguration.ExternalDocumentationLink>> = mutableMapOf()
- for ((jdk, links) in jdkToExternalDocumentationLinks) {
- for (link in links) {
- val info = cache[link.packageListUrl]
- if (info == null) {
- toResolve.getOrPut(jdk) { mutableListOf() }.add(link)
- } else if (info.packages.contains(dri.packageName)) {
- return link.url.toExternalForm() + getLink(dri, info)
- }
- }
- }
- // Not in cache, resolve packageLists
- for ((jdk, links) in toResolve) {
- for (link in links) {
- if(dokkaContext.configuration.offlineMode && link.packageListUrl.protocol.toLowerCase() != "file")
- continue
- val locationInfo =
- loadPackageList(jdk, link.packageListUrl)
- if (locationInfo.packages.contains(dri.packageName)) {
- return link.url.toExternalForm() + getLink(dri, locationInfo)
- }
+ protected val dokkaContext: DokkaContext,
+ protected val extension: String
+) : LocationProvider {
+ protected val externalLocationProviderFactories =
+ dokkaContext.plugin<DokkaBase>().query { externalLocationProviderFactory }
+
+ protected val packagesIndex: Map<String, ExternalLocationProvider?> = dokkaContext
+ .configuration
+ .sourceSets
+ .flatMap { sourceSet ->
+ sourceSet.externalDocumentationLinks.map {
+ PackageList.load(it.packageListUrl, sourceSet.jdkVersion, dokkaContext)
+ ?.let { packageList -> ExternalDocumentationInfo(it.url, packageList) }
}
- toResolve.remove(jdk)
- }
- return ""
- }
-
- private fun getLink(dri: DRI, locationInfo: LocationInfo): String =
- locationInfo.locations[dri.packageName + "." + dri.classNames]
- ?: // Not sure if it can be here, previously it shadowed only kotlin/dokka related sources, here it shadows both dokka/javadoc, cause I cannot distinguish what LocationProvider has been hypothetically chosen
- if (locationInfo.externalLocationProvider != null)
- with(locationInfo.externalLocationProvider) {
- dri.toLocation()
- }
- else
- throw IllegalStateException("Have not found any convenient ExternalLocationProvider for $dri DRI!")
-
- private fun loadPackageList(jdk: Int, url: URL): LocationInfo {
- val packageListStream = url.doOpenConnectionToReadContent().getInputStream()
- val (params, packages) =
- packageListStream
- .bufferedReader()
- .useLines { lines -> lines.partition { it.startsWith(DOKKA_PARAM_PREFIX) } }
-
- val paramsMap = params.asSequence()
- .map { it.removePrefix(DOKKA_PARAM_PREFIX).split(":", limit = 2) }
- .groupBy({ (key, _) -> key }, { (_, value) -> value })
-
- val format = paramsMap["format"]?.singleOrNull() ?: when {
- jdk < 8 -> "javadoc1" // Covers JDK 1 - 7
- jdk < 10 -> "javadoc8" // Covers JDK 8 - 9
- else -> "javadoc10" // Covers JDK 10+
}
-
- val locations = paramsMap["location"].orEmpty()
- .map { it.split("\u001f", limit = 2) }
- .map { (key, value) -> key to value }
- .toMap()
-
- val externalLocationProvider =
- externalLocationProviderFactories.asSequence().map { it.getExternalLocationProvider(format) }
- .filterNotNull().take(1).firstOrNull()
-
- val info = LocationInfo(
- externalLocationProvider,
- packages.toSet(),
- locations
- )
- cache[url] = info
- return info
- }
-
- private fun URL.doOpenConnectionToReadContent(timeout: Int = 10000, redirectsAllowed: Int = 16): URLConnection {
- val connection = this.openConnection().apply {
- connectTimeout = timeout
- readTimeout = timeout
- }
-
- when (connection) {
- is HttpURLConnection -> {
- return when (connection.responseCode) {
- in 200..299 -> {
- connection
- }
- HttpURLConnection.HTTP_MOVED_PERM,
- HttpURLConnection.HTTP_MOVED_TEMP,
- HttpURLConnection.HTTP_SEE_OTHER -> {
- if (redirectsAllowed > 0) {
- val newUrl = connection.getHeaderField("Location")
- URL(newUrl).doOpenConnectionToReadContent(timeout, redirectsAllowed - 1)
- } else {
- throw RuntimeException("Too many redirects")
- }
- }
- else -> {
- throw RuntimeException("Unhandled http code: ${connection.responseCode}")
- }
- }
+ .filterNotNull()
+ .flatMap { extDocInfo ->
+ extDocInfo.packageList.packages.map { packageName ->
+ val externalLocationProvider = (externalLocationProviderFactories.asSequence()
+ .mapNotNull { it.getExternalLocationProvider(extDocInfo) }.firstOrNull()
+ ?: run { dokkaContext.logger.error("No ExternalLocationProvider for '${extDocInfo.packageList.url}' found"); null })
+ run { null }
+ packageName to externalLocationProvider
}
- else -> return connection
}
- }
-
- data class LocationInfo(
- val externalLocationProvider: ExternalLocationProvider?,
- val packages: Set<String>,
- val locations: Map<String, String>
- )
-}
-
-private val reservedFilenames = setOf("index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out")
+ .toMap()
+ .filterKeys(String::isNotBlank)
-internal fun identifierToFilename(name: String): String {
- if (name.isEmpty()) return "--root--"
- val escaped = name.replace("<|>".toRegex(), "-")
- val lowercase = escaped.replace("[A-Z]".toRegex()) { matchResult -> "-" + matchResult.value.toLowerCase() }
- return if (lowercase in reservedFilenames) "--$lowercase--" else lowercase
-}
+ protected open fun getExternalLocation(dri: DRI, sourceSets: Set<DokkaSourceSet>): String? =
+ packagesIndex[dri.packageName]?.resolve(dri)
-private val PageNode.pathName: String
- get() = if (this is PackagePageNode) name else identifierToFilename(
- name
- )
+} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt
new file mode 100644
index 00000000..4233ffa1
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt
@@ -0,0 +1,103 @@
+package org.jetbrains.dokka.base.resolvers.local
+
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.base.DokkaBase
+import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
+import org.jetbrains.dokka.base.resolvers.external.ExternalLocationProvider
+import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentationInfo
+import org.jetbrains.dokka.base.resolvers.shared.PackageList
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.withDescendants
+import org.jetbrains.dokka.pages.*
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.query
+import java.util.*
+
+open class DokkaLocationProvider(
+ pageGraphRoot: RootPageNode,
+ dokkaContext: DokkaContext,
+ extension: String = ".html"
+) : DefaultLocationProvider(pageGraphRoot, dokkaContext, extension) {
+ protected open val PAGE_WITH_CHILDREN_SUFFIX = "index"
+
+ protected open val pathsIndex: Map<PageNode, List<String>> = IdentityHashMap<PageNode, List<String>>().apply {
+ fun registerPath(page: PageNode, prefix: List<String>) {
+ val newPrefix = prefix + page.pathName
+ put(page, newPrefix)
+ page.children.forEach { registerPath(it, newPrefix) }
+ }
+ put(pageGraphRoot, emptyList())
+ pageGraphRoot.children.forEach { registerPath(it, emptyList()) }
+ }
+
+ protected open val pagesIndex: Map<DRI, ContentPage> = pageGraphRoot.withDescendants().filterIsInstance<ContentPage>()
+ .flatMap { it.dri.map { dri -> dri to it } }
+ .groupingBy { it.first }
+ .aggregate { dri, _, (_, page), first ->
+ if (first) page else throw AssertionError("Multiple pages associated with dri: $dri")
+ }
+
+ protected open val anchorsIndex = pageGraphRoot.withDescendants().filterIsInstance<ContentPage>()
+ .flatMap { page ->
+ page.content.withDescendants()
+ .filter { it.extra[SymbolAnchorHint] != null }
+ .mapNotNull { it.dci.dri.singleOrNull() }
+ .distinct()
+ .map { it to page }
+ }.toMap()
+
+ override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean) =
+ pathTo(node, context) + if (!skipExtension) extension else ""
+
+ override fun resolve(dri: DRI, sourceSets: Set<DokkaSourceSet>, context: PageNode?) =
+ pagesIndex[dri]?.let { resolve(it, context) }
+ ?: anchorsIndex[dri]?.let { resolve(it, context) + "#$dri" }
+ // Not found in PageGraph, that means it's an external link
+ ?: getExternalLocation(dri, sourceSets)
+
+ override fun pathToRoot(from: PageNode): String =
+ pathTo(pageGraphRoot, from).removeSuffix(PAGE_WITH_CHILDREN_SUFFIX)
+
+ override fun ancestors(node: PageNode): List<PageNode> =
+ generateSequence(node) { it.parent() }.toList()
+
+ protected open fun pathTo(node: PageNode, context: PageNode?): String {
+ fun pathFor(page: PageNode) = pathsIndex[page] ?: throw AssertionError(
+ "${page::class.simpleName}(${page.name}) does not belong to current page graph so it is impossible to compute its path"
+ )
+
+ val contextNode =
+ if (context !is ClasslikePageNode && context?.children?.isEmpty() == true && context.parent() != null) context.parent() else context
+ val nodePath = pathFor(node)
+ val contextPath = contextNode?.let { pathFor(it) }.orEmpty()
+
+ val commonPathElements = nodePath.asSequence().zip(contextPath.asSequence())
+ .takeWhile { (a, b) -> a == b }.count()
+
+ return (List(contextPath.size - commonPathElements) { ".." } + nodePath.drop(commonPathElements) +
+ if (node is ClasslikePageNode || node.children.isNotEmpty())
+ listOf(PAGE_WITH_CHILDREN_SUFFIX)
+ else
+ emptyList()
+ ).joinToString("/")
+ }
+
+ private fun PageNode.parent() = pageGraphRoot.parentMap[this]
+
+ private val PageNode.pathName: String
+ get() = if (this is PackagePageNode) name else identifierToFilename(name)
+
+ companion object {
+ internal val reservedFilenames = setOf("index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out")
+
+ internal fun identifierToFilename(name: String): String {
+ if (name.isEmpty()) return "--root--"
+ val escaped = name.replace("[<>]".toRegex(), "-")
+ val lowercase = escaped.replace("[A-Z]".toRegex()) { matchResult -> "-" + matchResult.value.toLowerCase() }
+ return if (lowercase in reservedFilenames) "--$lowercase--" else lowercase
+ }
+ }
+}
+
+
diff --git a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProviderFactory.kt
index 442d2e6d..99cc0687 100644
--- a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProviderFactory.kt
+++ b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProviderFactory.kt
@@ -3,21 +3,18 @@ package org.jetbrains.dokka.base.resolvers.local
import org.jetbrains.dokka.pages.MultimoduleRootPageNode
import org.jetbrains.dokka.pages.RootPageNode
import org.jetbrains.dokka.plugability.DokkaContext
-import java.util.*
import java.util.concurrent.ConcurrentHashMap
-class DefaultLocationProviderFactory(private val context: DokkaContext) : LocationProviderFactory {
-
+class DokkaLocationProviderFactory(private val context: DokkaContext) : LocationProviderFactory {
private val cache = ConcurrentHashMap<CacheWrapper, LocationProvider>()
override fun getLocationProvider(pageNode: RootPageNode) = cache.computeIfAbsent(CacheWrapper(pageNode)) {
if (pageNode.children.first() is MultimoduleRootPageNode) MultimoduleLocationProvider(pageNode, context)
- else DefaultLocationProvider(pageNode, context)
+ else DokkaLocationProvider(pageNode, context)
}
-}
-
-private class CacheWrapper(val pageNode: RootPageNode) {
- override fun equals(other: Any?) = other is CacheWrapper && other.pageNode == this.pageNode
- override fun hashCode() = System.identityHashCode(pageNode)
-} \ No newline at end of file
+ private class CacheWrapper(val pageNode: RootPageNode) {
+ override fun equals(other: Any?) = other is CacheWrapper && other.pageNode == this.pageNode
+ override fun hashCode() = System.identityHashCode(pageNode)
+ }
+}
diff --git a/plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt
index 391af004..3775e94e 100644
--- a/plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt
+++ b/plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt
@@ -3,16 +3,10 @@ package org.jetbrains.dokka.base.resolvers.local
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.DisplaySourceSet
import org.jetbrains.dokka.pages.PageNode
-import org.jetbrains.dokka.pages.RootPageNode
interface LocationProvider {
fun resolve(dri: DRI, sourceSets: Set<DisplaySourceSet>, context: PageNode? = null): String?
fun resolve(node: PageNode, context: PageNode? = null, skipExtension: Boolean = false): String?
- fun resolveRoot(node: PageNode): String
+ fun pathToRoot(from: PageNode): String
fun ancestors(node: PageNode): List<PageNode>
}
-
-interface LocationProviderFactory {
- fun getLocationProvider(pageNode: RootPageNode): LocationProvider
-}
-
diff --git a/plugins/base/src/main/kotlin/resolvers/local/LocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/local/LocationProviderFactory.kt
new file mode 100644
index 00000000..fb72fc60
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/local/LocationProviderFactory.kt
@@ -0,0 +1,7 @@
+package org.jetbrains.dokka.base.resolvers.local
+
+import org.jetbrains.dokka.pages.RootPageNode
+
+interface LocationProviderFactory {
+ fun getLocationProvider(pageNode: RootPageNode): LocationProvider
+}
diff --git a/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt
index 5d2a96d5..f8c8fc6c 100644
--- a/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt
+++ b/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt
@@ -1,5 +1,7 @@
package org.jetbrains.dokka.base.resolvers.local
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProvider.Companion.identifierToFilename
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.DisplaySourceSet
import org.jetbrains.dokka.pages.PageNode
@@ -8,7 +10,7 @@ import org.jetbrains.dokka.plugability.DokkaContext
class MultimoduleLocationProvider(private val root: RootPageNode, context: DokkaContext) : LocationProvider {
- private val defaultLocationProvider = DefaultLocationProvider(root, context)
+ private val defaultLocationProvider = DokkaLocationProvider(root, context)
val paths = context.configuration.modules.map {
it.name to it.path
@@ -22,7 +24,7 @@ class MultimoduleLocationProvider(private val root: RootPageNode, context: Dokka
override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean) =
defaultLocationProvider.resolve(node, context, skipExtension)
- override fun resolveRoot(node: PageNode): String = defaultLocationProvider.resolveRoot(node)
+ override fun pathToRoot(from: PageNode): String = defaultLocationProvider.pathToRoot(from)
override fun ancestors(node: PageNode): List<PageNode> = listOf(root)
diff --git a/plugins/base/src/main/kotlin/resolvers/shared/ExternalDocumentationInfo.kt b/plugins/base/src/main/kotlin/resolvers/shared/ExternalDocumentationInfo.kt
new file mode 100644
index 00000000..473d46d1
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/shared/ExternalDocumentationInfo.kt
@@ -0,0 +1,5 @@
+package org.jetbrains.dokka.base.resolvers.shared
+
+import java.net.URL
+
+data class ExternalDocumentationInfo(val documentationURL: URL, val packageList: PackageList) \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/resolvers/shared/LinkFormat.kt b/plugins/base/src/main/kotlin/resolvers/shared/LinkFormat.kt
new file mode 100644
index 00000000..42be72c4
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/shared/LinkFormat.kt
@@ -0,0 +1,6 @@
+package org.jetbrains.dokka.base.resolvers.shared
+
+interface LinkFormat {
+ val formatName: String
+ val linkExtension: String
+} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/resolvers/shared/PackageList.kt b/plugins/base/src/main/kotlin/resolvers/shared/PackageList.kt
new file mode 100644
index 00000000..a9f0e618
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/shared/PackageList.kt
@@ -0,0 +1,42 @@
+package org.jetbrains.dokka.base.resolvers.shared
+
+import org.jetbrains.dokka.base.renderers.PackageListService
+import org.jetbrains.dokka.plugability.DokkaContext
+import java.net.URL
+
+data class PackageList(
+ val linkFormat: RecognizedLinkFormat,
+ val packages: Set<String>,
+ val locations: Map<String, String>,
+ val url: URL
+) {
+ companion object {
+ fun load(url: URL, jdkVersion: Int, dokkaContext: DokkaContext): PackageList? {
+ if (dokkaContext.configuration.offlineMode && url.protocol.toLowerCase() != "file")
+ return null
+
+ val packageListStream = url.doOpenConnectionToReadContent().getInputStream()
+ val (params, packages) =
+ packageListStream
+ .bufferedReader()
+ .useLines { lines -> lines.partition { it.startsWith(PackageListService.DOKKA_PARAM_PREFIX) } }
+
+ val paramsMap = params.asSequence()
+ .map { it.removePrefix("${PackageListService.DOKKA_PARAM_PREFIX}.").split(":", limit = 2) }
+ .groupBy({ (key, _) -> key }, { (_, value) -> value })
+
+ val format = paramsMap["format"]?.singleOrNull()?.let { RecognizedLinkFormat.fromString(it) } ?: when {
+ jdkVersion < 8 -> RecognizedLinkFormat.Javadoc1 // Covers JDK 1 - 7
+ jdkVersion < 10 -> RecognizedLinkFormat.Javadoc8 // Covers JDK 8 - 9
+ else -> RecognizedLinkFormat.Javadoc10 // Covers JDK 10+
+ }
+
+ val locations = paramsMap["location"].orEmpty()
+ .map { it.split("\u001f", limit = 2) }
+ .map { (key, value) -> key to value }
+ .toMap()
+
+ return PackageList(format, packages.toSet(), locations, url)
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/resolvers/shared/RecognizedLinkFormat.kt b/plugins/base/src/main/kotlin/resolvers/shared/RecognizedLinkFormat.kt
new file mode 100644
index 00000000..e8044b4f
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/shared/RecognizedLinkFormat.kt
@@ -0,0 +1,18 @@
+package org.jetbrains.dokka.base.resolvers.shared
+
+enum class RecognizedLinkFormat(override val formatName: String, override val linkExtension: String) : LinkFormat {
+ DokkaHtml("html-v1", "html"),
+ DokkaJavadoc("javadoc-v1", "html"),
+ DokkaGFM("gfm-v1", "md"),
+ DokkaJekyll("jekyll-v1", "md"),
+ Javadoc1("javadoc1", "html"),
+ Javadoc8("javadoc8", "html"),
+ Javadoc10("javadoc10", "html"),
+ DokkaOldHtml("html", "html"),
+ KotlinWebsiteHtml("kotlin-website-html", "html");
+
+ companion object {
+ fun fromString(formatName: String) =
+ values().asSequence().filter { it.formatName == formatName }.firstOrNull()
+ }
+} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/resolvers/shared/utils.kt b/plugins/base/src/main/kotlin/resolvers/shared/utils.kt
new file mode 100644
index 00000000..cb737041
--- /dev/null
+++ b/plugins/base/src/main/kotlin/resolvers/shared/utils.kt
@@ -0,0 +1,36 @@
+package org.jetbrains.dokka.base.resolvers.shared
+
+import java.net.HttpURLConnection
+import java.net.URL
+import java.net.URLConnection
+
+internal fun URL.doOpenConnectionToReadContent(timeout: Int = 10000, redirectsAllowed: Int = 16): URLConnection {
+ val connection = this.openConnection().apply {
+ connectTimeout = timeout
+ readTimeout = timeout
+ }
+
+ when (connection) {
+ is HttpURLConnection -> {
+ return when (connection.responseCode) {
+ in 200..299 -> {
+ connection
+ }
+ HttpURLConnection.HTTP_MOVED_PERM,
+ HttpURLConnection.HTTP_MOVED_TEMP,
+ HttpURLConnection.HTTP_SEE_OTHER -> {
+ if (redirectsAllowed > 0) {
+ val newUrl = connection.getHeaderField("Location")
+ URL(newUrl).doOpenConnectionToReadContent(timeout, redirectsAllowed - 1)
+ } else {
+ throw RuntimeException("Too many redirects")
+ }
+ }
+ else -> {
+ throw RuntimeException("Unhandled http code: ${connection.responseCode}")
+ }
+ }
+ }
+ else -> return connection
+ }
+}
diff --git a/plugins/base/src/test/kotlin/locationProvider/DefaultLocationProviderTest.kt b/plugins/base/src/test/kotlin/locationProvider/DefaultLocationProviderTest.kt
index a219fb04..89161080 100644
--- a/plugins/base/src/test/kotlin/locationProvider/DefaultLocationProviderTest.kt
+++ b/plugins/base/src/test/kotlin/locationProvider/DefaultLocationProviderTest.kt
@@ -1,7 +1,7 @@
package locationProvider
import org.jetbrains.dokka.plugability.DokkaContext
-import org.jetbrains.dokka.base.resolvers.local.DefaultLocationProvider
+import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProvider
import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest
import org.junit.jupiter.api.Assertions.assertNotEquals
import org.junit.jupiter.api.Test
@@ -33,7 +33,7 @@ class DefaultLocationProviderTest: AbstractCoreTest() {
}
pagesGenerationStage = { module ->
- val lp = DefaultLocationProvider(module, context!!)
+ val lp = DokkaLocationProvider(module, context!!)
assertNotEquals(lp.resolve(module.children.single()).removePrefix("/"), lp.resolve(module))
}
}
diff --git a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt
index eea4dc0c..4f55695d 100644
--- a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt
+++ b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt
@@ -5,9 +5,9 @@ import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.renderers.DefaultTabSortingStrategy
import org.jetbrains.dokka.base.renderers.RootCreator
-import org.jetbrains.dokka.base.resolvers.external.DokkaExternalLocationProviderFactory
-import org.jetbrains.dokka.base.resolvers.external.JavadocExternalLocationProviderFactory
-import org.jetbrains.dokka.base.resolvers.local.DefaultLocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.external.javadoc.JavadocExternalLocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProviderFactory
import org.jetbrains.dokka.testApi.context.MockContext
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
@@ -46,10 +46,10 @@ abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase<Element>() {
val files = TestOutputWriter()
override val context = MockContext(
DokkaBase().outputWriter to { _ -> files },
- DokkaBase().locationProviderFactory to ::DefaultLocationProviderFactory,
+ DokkaBase().locationProviderFactory to ::DokkaLocationProviderFactory,
DokkaBase().htmlPreprocessors to { _ -> RootCreator },
DokkaBase().externalLocationProviderFactory to { ::JavadocExternalLocationProviderFactory },
- DokkaBase().externalLocationProviderFactory to { ::DokkaExternalLocationProviderFactory },
+ DokkaBase().externalLocationProviderFactory to { ::DefaultExternalLocationProviderFactory },
DokkaBase().tabSortingStrategy to { DefaultTabSortingStrategy() },
testConfiguration = DokkaConfigurationImpl(
sourceSets = listOf(js, jvm, native)
diff --git a/plugins/build.gradle.kts b/plugins/build.gradle.kts
index 7dba6385..6ce58a47 100644
--- a/plugins/build.gradle.kts
+++ b/plugins/build.gradle.kts
@@ -1,4 +1,5 @@
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
+import org.gradle.api.tasks.testing.logging.TestLogEvent
subprojects {
apply {
@@ -20,7 +21,10 @@ subprojects {
useJUnitPlatform()
testLogging {
exceptionFormat = TestExceptionFormat.FULL
- events( "skipped", "failed")
+ events(TestLogEvent.SKIPPED, TestLogEvent.FAILED)
+ showExceptions = true
+ showCauses = true
+ showStackTraces = true
}
}
} \ No newline at end of file
diff --git a/plugins/gfm/src/main/kotlin/GfmPlugin.kt b/plugins/gfm/src/main/kotlin/GfmPlugin.kt
index 3cec8320..c758467a 100644
--- a/plugins/gfm/src/main/kotlin/GfmPlugin.kt
+++ b/plugins/gfm/src/main/kotlin/GfmPlugin.kt
@@ -5,9 +5,10 @@ import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.renderers.DefaultRenderer
import org.jetbrains.dokka.base.renderers.PackageListCreator
import org.jetbrains.dokka.base.renderers.RootCreator
-import org.jetbrains.dokka.base.resolvers.local.DefaultLocationProvider
+import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProvider
import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory
import org.jetbrains.dokka.model.DisplaySourceSet
+import org.jetbrains.dokka.base.resolvers.shared.RecognizedLinkFormat
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.DokkaPlugin
@@ -39,7 +40,7 @@ class GfmPlugin : DokkaPlugin() {
val packageListCreator by extending {
(gfmPreprocessors
- providing { PackageListCreator(it, "gfm", "md") }
+ providing { PackageListCreator(it, RecognizedLinkFormat.DokkaGFM) }
order { after(rootCreator) })
}
}
@@ -355,9 +356,8 @@ class MarkdownLocationProviderFactory(val context: DokkaContext) : LocationProvi
class MarkdownLocationProvider(
pageGraphRoot: RootPageNode,
dokkaContext: DokkaContext
-) : DefaultLocationProvider(
+) : DokkaLocationProvider(
pageGraphRoot,
- dokkaContext
-) {
- override val extension = ".md"
-}
+ dokkaContext,
+".md"
+) \ No newline at end of file
diff --git a/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt b/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt
index 7c9590c6..35c2da3d 100644
--- a/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt
+++ b/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt
@@ -6,8 +6,8 @@ import org.jetbrains.dokka.gfm.MarkdownLocationProviderFactory
import org.jetbrains.dokka.testApi.context.MockContext
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.renderers.RootCreator
-import org.jetbrains.dokka.base.resolvers.external.DokkaExternalLocationProviderFactory
-import org.jetbrains.dokka.base.resolvers.external.JavadocExternalLocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProviderFactory
+import org.jetbrains.dokka.base.resolvers.external.javadoc.JavadocExternalLocationProviderFactory
import renderers.RenderingOnlyTestBase
import utils.TestOutputWriter
@@ -18,7 +18,7 @@ abstract class GfmRenderingOnlyTestBase : RenderingOnlyTestBase<String>() {
DokkaBase().outputWriter to { _ -> files },
DokkaBase().locationProviderFactory to ::MarkdownLocationProviderFactory,
DokkaBase().externalLocationProviderFactory to { ::JavadocExternalLocationProviderFactory },
- DokkaBase().externalLocationProviderFactory to { ::DokkaExternalLocationProviderFactory },
+ DokkaBase().externalLocationProviderFactory to { ::DefaultExternalLocationProviderFactory },
GfmPlugin().gfmPreprocessors to { _ -> RootCreator },
testConfiguration = DokkaConfigurationImpl()
diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProvider.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProvider.kt
index 9b0d8b04..3359b32f 100644
--- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProvider.kt
+++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProvider.kt
@@ -1,7 +1,8 @@
package org.jetbrains.dokka.javadoc.location
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.base.resolvers.local.DefaultLocationProvider
import org.jetbrains.dokka.javadoc.pages.*
-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
@@ -14,7 +15,7 @@ import org.jetbrains.dokka.plugability.DokkaContext
import java.util.*
class JavadocLocationProvider(pageRoot: RootPageNode, dokkaContext: DokkaContext) :
- BaseLocationProvider(dokkaContext) {
+ DefaultLocationProvider(pageRoot, dokkaContext, ".html") {
private val pathIndex = IdentityHashMap<PageNode, List<String>>().apply {
fun registerPath(page: PageNode, prefix: List<String> = emptyList()) {
@@ -64,8 +65,8 @@ class JavadocLocationProvider(pageRoot: RootPageNode, dokkaContext: DokkaContext
private fun JavadocClasslikePageNode.findAnchorableByDRI(dri: DRI): AnchorableJavadocNode? =
(constructors + methods + entries + properties).firstOrNull { it.dri == dri }
- override fun resolve(dri: DRI, sourceSets: Set<DisplaySourceSet>, context: PageNode?): String {
- return nodeIndex[dri]?.let { resolve(it, context) }
+ override fun resolve(dri: DRI, sourceSets: Set<DisplaySourceSet>, context: PageNode?) =
+ nodeIndex[dri]?.let { resolve(it, context) }
?: nodeIndex[dri.parent]?.takeIf { it is JavadocClasslikePageNode }?.let {
val anchor = when (val anchorElement = (it as? JavadocClasslikePageNode)?.findAnchorableByDRI(dri)) {
is JavadocFunctionNode -> anchorElement.getAnchor()
@@ -79,17 +80,18 @@ class JavadocLocationProvider(pageRoot: RootPageNode, dokkaContext: DokkaContext
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 TypeParameter -> bound.name
- is PrimitiveJavaType -> bound.name
- is UnresolvedBound -> bound.name
- is JavaObject -> "Object"
- else -> bound.toString()
- }
- })"
+ "$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 TypeParameter -> bound.name
+ is PrimitiveJavaType -> bound.name
+ is UnresolvedBound -> bound.name
+ is JavaObject -> "Object"
+ else -> bound.toString()
+ }
+ } + ")"
fun anchorForFunctionNode(node: JavadocFunctionNode) = node.getAnchor()
@@ -122,7 +124,7 @@ class JavadocLocationProvider(pageRoot: RootPageNode, dokkaContext: DokkaContext
}
}?.relativeTo(pathIndex[contextRoot].orEmpty())?.let { if (skipExtension) "$it.html" else it }.orEmpty()
- override fun resolveRoot(node: PageNode): String {
+ override fun pathToRoot(from: PageNode): String {
TODO("Not yet implemented")
}
diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProviderFactory.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProviderFactory.kt
index 7dd8abe1..1c4420f3 100644
--- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProviderFactory.kt
+++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProviderFactory.kt
@@ -5,7 +5,6 @@ import org.jetbrains.dokka.pages.RootPageNode
import org.jetbrains.dokka.plugability.DokkaContext
class JavadocLocationProviderFactory(private val context: DokkaContext) : LocationProviderFactory {
-
override fun getLocationProvider(pageNode: RootPageNode) =
JavadocLocationProvider(pageNode, context)
} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToHtmlTranslator.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToHtmlTranslator.kt
index 1e9a3d65..b5fdde33 100644
--- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToHtmlTranslator.kt
+++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToHtmlTranslator.kt
@@ -69,10 +69,9 @@ internal class JavadocContentToHtmlTranslator(
).joinToString(separator = " ") { htmlForContentNode(it, relative) }
private fun buildLinkFromNode(node: ContentDRILink, relative: PageNode?) =
- buildLink(
- locationProvider.resolve(node.address, node.sourceSets, relative),
- htmlForContentNodes(node.children, relative)
- )
+ locationProvider.resolve(node.address, node.sourceSets, relative)?.let {
+ buildLink(it, htmlForContentNodes(node.children, relative))
+ } ?: htmlForContentNodes(node.children, relative)
private fun buildLinkFromNode(node: ContentResolvedLink, relative: PageNode?) =
buildLink(node.address, htmlForContentNodes(node.children, relative))
diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/SearchScriptsCreator.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/SearchScriptsCreator.kt
index 736a1f93..e25a29fd 100644
--- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/SearchScriptsCreator.kt
+++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/SearchScriptsCreator.kt
@@ -57,7 +57,7 @@ class SearchScriptsCreator(private val locationProvider: JavadocLocationProvider
val modules = SearchData(moduleRecords = input.map {
SearchRecord(
l = it.name,
- url = locationProvider.resolve(it).formatToEndWithHtml()
+ url = locationProvider.resolve(it)?.formatToEndWithHtml()
)
})
val processablePackages = input.flatMap { it.children.filterIsInstance<JavadocPackagePageNode>() }
@@ -68,7 +68,7 @@ class SearchScriptsCreator(private val locationProvider: JavadocLocationProvider
val packages = input.map {
SearchRecord(
l = it.name,
- url = locationProvider.resolve(it).formatToEndWithHtml()
+ url = locationProvider.resolve(it)?.formatToEndWithHtml()
)
} + SearchRecord.allPackages
val types = input.flatMap {
@@ -86,7 +86,7 @@ class SearchScriptsCreator(private val locationProvider: JavadocLocationProvider
SearchRecord(
p = it.first.name,
l = it.second.name,
- url = locationProvider.resolve(it.second).formatToEndWithHtml()
+ url = locationProvider.resolve(it.second)?.formatToEndWithHtml()
)
} + allTypes
val updated = accumulator.copy(typeRecords = types)
diff --git a/plugins/jekyll/src/main/kotlin/JekyllPlugin.kt b/plugins/jekyll/src/main/kotlin/JekyllPlugin.kt
index 45afb072..81a49812 100644
--- a/plugins/jekyll/src/main/kotlin/JekyllPlugin.kt
+++ b/plugins/jekyll/src/main/kotlin/JekyllPlugin.kt
@@ -4,6 +4,7 @@ import org.jetbrains.dokka.CoreExtensions
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.renderers.PackageListCreator
import org.jetbrains.dokka.base.renderers.RootCreator
+import org.jetbrains.dokka.base.resolvers.shared.RecognizedLinkFormat
import org.jetbrains.dokka.gfm.CommonmarkRenderer
import org.jetbrains.dokka.gfm.GfmPlugin
import org.jetbrains.dokka.pages.*
@@ -31,11 +32,7 @@ class JekyllPlugin : DokkaPlugin() {
val packageListCreator by extending {
jekyllPreprocessors providing {
- PackageListCreator(
- it,
- "jekyll",
- "md"
- )
+ PackageListCreator(it, RecognizedLinkFormat.DokkaJekyll)
} order { after(rootCreator) }
}
}