From 885ecd28153b484277c9ddcbf4a7f9d761a59545 Mon Sep 17 00:00:00 2001 From: Paweł Marks Date: Mon, 27 Jan 2020 09:34:16 +0100 Subject: Unifing model for pages with content ant technical renderer specific pages --- .../kotlin/resolvers/DefaultLocationProvider.kt | 81 ++++++++++------------ 1 file changed, 38 insertions(+), 43 deletions(-) (limited to 'core/src/main/kotlin/resolvers/DefaultLocationProvider.kt') 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 = pageGraphRoot.asSequence().filterIsInstance() + .groupingBy { it.dri } + .aggregate { dri, _, page, first -> + if (first) page else throw AssertionError("Multiple pages associated with dri: $dri") + } - private val pagesCache = mutableMapOf>() - private val pathCache: MutableMap> = IdentityHashMap>() + protected val pathsIndex: Map> = IdentityHashMap>().apply { + fun registerPath(page: PageNode, prefix: List) { + 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, 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 = when (node) { - null -> emptyList() - else -> ancestors(node.parent()) + node - } - - override fun top(): PageNode = pageGraphRoot - - protected open fun findInPageGraph(dri: DRI, platforms: List): 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 = + 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): List = 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(val unwrapped: T?) - -private val T?.wrapped: Maybe get() = Maybe(this) \ No newline at end of file +private val PageNode.pathName: String + get() = if (this is PackagePageNode) name else identifierToFilename(name) -- cgit