All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.dokka.javadoc.pages.JavadocPageNodes.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

package org.jetbrains.dokka.javadoc.pages

import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.base.renderers.sourceSets
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.model.properties.PropertyContainer
import org.jetbrains.dokka.model.properties.WithExtraProperties
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.analysis.kotlin.internal.InheritanceBuilder
import org.jetbrains.dokka.analysis.kotlin.internal.InheritanceNode

public interface JavadocPageNode : ContentPage, WithDocumentables

public interface WithJavadocExtra : WithExtraProperties {
    override fun withNewExtras(newExtras: PropertyContainer): T =
        throw IllegalStateException("Merging extras is not applicable for javadoc")
}

public fun interface WithNavigable {
    public fun getAllNavigables(): List
}

public interface WithBrief {
    public val brief: List
}

public class JavadocModulePageNode(
    override val name: String,
    override val content: JavadocContentNode,
    override val children: List,
    override val dri: Set,
    override val extra: PropertyContainer = PropertyContainer.empty()
) :
    RootPageNode(),
    WithJavadocExtra,
    NavigableJavadocNode,
    JavadocPageNode,
    ModulePage {

    override val documentables: List = emptyList()
    override val embeddedResources: List = emptyList()
    override fun modified(name: String, children: List): RootPageNode =
        JavadocModulePageNode(name, content, children, dri, extra)

    override fun modified(
        name: String,
        content: ContentNode,
        dri: Set,
        embeddedResources: List,
        children: List
    ): ContentPage = JavadocModulePageNode(name, content as JavadocContentNode, children, dri, extra)

    override fun getId(): String = name

    override fun getDRI(): DRI = dri.first()
}

public class JavadocPackagePageNode(
    override val name: String,
    override val content: JavadocContentNode,
    override val dri: Set,

    override val documentables: List = emptyList(),
    override val children: List = emptyList(),
    override val embeddedResources: List = listOf()
) : JavadocPageNode,
    WithNavigable,
    NavigableJavadocNode,
    PackagePage {

    init {
        require(name.isNotBlank()) { "Empty name is not supported " }
    }

    override fun getAllNavigables(): List =
        children.filterIsInstance().flatMap {
            if (it is WithNavigable) it.getAllNavigables()
            else listOf(it)
        }

    override fun modified(
        name: String,
        children: List
    ): PageNode = JavadocPackagePageNode(
        name,
        content,
        dri,
        documentables,
        children,
        embeddedResources
    )

    override fun modified(
        name: String,
        content: ContentNode,
        dri: Set,
        embeddedResources: List,
        children: List
    ): ContentPage =
        JavadocPackagePageNode(
            name,
            content as JavadocContentNode,
            dri,
            documentables,
            children,
            embeddedResources
        )

    override fun getId(): String = name

    override fun getDRI(): DRI = dri.first()
}

public interface NavigableJavadocNode {
    public fun getId(): String
    public fun getDRI(): DRI
}

public sealed class AnchorableJavadocNode(
    public open val name: String,
    public open val dri: DRI
) : NavigableJavadocNode {
    override fun getId(): String = name
    override fun getDRI(): DRI = dri
}

public data class JavadocEntryNode(
    override val dri: DRI,
    override val name: String,
    val signature: JavadocSignatureContentNode,
    override val brief: List,
    override val extra: PropertyContainer = PropertyContainer.empty()
) : AnchorableJavadocNode(name, dri), WithJavadocExtra, WithBrief

public data class JavadocParameterNode(
    override val dri: DRI,
    override val name: String,
    val type: ContentNode,
    val description: List,
    val typeBound: Bound,
    override val extra: PropertyContainer = PropertyContainer.empty()
) : AnchorableJavadocNode(name, dri), WithJavadocExtra

public data class JavadocPropertyNode(
    override val dri: DRI,
    override val name: String,
    val signature: JavadocSignatureContentNode,
    override val brief: List,

    override val extra: PropertyContainer = PropertyContainer.empty()
) : AnchorableJavadocNode(name, dri), WithJavadocExtra, WithBrief

public data class JavadocFunctionNode(
    val signature: JavadocSignatureContentNode,
    override val brief: List,
    val description: List,
    val parameters: List,

    val returnTagContent: List,
    val sinceTagContent: List>,

    override val name: String,
    override val dri: DRI,
    override val extra: PropertyContainer = PropertyContainer.empty()
) : AnchorableJavadocNode(name, dri), WithJavadocExtra, WithBrief {
    val isInherited: Boolean
        get() {
            val extra = extra[InheritedMember]
            return extra?.inheritedFrom?.keys?.firstOrNull { it.analysisPlatform == Platform.jvm }?.let { jvm ->
                extra.isInherited(jvm)
            } ?: false
        }
}

