diff options
14 files changed, 293 insertions, 187 deletions
diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 8144c3cf..00000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="CompilerConfiguration"> - <wildcardResourcePatterns> - <entry name="!?*.java" /> - <entry name="!?*.form" /> - <entry name="!?*.class" /> - <entry name="!?*.groovy" /> - <entry name="!?*.scala" /> - <entry name="!?*.flex" /> - <entry name="!?*.kt" /> - <entry name="!?*.clj" /> - </wildcardResourcePatterns> - <bytecodeTargetLevel target="1.8" /> - </component> -</project>
\ 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 new file mode 100644 index 00000000..ab633fdc --- /dev/null +++ b/plugins/base/src/main/kotlin/resolvers/local/BaseLocationProvider.kt @@ -0,0 +1,141 @@ +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.links.DRI +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.query +import java.lang.IllegalStateException +import java.net.HttpURLConnection +import java.net.URL +import java.net.URLConnection + +abstract class BaseLocationProvider(protected val dokkaContext: DokkaContext) : LocationProvider { + + protected val externalLocationProviderFactories = + dokkaContext.plugin<DokkaBase>().query { externalLocationProviderFactory } + + protected fun getExternalLocation( + dri: DRI, + sourceSets: Set<DokkaSourceSet> + ): String { + val jdkToExternalDocumentationLinks = dokkaContext.configuration.sourceSets + .filter { sourceSet -> + sourceSets.contains(sourceSet) + } + .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 = 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 "" + } + + private val cache: MutableMap<URL, DefaultLocationProvider.LocationInfo> = mutableMapOf() + + + 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 { + 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." + } + +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt index 6c4869d8..e48aa926 100644 --- a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt +++ b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt @@ -2,30 +2,23 @@ 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.external.ExternalLocationProvider import org.jetbrains.dokka.links.DRI 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.net.HttpURLConnection import java.net.URL import java.net.URLConnection import java.util.* private const val PAGE_WITH_CHILDREN_SUFFIX = "index" -private const val DOKKA_PARAM_PREFIX = "\$dokka." open class DefaultLocationProvider( protected val pageGraphRoot: RootPageNode, - protected val dokkaContext: DokkaContext -) : LocationProvider { + dokkaContext: DokkaContext +) : BaseLocationProvider(dokkaContext) { protected open val extension = ".html" - protected val externalLocationProviderFactories = - dokkaContext.plugin<DokkaBase>().query { externalLocationProviderFactory } - protected val pagesIndex: Map<DRI, ContentPage> = pageGraphRoot.asSequence().filterIsInstance<ContentPage>() .map { it.dri.map { dri -> dri to it } }.flatten() .groupingBy { it.first } @@ -49,12 +42,7 @@ open class DefaultLocationProvider( override fun resolve(dri: DRI, sourceSets: Set<DokkaSourceSet>, context: PageNode?): String = pagesIndex[dri]?.let { resolve(it, context) } ?: // Not found in PageGraph, that means it's an external link - getLocation( - dri, - sourceSets - .groupBy({ it.jdkVersion }, { it.externalDocumentationLinks }) - .map { it.key to it.value.flatten().distinct() }.toMap() - ) + getExternalLocation(dri, sourceSets) override fun resolveRoot(node: PageNode): String = pathTo(pageGraphRoot, node).removeSuffix(PAGE_WITH_CHILDREN_SUFFIX) @@ -105,7 +93,7 @@ open class DefaultLocationProvider( // Not in cache, resolve packageLists for ((jdk, links) in toResolve) { for (link in links) { - if (dokkaContext.configuration.offlineMode && link.packageListUrl.protocol.toLowerCase() != "file") + if(dokkaContext.configuration.offlineMode && link.packageListUrl.protocol.toLowerCase() != "file") continue val locationInfo = loadPackageList(jdk, link.packageListUrl) diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt index 12c53ab7..767e0c68 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt @@ -17,7 +17,6 @@ import org.jetbrains.dokka.pages.ContentNode import org.jetbrains.dokka.pages.ContentText import org.jetbrains.dokka.pages.DCI import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.kotlin.utils.addToStdlib.safeAs open class JavadocPageCreator( commentsToContentConverter: CommentsToContentConverter, @@ -47,13 +46,22 @@ open class JavadocPageCreator( modifiers = listOfNotNull(c.visibility[jvm]?.name), signature = signatureProvider.signature(c).nodeForJvm(jvm), description = c.descriptionToContentNodes(), - constructors = c.safeAs<WithConstructors>()?.constructors?.map { it.toJavadocFunction(jvm) }.orEmpty(), - methods = c.functions.map { it.toJavadocFunction(jvm) }, - entries = c.safeAs<DEnum>()?.entries?.map { JavadocEntryNode(signatureProvider.signature(it).nodeForJvm(jvm), it.descriptionToContentNodes(jvm)) }.orEmpty(), + constructors = (c as? WithConstructors)?.constructors?.mapNotNull { it.toJavadocFunction() }.orEmpty(), + methods = c.functions.mapNotNull { it.toJavadocFunction() }, + entries = (c as? DEnum)?.entries?.map { + JavadocEntryNode( + signatureProvider.signature(it).nodeForJvm(jvm), it.descriptionToContentNodes(jvm) + ) + }.orEmpty(), classlikes = c.classlikes.mapNotNull { pageForClasslike(it) }, - properties = c.properties.map { JavadocPropertyNode(signatureProvider.signature(it).nodeForJvm(jvm), it.descriptionToContentNodes(jvm)) }, + properties = c.properties.map { + JavadocPropertyNode( + signatureProvider.signature(it).nodeForJvm(jvm), + it.descriptionToContentNodes(jvm) + ) + }, documentable = c, - extras = c.safeAs<WithExtraProperties<Documentable>>()?.extra ?: PropertyContainer.empty() + extras = (c as? WithExtraProperties<Documentable>)?.extra ?: PropertyContainer.empty() ) } @@ -61,7 +69,7 @@ open class JavadocPageCreator( JavadocContentGroup( setOf(m.dri), JavadocContentKind.OverviewSummary, - m.jvmSource.toSet() + m.jvmSourceSets.toSet() ) { title(m.name, m.brief(),"0.0.1", dri = setOf(m.dri), kind = ContentKind.Main) list("Packages", "Package", setOf(m.dri), ContentKind.Packages, m.packages.sortedBy { it.name }.map { p -> @@ -76,9 +84,9 @@ open class JavadocPageCreator( JavadocContentGroup( setOf(p.dri), JavadocContentKind.PackageSummary, - p.jvmSource.toSet() + p.jvmSourceSets.toSet() ) { - title(p.name, p.brief(),"0.0.1", dri = setOf(p.dri), kind = ContentKind.Packages) + title(p.name, p.brief(), "0.0.1", dri = setOf(p.dri), kind = ContentKind.Packages) list("Packages", "Package", setOf(p.dri), ContentKind.Packages, p.classlikes.sortedBy { it.name }.map { c -> RowJavadocListEntry( LinkJavadocListEntry(c.name.orEmpty(), setOf(c.dri), JavadocContentKind.Class, sourceSets), @@ -91,7 +99,7 @@ open class JavadocPageCreator( JavadocContentGroup( setOf(c.dri), JavadocContentKind.Class, - c.jvmSource.toSet() + c.jvmSourceSets.toSet() ) { title( c.name.orEmpty(), @@ -127,31 +135,34 @@ open class JavadocPageCreator( is UnresolvedBound -> p.name } - private fun DFunction.toJavadocFunction(sourceSetData: DokkaSourceSet) = JavadocFunctionNode( - name = name, - signature = signatureProvider.signature(this).nodeForJvm(sourceSetData), - brief = brief(sourceSetData), - parameters = parameters.map { - JavadocParameterNode( - name = it.name.orEmpty(), - type = signatureForProjection(it.type), - description = it.brief() - ) - }, - extras = extra - ) + private fun DFunction.toJavadocFunction() = highestJvmSourceSet?.let { jvm -> + JavadocFunctionNode( + name = name, + dri = dri, + signature = signatureProvider.signature(this).nodeForJvm(jvm), + brief = brief(jvm), + parameters = parameters.map { + JavadocParameterNode( + name = it.name.orEmpty(), + type = signatureForProjection(it.type), + description = it.brief() + ) + }, + extras = extra + ) + } - private val Documentable.jvmSource + private val Documentable.jvmSourceSets get() = sourceSets.filter { it.analysisPlatform == Platform.jvm } private val Documentable.highestJvmSourceSet - get() = jvmSource.let { sources -> - sources.firstOrNull { it != expectPresentInSet } ?: sources.firstOrNull() + 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? = + private inline fun <reified T : TagWrapper> Documentable.findNodeInDocumentation(sourceSetData: DokkaSourceSet?): T? = documentation[sourceSetData]?.firstChildOfType<T>() private fun Documentable.descriptionToContentNodes(sourceSet: DokkaSourceSet? = highestJvmSourceSet) = findNodeInDocumentation<Description>(sourceSet)?.let { @@ -169,7 +180,7 @@ open class JavadocPageCreator( val description = descriptionToContentNodes(sourceSet) val contents = mutableListOf<ContentNode>() for (node in description) { - if ( node is ContentText && firstSentenceRegex.containsMatchIn(node.text) ) { + if (node is ContentText && firstSentenceRegex.containsMatchIn(node.text)) { contents.add(node.copy(text = firstSentenceRegex.find(node.text)?.value.orEmpty())) break } else { diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt index 504eecfd..2d24bbf1 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt @@ -1,16 +1,21 @@ package org.jetbrains.dokka.javadoc import javadoc.JavadocDocumentableToPageTranslator +import javadoc.location.JavadocLocationProviderFactory import javadoc.renderer.KorteJavadocRenderer import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.base.resolvers.external.JavadocExternalLocationProviderFactory import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.kotlinAsJava.signatures.JavaSignatureProvider class JavadocPlugin : DokkaPlugin() { + + val dokkaBasePlugin by lazy { plugin<DokkaBase>() } + + val locationProviderFactory by extensionPoint<JavadocLocationProviderFactory>() + val dokkaJavadocPlugin by extending { - val dokkaBasePlugin = plugin<DokkaBase>() CoreExtensions.renderer providing { ctx -> KorteJavadocRenderer( dokkaBasePlugin.querySingle { outputWriter }, @@ -21,7 +26,6 @@ class JavadocPlugin : DokkaPlugin() { } val pageTranslator by extending { - val dokkaBasePlugin = plugin<DokkaBase>() CoreExtensions.documentableToPageTranslator providing { context -> JavadocDocumentableToPageTranslator( dokkaBasePlugin.querySingle { commentsToContentConverter }, @@ -30,5 +34,11 @@ class JavadocPlugin : DokkaPlugin() { ) } } + + val javadocLocationProviderFactory by extending { + locationProviderFactory providing { context -> + JavadocLocationProviderFactory(context) + } + } } diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt b/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt index d731ec5f..56a9015a 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt @@ -1,32 +1,19 @@ -package javadoc +package javadoc.location import javadoc.pages.* import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.Platform import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.resolvers.local.LocationProvider +import org.jetbrains.dokka.base.resolvers.local.BaseLocationProvider import org.jetbrains.dokka.links.DRI 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 org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.query -import java.nio.file.Paths import java.util.* -class JavadocLocationProvider(pageRoot: RootPageNode, private val context: DokkaContext) : LocationProvider { - private val externalLocationProviderFactories = - context.plugin<DokkaBase>().query { externalLocationProviderFactory } - private val externalLocationProvider = - externalLocationProviderFactories.asSequence().map { it.getExternalLocationProvider("javadoc10") } - .filterNotNull().take(1).firstOrNull() - private val externalDocumentationLinks by lazy { - context.configuration.sourceSets - .filter { sourceSet -> sourceSet.analysisPlatform == Platform.jvm } - .flatMap { it.externalDocumentationLinks } - .distinct() - } +class JavadocLocationProvider(pageRoot: RootPageNode, private val context: DokkaContext) : BaseLocationProvider(context) { private val pathIndex = IdentityHashMap<PageNode, List<String>>().apply { fun registerPath(page: PageNode, prefix: List<String> = emptyList()) { @@ -54,10 +41,9 @@ class JavadocLocationProvider(pageRoot: RootPageNode, private val context: Dokka pageRoot.children.forEach { registerPath(it) } } - private val nodeIndex = IdentityHashMap<DRI, PageNode>().apply { + 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) @@ -65,24 +51,27 @@ class JavadocLocationProvider(pageRoot: RootPageNode, private val context: Dokka 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("/") + } + override fun resolve(dri: DRI, sourceSets: Set<DokkaSourceSet>, context: PageNode?): String = - context?.let { resolve(it, skipExtension = false) } ?: nodeIndex[dri]?.let { - resolve(it, skipExtension = true) - } ?: with(externalLocationProvider!!) { - dri.toLocation() - } + nodeIndex[dri]?.let { resolve(it, context) } + ?: getExternalLocation(dri, sourceSets) override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean): String = - pathIndex[node]?.joinToString("/")?.let { + 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, dir: String = "", skipExtension: Boolean = true) = + fun resolve(link: LinkJavadocListEntry, contextRoot: PageNode? = null, skipExtension: Boolean = true) = pathIndex[link.dri.first()]?.let { when (link.kind) { - JavadocContentKind.Class -> it + JavadocContentKind.Class -> it JavadocContentKind.OverviewSummary -> it.dropLast(1) + "index" JavadocContentKind.PackageSummary -> it.dropLast(1) + "package-summary" JavadocContentKind.AllClasses -> it.dropLast(1) + "allclasses" @@ -90,9 +79,7 @@ class JavadocLocationProvider(pageRoot: RootPageNode, private val context: Dokka JavadocContentKind.PackageTree -> it.dropLast(1) + "package-tree" else -> it } - }?.joinToString("/")?.let { if (skipExtension) "$it.html" else it }?.let { - Paths.get(dir).relativize(Paths.get(it)).toString() - } ?: run { "" } //TODO just a glue to compile it on HMPP + }?.relativeTo(pathIndex[contextRoot].orEmpty())?.let { if (skipExtension) "$it.html" else it }.orEmpty() override fun resolveRoot(node: PageNode): String { TODO("Not yet implemented") diff --git a/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProviderFactory.kt b/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProviderFactory.kt new file mode 100644 index 00000000..b6bfb48d --- /dev/null +++ b/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProviderFactory.kt @@ -0,0 +1,11 @@ +package javadoc.location + +import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory +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/javadoc/pages/JavadocPageNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt index 5ac232d4..24e481e8 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt @@ -104,28 +104,10 @@ data class JavadocFunctionNode( val signature: ContentNode, val brief: List<ContentNode>, val parameters: List<JavadocParameterNode>, - override val name: String, - override val dri: Set<DRI> = emptySet(), - override val children: List<PageNode> = emptyList(), - override val documentable: Documentable? = null, - override val embeddedResources: List<String> = emptyList(), + val name: String, + val dri: DRI, val extras: PropertyContainer<DFunction> = PropertyContainer.empty() -) : JavadocPageNode { - - override val content: ContentNode = EmptyNode(DRI.topLevel, ContentKind.Classlikes, emptySet()) - - override fun modified( - name: String, - children: List<PageNode> - ): PageNode = TODO() - - override fun modified( - name: String, - content: ContentNode, - dri: Set<DRI>, - embeddedResources: List<String>, - children: List<PageNode> - ): ContentPage = TODO() +) { val modifiersAndSignature: Pair<ContentNode, ContentNode> get() = (signature as ContentGroup).splitSignatureIntoModifiersAndName() @@ -340,7 +322,6 @@ class TreeViewPage( listOf(psi to l) + l.flatMap { gatherPsiClasses(it) } } - val psiInheritanceTree = documentables.flatMap { (_, v) -> (v as? WithExpectActual)?.sources?.values.orEmpty() } .filterIsInstance<PsiDocumentableSource>().mapNotNull { it.psi as? PsiClass }.flatMap(::gatherPsiClasses) .flatMap { entry -> entry.second.map { it to entry.first } } diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt index 5f628626..7d6f37c0 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt @@ -1,41 +1,31 @@ package javadoc.renderer import javadoc.pages.TextNode -import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.base.resolvers.local.LocationProvider -import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext -import java.nio.file.Path -import java.nio.file.Paths internal class JavadocContentToHtmlTranslator( private val locationProvider: LocationProvider, private val context: DokkaContext ) { - fun <T> htmlForContentNode(node: ContentNode, relative: T?, locate: ContentDRILink.(T?) -> String): String = + fun htmlForContentNode(node: ContentNode, relative: PageNode?): String = when (node) { - is ContentGroup -> htmlForContentNodes(node.children, relative, locate) + is ContentGroup -> htmlForContentNodes(node.children, relative) is ContentText -> node.text is TextNode -> node.text is ContentDRILink -> buildLink( - node.locate(relative), - htmlForContentNodes(node.children, relative, locate) + locationProvider.resolve(node.address, node.sourceSets, relative), + htmlForContentNodes(node.children, relative) ) - is ContentResolvedLink -> buildLink(node.address, htmlForContentNodes(node.children, relative, locate)) + is ContentResolvedLink -> buildLink(node.address, htmlForContentNodes(node.children, relative)) is ContentCode -> htmlForCode(node.children) else -> "" } - fun <T> htmlForContentNodes(list: List<ContentNode>, relative: T?, locate: ContentDRILink.(T?) -> String) = - list.joinToString(separator = "") { htmlForContentNode(it, relative, locate) } - - private fun locate(link: ContentDRILink, relativePath: String?) = - resolveLink(link.address, link.sourceSets, relativePath) - - fun htmlForContentNodes(list: List<ContentNode>, relative: String?) = - htmlForContentNodes(list, relative, ::locate) + fun htmlForContentNodes(list: List<ContentNode>, relative: PageNode?) = + list.joinToString(separator = "") { htmlForContentNode(it, relative) } private fun htmlForCode(code: List<ContentNode>): String = code.map { element -> when (element) { @@ -45,16 +35,6 @@ internal class JavadocContentToHtmlTranslator( } }.joinToString("<br>", """<span class="code">""", "</span>") { it } - private fun resolveLink(address: DRI, sourceSets: Set<DokkaConfiguration.DokkaSourceSet>, relativePath: String?) = - locationProvider.resolve(address, sourceSets).let { - val afterFormattingToHtml = it.formatToEndWithHtml() - if (relativePath != null) afterFormattingToHtml.relativizePath(relativePath) - else afterFormattingToHtml - } - - private fun String.relativizePath(parent: String) = - Paths.get(parent).relativize(Paths.get(this)).normalize().toFile().toString() - companion object { fun buildLink(address: String, content: String) = diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt index 4d1ccca5..50a971ea 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt @@ -19,6 +19,7 @@ internal class JavadocContentToTemplateMapTranslator( mapOf<String, Any?>( "docName" to "docName", // todo docname "pathToRoot" to pathToRoot, + "contextRoot" to node, "kind" to "main", ) + templateMapForNode(node) @@ -27,7 +28,6 @@ internal class JavadocContentToTemplateMapTranslator( when (node) { is JavadocModulePageNode -> InnerTranslator(node).templateMapForJavadocContentNode(node.content) is JavadocClasslikePageNode -> InnerTranslator(node).templateMapForClasslikeNode(node) - is JavadocFunctionNode -> InnerTranslator(node).templateMapForFunctionNode(node) is JavadocPackagePageNode -> InnerTranslator(node).templateMapForPackagePageNode(node) is TreeViewPage -> InnerTranslator(node).templateMapForTreeViewPage(node) is AllClassesPage -> InnerTranslator(node).templateMapForAllClassesPage(node) @@ -65,19 +65,19 @@ internal class JavadocContentToTemplateMapTranslator( internal fun templateMapForFunctionNode(node: JavadocFunctionNode): TemplateMap { val (modifiers, signature) = node.modifiersAndSignature return mapOf( - "signature" to htmlForContentNode(node.signature, node), - "brief" to htmlForContentNodes(node.brief, node), + "signature" to htmlForContentNode(node.signature, contextNode), + "brief" to htmlForContentNodes(node.brief, contextNode), "parameters" to node.parameters.map { templateMapForParameterNode(it) }, "inlineParameters" to node.parameters.joinToString { "${it.type} ${it.name}" }, - "modifiers" to htmlForContentNode(modifiers, node), - "signatureWithoutModifiers" to htmlForContentNode(signature, node), + "modifiers" to htmlForContentNode(modifiers, contextNode), + "signatureWithoutModifiers" to htmlForContentNode(signature, contextNode), "name" to node.name ) } internal fun templateMapForClasslikeNode(node: JavadocClasslikePageNode): TemplateMap = mapOf( - "constructors" to node.constructors.map { templateMapForNode(it) }, + "constructors" to node.constructors.map { templateMapForFunctionNode(it) }, "signature" to htmlForContentNode(node.signature, node), "methods" to templateMapForClasslikeMethods(node.methods), "classlikeDocumentation" to htmlForContentNodes(node.description, node), @@ -113,12 +113,12 @@ internal class JavadocContentToTemplateMapTranslator( private fun templateMapForClasslikeMethods(nodes: List<JavadocFunctionNode>): TemplateMap { val (inherited, own) = nodes.partition { val extra = it.extras[InheritedFunction] - extra?.inheritedFrom?.keys?.first { it.analysisPlatform == Platform.jvm }?.let { jvm -> + extra?.inheritedFrom?.keys?.firstOrNull { it.analysisPlatform == Platform.jvm }?.let { jvm -> extra.isInherited(jvm) } ?: false } return mapOf( - "own" to own.map { templateMapForNode(it) }, + "own" to own.map { templateMapForFunctionNode(it) }, "inherited" to inherited.map { templateMapForInheritedMethod(it) } .groupBy { it["inheritedFrom"] as String }.entries.map { mapOf( @@ -188,14 +188,12 @@ internal class JavadocContentToTemplateMapTranslator( "list" to node.children ) } - fun locate(link: ContentDRILink, relativeNode: PageNode?) = - locationProvider.resolve(link.address, link.sourceSets, relativeNode) private fun htmlForContentNode(node: ContentNode, relativeNode: PageNode) = - htmlTranslator.htmlForContentNode(node, relativeNode, ::locate) + htmlTranslator.htmlForContentNode(node, relativeNode) private fun htmlForContentNodes(nodes: List<ContentNode>, relativeNode: PageNode) = - htmlTranslator.htmlForContentNodes(nodes, relativeNode, ::locate) + htmlTranslator.htmlForContentNodes(nodes, relativeNode) } private fun DRI.displayable(): String = "${packageName}.${sureClassNames}" diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt index 7b122b7d..a7d18100 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt @@ -1,7 +1,7 @@ package javadoc.renderer import com.soywiz.korte.* -import javadoc.JavadocLocationProvider +import javadoc.location.JavadocLocationProvider import javadoc.pages.* import javadoc.renderer.JavadocContentToHtmlTranslator.Companion.buildLink import kotlinx.coroutines.CoroutineScope @@ -9,9 +9,12 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.jetbrains.dokka.base.renderers.OutputWriter +import org.jetbrains.dokka.javadoc.JavadocPlugin import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.renderers.Renderer import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.nio.file.Path @@ -20,14 +23,22 @@ import java.time.LocalDate typealias TemplateMap = Map<String, Any?> -class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaContext, val resourceDir: String) : +class KorteJavadocRenderer(private val outputWriter: OutputWriter, val context: DokkaContext, resourceDir: String) : Renderer { private lateinit var locationProvider: JavadocLocationProvider - override fun render(root: RootPageNode) = root.let { preprocessors.fold(root) { r, t -> t.invoke(r) } }.let { r -> - locationProvider = JavadocLocationProvider(r, context) + private val contentToHtmlTranslator by lazy { + JavadocContentToHtmlTranslator(locationProvider, context) + } + + private val contentToTemplateMapTranslator by lazy { + JavadocContentToTemplateMapTranslator(locationProvider, context) + } + + override fun render(root: RootPageNode) = root.let { preprocessors.fold(root) { r, t -> t.invoke(r) } }.let { newRoot -> + locationProvider = context.plugin<JavadocPlugin>().querySingle { locationProviderFactory }.getLocationProvider(newRoot) runBlocking(Dispatchers.IO) { - renderModulePageNode(r as JavadocModulePageNode) + renderModulePageNode(newRoot as JavadocModulePageNode) } } @@ -53,7 +64,7 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon val name = "index" val pathToRoot = "" - val contentMap = JavadocContentToTemplateMapTranslator(locationProvider, context).templateMapForPageNode(node, pathToRoot) + val contentMap = contentToTemplateMapTranslator.templateMapForPageNode(node, pathToRoot) writeFromTemplate(outputWriter, "$link/$name".toNormalized(), "tabPage.korte", contentMap.toList()) node.children.forEach { renderNode(it, link) } @@ -66,12 +77,12 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon if (it.isNotEmpty()) "$it/" else it } - val contentMap = JavadocContentToTemplateMapTranslator(locationProvider, context).templateMapForPageNode(node, pathToRoot) + val contentMap = contentToTemplateMapTranslator.templateMapForPageNode(node, pathToRoot) writeFromTemplate(outputWriter, link, templateForNode(node), contentMap.toList()) node.children.forEach { renderNode(it, link.toNormalized()) } } - fun CoroutineScope.renderSpecificPage(node: RendererSpecificPage, path: String) = launch { + private fun CoroutineScope.renderSpecificPage(node: RendererSpecificPage, path: String) = launch { when (val strategy = node.strategy) { is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, "") is RenderingStrategy.Write -> outputWriter.writeHtml(path, strategy.text) @@ -83,10 +94,10 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon } } - fun Pair<String, String>.pairToTag() = - """<th class="colFirst" scope="row">${first}</th>\n<td class="colLast">${second}</td>""" + private fun Pair<String, String>.pairToTag() = + """<th class="colFirst" scope="row">${first}</th><td class="colLast">${second}</td>""" - fun DRI.toLink(context: PageNode? = null) = locationProvider.resolve(this, emptySet(), context) + private fun DRI.toLink(context: PageNode? = null) = locationProvider.resolve(this, emptySet(), context) private fun Path.toNormalized() = this.normalize().toFile().toString() private fun String.toNormalized() = Paths.get(this).toNormalized() @@ -102,7 +113,7 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon writer.writeHtml(path, tmp) } - fun getTemplateConfig() = TemplateConfig().also { config -> + private fun getTemplateConfig() = TemplateConfig().also { config -> listOf( TeFunction("curDate") { LocalDate.now() }, TeFunction("jQueryVersion") { "3.1" }, @@ -111,18 +122,17 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon TeFunction("h1Title") { args -> if ((args.first() as? String) == "package") "title=\"Package\" " else "" }, TeFunction("createTabRow") { args -> val (link, doc) = args.first() as RowJavadocListEntry - val dir = args[1] as String? - val translator = JavadocContentToHtmlTranslator(locationProvider, context) + val contextRoot = args[1] as PageNode? (buildLink( - locationProvider.resolve(link, dir.orEmpty()), + locationProvider.resolve(link, contextRoot), link.name - ) to translator.htmlForContentNodes(doc, dir)).pairToTag().trim() + ) to contentToHtmlTranslator.htmlForContentNodes(doc, contextRoot)).pairToTag().trim() }, TeFunction("createListRow") { args -> val link = args.first() as LinkJavadocListEntry - val dir = args[1] as String? + val contextRoot = args[1] as PageNode? buildLink( - locationProvider.resolve(link, dir.orEmpty()), + locationProvider.resolve(link, contextRoot), link.name ) }, @@ -171,13 +181,14 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon } } - val config = getTemplateConfig() - val templateRenderer = Templates( + private val config = getTemplateConfig() + private val templateRenderer = Templates( ResourceTemplateProvider( resourceDir - ), config = config, cache = true) + ), config = config, cache = true + ) - class ResourceTemplateProvider(val basePath: String) : TemplateProvider { + private class ResourceTemplateProvider(val basePath: String) : TemplateProvider { override suspend fun get(template: String): String = javaClass.classLoader.getResourceAsStream("$basePath/$template")?.bufferedReader()?.lines()?.toArray() ?.joinToString("\n") ?: throw IllegalStateException("Template not found: $basePath/$template") diff --git a/plugins/javadoc/src/main/resources/views/components/indexTable.korte b/plugins/javadoc/src/main/resources/views/components/indexTable.korte index 8595a728..9ee387e1 100644 --- a/plugins/javadoc/src/main/resources/views/components/indexTable.korte +++ b/plugins/javadoc/src/main/resources/views/components/indexTable.korte @@ -6,7 +6,7 @@ </tr> <tbody> {% for item in list %} - <tr class="{{ rowColor(loop.index0) }}">{{ createTabRow(item, dir)|raw }}</tr> + <tr class="{{ rowColor(loop.index0) }}">{{ createTabRow(item, contextRoot)|raw }}</tr> {% end -%} </tbody> </table>
\ No newline at end of file diff --git a/plugins/javadoc/src/main/resources/views/listPage.korte b/plugins/javadoc/src/main/resources/views/listPage.korte index 981ceeb9..985f1d4d 100644 --- a/plugins/javadoc/src/main/resources/views/listPage.korte +++ b/plugins/javadoc/src/main/resources/views/listPage.korte @@ -5,7 +5,7 @@ <main role="main" class="indexContainer"> <ul> {% for item in list %} - <li>{{ createListRow(item, dir)|raw }}</li> + <li>{{ createListRow(item, contextRoot)|raw }}</li> {% end -%} </ul> </main> diff --git a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt index c6fcb9b0..ca817219 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt @@ -117,16 +117,20 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge val returnType = f.type signatureForProjection(returnType) text(nbsp.toString()) - link(f.name, f.dri) - list(f.generics, prefix = "<", suffix = ">") { - +buildSignature(it) - } - list(f.parameters, "(", ")") { - annotationsInline(it) - text(it.modifiers()[it]?.toSignatureString() ?: "") - signatureForProjection(it.type) - text(nbsp.toString()) - link(it.name!!, it.dri) + group { + link(f.name, f.dri) + list(f.generics, prefix = "<", suffix = ">") { + +buildSignature(it) + } + text("(") + list(f.parameters) { + annotationsInline(it) + text(it.modifiers()[it]?.toSignatureString() ?: "") + signatureForProjection(it.type) + text(nbsp.toString()) + link(it.name!!, it.dri) + } + text(")") } } |