diff options
Diffstat (limited to 'core/src/main/kotlin/resolvers')
3 files changed, 44 insertions, 48 deletions
diff --git a/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt b/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt index 8e848b63..48ea5316 100644 --- a/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt +++ b/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt @@ -8,19 +8,35 @@ import org.jetbrains.dokka.plugability.single import org.jetbrains.dokka.utilities.htmlEscape import java.util.* +private const val PAGE_WITH_CHILDREN_SUFFIX = "index" + open class DefaultLocationProvider( - private val pageGraphRoot: ModulePageNode, - private val dokkaContext: DokkaContext -) : LocationProvider { // TODO: cache - private val extension = dokkaContext.single(CoreExtensions.fileExtension) + protected val pageGraphRoot: RootPageNode, + protected val dokkaContext: DokkaContext +) : LocationProvider { + protected val extension = dokkaContext.single(CoreExtensions.fileExtension) + + protected val pagesIndex: Map<DRI, ContentPage> = pageGraphRoot.asSequence().filterIsInstance<ContentPage>() + .groupingBy { it.dri } + .aggregate { dri, _, page, first -> + if (first) page else throw AssertionError("Multiple pages associated with dri: $dri") + } - private val pagesCache = mutableMapOf<DRI, Maybe<PageNode>>() - private val pathCache: MutableMap<PageNode, List<String>> = IdentityHashMap<PageNode, List<String>>() + 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?): String = pathTo(node, context) + extension + override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean): String = + pathTo(node, context) + if (!skipExtension) extension else "" override fun resolve(dri: DRI, platforms: List<PlatformData>, context: PageNode?): String = - findInPageGraph(dri, platforms)?.let { resolve(it, context) } ?: + pagesIndex[dri]?.let { resolve(it, context) } ?: // Not found in PageGraph, that means it's an external link ExternalLocationProvider.getLocation(dri, this.dokkaContext.configuration.passesConfigurations @@ -31,50 +47,30 @@ open class DefaultLocationProvider( .flatMap { it.externalDocumentationLinks }.distinct() ) - override fun resolveRoot(node: PageNode): String = "../${pathTo(pageGraphRoot, node).removeSuffix( - PAGE_WITH_CHILDREN_SUFFIX - )}" - - private fun PageNode.parent() = pageGraphRoot.parentMap[this] - - override fun ancestors(node: PageNode?): List<PageNode> = when (node) { - null -> emptyList() - else -> ancestors(node.parent()) + node - } - - override fun top(): PageNode = pageGraphRoot - - protected open fun findInPageGraph(dri: DRI, platforms: List<PlatformData>): PageNode? = - pagesCache.getOrPut(dri) { pageGraphRoot.dfs { it.dri == dri }.wrapped }.unwrapped + 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 PageNode.pathName(): String = - if (this is PackagePageNode) name - else identifierToFilename(name) - - fun getPathInternal(pathNode: PageNode?, path: List<String>): List<String> = when (pathNode) { - null -> path - else -> getPathInternal(pathNode.parent(), path + pathNode.pathName().ifEmpty { "root" }) - } - - fun getPath(pathNode: PageNode) = pathCache.getOrPut(pathNode) { getPathInternal(pathNode, emptyList()) } + 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?.children?.isEmpty() == true && context.parent() != null) context.parent() else context - val nodePath = getPath(node).reversed() - val contextPath = contextNode?.let(::getPath).orEmpty().reversed() + val nodePath = pathFor(node) + val contextPath = contextNode?.let { pathFor(it) }.orEmpty() - val commonPathElements = nodePath.zip(contextPath).takeWhile { (a, b) -> a == b }.size + val commonPathElements = nodePath.asSequence().zip(contextPath.asSequence()) + .takeWhile { (a, b) -> a == b }.count() return (List(contextPath.size - commonPathElements) { ".." } + nodePath.drop(commonPathElements) + if (node.children.isNotEmpty()) listOf(PAGE_WITH_CHILDREN_SUFFIX) else emptyList()).joinToString("/") } - private companion object { - const val PAGE_WITH_CHILDREN_SUFFIX = "index" - } + private fun PageNode.parent() = pageGraphRoot.parentMap[this] } fun DRI.toJavadocLocation(jdkVersion: Int): String { // TODO: classes without packages? @@ -122,6 +118,5 @@ private fun identifierToFilename(name: String): String { return if (lowercase in reservedFilenames) "--$lowercase--" else lowercase } -private class Maybe<T : Any>(val unwrapped: T?) - -private val <T : Any> T?.wrapped: Maybe<T> get() = Maybe(this)
\ No newline at end of file +private val PageNode.pathName: String + get() = if (this is PackagePageNode) name else identifierToFilename(name) diff --git a/core/src/main/kotlin/resolvers/LocationProvider.kt b/core/src/main/kotlin/resolvers/LocationProvider.kt index 7d77ccb8..3bc9ab72 100644 --- a/core/src/main/kotlin/resolvers/LocationProvider.kt +++ b/core/src/main/kotlin/resolvers/LocationProvider.kt @@ -1,13 +1,13 @@ package org.jetbrains.dokka.resolvers import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.pages.ContentPage import org.jetbrains.dokka.pages.PageNode import org.jetbrains.dokka.pages.PlatformData interface LocationProvider { fun resolve(dri: DRI, platforms: List<PlatformData>, context: PageNode? = null): String - fun resolve(node: PageNode, context: PageNode? = null): String + fun resolve(node: PageNode, context: PageNode? = null, skipExtension: Boolean = false): String fun resolveRoot(node: PageNode): String - fun ancestors(node: PageNode?): List<PageNode> - fun top(): PageNode + fun ancestors(node: PageNode): List<PageNode> } diff --git a/core/src/main/kotlin/resolvers/LocationProviderFactory.kt b/core/src/main/kotlin/resolvers/LocationProviderFactory.kt index c657846a..782795de 100644 --- a/core/src/main/kotlin/resolvers/LocationProviderFactory.kt +++ b/core/src/main/kotlin/resolvers/LocationProviderFactory.kt @@ -1,13 +1,14 @@ package org.jetbrains.dokka.resolvers import org.jetbrains.dokka.pages.ModulePageNode +import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.DokkaContext interface LocationProviderFactory { - fun getLocationProvider(pageNode: ModulePageNode): LocationProvider + fun getLocationProvider(pageNode: RootPageNode): LocationProvider } class DefaultLocationProviderFactory(val context: DokkaContext) : LocationProviderFactory { - override fun getLocationProvider(pageNode: ModulePageNode) = DefaultLocationProvider(pageNode, context) + override fun getLocationProvider(pageNode: RootPageNode) = DefaultLocationProvider(pageNode, context) }
\ No newline at end of file |