public class JavadocClasslikePageNode(
    override val name: String,
    override val content: JavadocContentNode,
    override val dri: Set,
    public val signature: JavadocSignatureContentNode,
    public val description: List,
    public val constructors: List,
    public val methods: List,
    public val entries: List,
    public val classlikes: List,
    public val properties: List,
    override val brief: List,

    public val sinceTagContent: List>,
    public val authorTagContent: List>,

    override val documentables: List = emptyList(),
    override val children: List = emptyList(),
    override val embeddedResources: List = listOf(),
    override val extra: PropertyContainer = PropertyContainer.empty(),
) : JavadocPageNode, WithJavadocExtra, NavigableJavadocNode, WithNavigable, WithBrief, ClasslikePage {

    override fun getAllNavigables(): List =
        methods + entries + classlikes.map { it.getAllNavigables() }.flatten() + this

    public fun getAnchorables(): List =
        constructors + methods + entries + properties

    public val kind: String? = documentables.firstOrNull()?.kind()
    public val packageName: String? = dri.first().packageName

    override fun getId(): String = name
    override fun getDRI(): DRI = dri.first()

    override fun modified(
        name: String,
        children: List
    ): PageNode = JavadocClasslikePageNode(
        name,
        content,
        dri,
        signature,
        description,
        constructors,
        methods,
        entries,
        classlikes,
        properties,
        brief,
        sinceTagContent,
        authorTagContent,
        documentables,
        children,
        embeddedResources,
        extra
    )

    override fun modified(
        name: String,
        content: ContentNode,
        dri: Set,
        embeddedResources: List,
        children: List
    ): ContentPage =
        JavadocClasslikePageNode(
            name,
            content as JavadocContentNode,
            dri,
            signature,
            description,
            constructors,
            methods,
            entries,
            classlikes,
            properties,
            brief,
            sinceTagContent,
            authorTagContent,
            documentables,
            children,
            embeddedResources,
            extra
        )
}

public class AllClassesPage(
    public val classes: List
) : JavadocPageNode {
    public val classEntries: List =
        classes.map { LinkJavadocListEntry(it.name, it.dri, ContentKind.Classlikes, it.sourceSets().toSet()) }

    override val name: String = "All Classes"
    override val dri: Set = setOf(DRI.topLevel)

    override val documentables: List = emptyList()
    override val embeddedResources: List = emptyList()

    override val content: ContentNode =
        EmptyNode(
            DRI.topLevel,
            ContentKind.Classlikes,
            classes.flatMap { it.sourceSets() }.toSet()
        )

    override fun modified(
        name: String,
        content: ContentNode,
        dri: Set,
        embeddedResources: List,
        children: List
    ): ContentPage = this

    override fun modified(name: String, children: List): PageNode =
        this

    override val children: List = emptyList()

}

public class DeprecatedPage(
    public val elements: Map>,
    sourceSet: Set
) : JavadocPageNode {
    override val name: String = "deprecated"
    override val dri: Set = setOf(DRI.topLevel)
    override val documentables: List = emptyList()
    override val children: List = emptyList()
    override val embeddedResources: List = listOf()

    override val content: ContentNode = EmptyNode(
        DRI.topLevel,
        ContentKind.Main,
        sourceSet
    )

    override fun modified(
        name: String,
        children: List
    ): PageNode = this

    override fun modified(
        name: String,
        content: ContentNode,
        dri: Set,
        embeddedResources: List,
        children: List
    ): ContentPage = this

}

public class DeprecatedNode(
    public val name: String,
    public val address: DRI,
    public val description: List
) {
    override fun equals(other: Any?): Boolean =
        (other as? DeprecatedNode)?.address == address

    override fun hashCode(): Int = address.hashCode()
}

public enum class DeprecatedPageSection(
    public val id: String,
    public val caption: String,
    public val header: String,
) {
    DeprecatedModules("module", "Modules", "Module"),
    DeprecatedInterfaces("interface", "Interfaces", "Interface"),
    DeprecatedClasses("class", "Classes", "Class"),
    DeprecatedExceptions("exception", "Exceptions", "Exceptions"),
    DeprecatedFields("field", "Fields", "Field"),
    DeprecatedMethods("method", "Methods", "Method"),
    DeprecatedConstructors("constructor", "Constructors", "Constructor"),
    DeprecatedEnums("enum", "Enums", "Enum"),
    DeprecatedEnumConstants("enum.constant", "Enum Constants", "Enum Constant"),
    DeprecatedForRemoval("forRemoval", "For Removal", "Element");

    internal fun getPosition() = ordinal
}

public class IndexPage(
    public val id: Int,
    public val elements: List,
    public val keys: List,

    sourceSet: Set

) : JavadocPageNode {
    override val name: String = "index-$id"
    override val dri: Set = setOf(DRI.topLevel)
    override val documentables: List = emptyList()
    override val children: List = emptyList()
    override val embeddedResources: List = listOf()
    public val title: String = "${keys[id - 1]}-index"

    override val content: ContentNode = EmptyNode(
        DRI.topLevel,
        ContentKind.Classlikes,
        sourceSet
    )

    override fun modified(
        name: String,
        children: List
    ): PageNode = this

    override fun modified(
        name: String,
        content: ContentNode,
        dri: Set,
        embeddedResources: List,
        children: List
    ): ContentPage = this

}

public class TreeViewPage(
    override val name: String,
    public val packages: List?,
    public val classes: List?,
    override val dri: Set,
    override val documentables: List = emptyList(),
    public val root: PageNode,
    public val inheritanceBuilder: InheritanceBuilder
) : JavadocPageNode {
    init {
        assert(packages == null || classes == null)
        assert(packages != null || classes != null)
    }

    private val childrenDocumentables = root.children.filterIsInstance().flatMap { node ->
        getDocumentableEntries(node)
    }.groupBy({ it.first }) { it.second }.map { (l, r) -> l to r.first() }.toMap()

    private val inheritanceTuple = generateInheritanceTree()
    internal val classGraph = inheritanceTuple.first
    internal val interfaceGraph = inheritanceTuple.second

    override val children: List = emptyList()

    public val title: String = when (documentables.firstOrNull()) {
        is DPackage -> "$name Class Hierarchy"
        else -> "All packages"
    }

    public val kind: String = when (documentables.firstOrNull()) {
        is DPackage -> "package"
        else -> "main"
    }

    override fun modified(
        name: String,
        content: ContentNode,
        dri: Set,
        embeddedResources: List,
        children: List
    ): ContentPage =
        TreeViewPage(
            name,
            packages = children.filterIsInstance().takeIf { it.isNotEmpty() },
            classes = children.filterIsInstance().takeIf { it.isNotEmpty() },
            dri = dri,
            documentables,
            root = root,
            inheritanceBuilder
        )

    override fun modified(name: String, children: List): PageNode =
        TreeViewPage(
            name,
            packages = children.filterIsInstance().takeIf { it.isNotEmpty() },
            classes = children.filterIsInstance().takeIf { it.isNotEmpty() },
            dri = dri,
            documentables,
            root = root,
            inheritanceBuilder
        )

    override val embeddedResources: List = emptyList()

    override val content: ContentNode = EmptyNode(
        DRI.topLevel,
        ContentKind.Classlikes,
        emptySet()
    )

    private fun generateInheritanceTree(): Pair, List> {
        val mergeMap = mutableMapOf()

        fun addToMap(info: InheritanceNode, map: MutableMap) {
            if (map.containsKey(info.dri))
                map.computeIfPresent(info.dri) { _, info2 ->
                    info.copy(children = (info.children + info2.children).distinct())
                }!!.children.forEach { addToMap(it, map) }
            else
                map[info.dri] = info
        }

        fun collect(dri: DRI): InheritanceNode =
            InheritanceNode(
                dri,
                mergeMap[dri]?.children.orEmpty().map { collect(it.dri) },
                mergeMap[dri]?.interfaces.orEmpty(),
                mergeMap[dri]?.isInterface ?: false
            )

        fun classTreeRec(node: InheritanceNode): List = if (node.isInterface) {
            node.children.flatMap(::classTreeRec)
        } else {
            listOf(node.copy(children = node.children.flatMap(::classTreeRec)))
        }

        fun classTree(node: InheritanceNode) = classTreeRec(node).singleOrNull()

        fun interfaceTreeRec(node: InheritanceNode): List = if (node.isInterface) {
            listOf(node.copy(children = node.children.filter { it.isInterface }))
        } else {
            node.children.flatMap(::interfaceTreeRec)
        }

        fun interfaceTree(node: InheritanceNode) = interfaceTreeRec(node).firstOrNull() // TODO.single()

        val inheritanceNodes = inheritanceBuilder.build(childrenDocumentables)
        inheritanceNodes.forEach { addToMap(it, mergeMap) }

        val rootNodes = mergeMap.entries.filter {
            it.key.classNames in setOf("Any", "Object") //TODO: Probably should be matched by DRI, not just className
        }.map {
            collect(it.value.dri)
        }

        return rootNodes.let { Pair(it.mapNotNull(::classTree), it.mapNotNull(::interfaceTree)) }
    }

    private fun getDocumentableEntries(node: WithDocumentables): List> =
        node.documentables.map { it.dri to it } +
                (node as? ContentPage)?.children?.filterIsInstance()
                    ?.flatMap(::getDocumentableEntries).orEmpty()

}

private fun Documentable.kind(): String? =
    when (this) {
        is DClass -> "class"
        is DEnum -> "enum"
        is DAnnotation -> "annotation"
        is DObject -> "object"
        is DInterface -> "interface"
        else -> null
    }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy