package org.jetbrains.dokka.model import com.intellij.psi.PsiNamedElement import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.model.properties.WithExtraProperties import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.load.kotlin.toSourceElement abstract class Documentable { abstract val name: String? abstract val dri: DRI abstract val children: List abstract val documentation: PlatformDependent abstract val platformData: List override fun toString(): String = "${javaClass.simpleName}($dri)" override fun equals(other: Any?) = other is Documentable && this.dri == other.dri // TODO: https://github.com/Kotlin/dokka/pull/667#discussion_r382555806 override fun hashCode() = dri.hashCode() val briefDocTagString: String by lazy { // TODO > utils documentation.values .firstOrNull() ?.children ?.firstOrNull() ?.root ?.docTagSummary() ?.shorten(40) ?: "" } } data class PlatformDependent( val map: Map, val expect: T? = null ) : Map by map { val prevalentValue: T? get() = map.values.distinct().singleOrNull() val allValues: Sequence = sequence { expect?.also { yield(it) } yieldAll(map.values) } companion object { fun empty(): PlatformDependent = PlatformDependent(emptyMap()) fun from(platformData: PlatformData, element: T) = PlatformDependent(mapOf(platformData to element)) } } interface WithExpectActual { val sources: PlatformDependent } interface WithScope { val functions: List val properties: List val classlikes: List } interface WithVisibility { val visibility: PlatformDependent } interface WithType { val type: TypeWrapper } interface WithAbstraction { val modifier: Modifier } sealed class Modifier(val name: String) sealed class KotlinModifier(name: String) : Modifier(name) { object Abstract : KotlinModifier("abstract") object Open : KotlinModifier("open") object Final : KotlinModifier("final") object Sealed : KotlinModifier("sealed") object Empty : KotlinModifier("") } sealed class JavaModifier(name: String) : Modifier(name) { object Abstract : JavaModifier("abstract") object Final : JavaModifier("final") object Empty : JavaModifier("") } interface WithCompanion { val companion: Object? } interface WithConstructors { val constructors: List } interface WithGenerics { val generics: List } interface WithSupertypes { val supertypes: PlatformDependent> } interface Callable : WithVisibility, WithType, WithAbstraction, WithExpectActual { val receiver: Parameter? } abstract class Classlike : Documentable(), WithScope, WithVisibility, WithExpectActual data class Module( override val name: String, val packages: List, override val documentation: PlatformDependent, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val dri: DRI = DRI.topLevel override val children: List get() = packages override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class Package( override val dri: DRI, override val functions: List, override val properties: List, override val classlikes: List, override val documentation: PlatformDependent, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithExtraProperties { override val name = dri.packageName.orEmpty() override val children: List get() = (properties + functions + classlikes) as List override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class Class( override val dri: DRI, override val name: String, override val constructors: List, override val functions: List, override val properties: List, override val classlikes: List, override val sources: PlatformDependent, override val visibility: PlatformDependent, override val companion: Object?, override val generics: List, override val supertypes: PlatformDependent>, override val documentation: PlatformDependent, override val modifier: Modifier, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Classlike(), WithAbstraction, WithCompanion, WithConstructors, WithGenerics, WithSupertypes, WithExtraProperties { override val children: List get() = (functions + properties + classlikes + constructors) as List override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class Enum( override val dri: DRI, override val name: String, val entries: List, override val documentation: PlatformDependent, override val sources: PlatformDependent, override val functions: List, override val properties: List, override val classlikes: List, override val visibility: PlatformDependent, override val companion: Object?, override val constructors: List, override val supertypes: PlatformDependent>, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Classlike(), WithCompanion, WithConstructors, WithSupertypes, WithExtraProperties { override val children: List get() = (entries + functions + properties + classlikes + constructors) as List override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class EnumEntry( override val dri: DRI, override val name: String, override val documentation: PlatformDependent, override val functions: List, override val properties: List, override val classlikes: List, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithExtraProperties { override val children: List get() = (functions + properties + classlikes) as List override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class Function( override val dri: DRI, override val name: String, val isConstructor: Boolean, val parameters: List, override val documentation: PlatformDependent, override val sources: PlatformDependent, override val visibility: PlatformDependent, override val type: TypeWrapper, override val generics: List, override val receiver: Parameter?, override val modifier: Modifier, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), Callable, WithGenerics, WithExtraProperties { override val children: List get() = parameters override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class Interface( override val dri: DRI, override val name: String, override val documentation: PlatformDependent, override val sources: PlatformDependent, override val functions: List, override val properties: List, override val classlikes: List, override val visibility: PlatformDependent, override val companion: Object?, override val generics: List, override val supertypes: PlatformDependent>, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Classlike(), WithCompanion, WithGenerics, WithSupertypes, WithExtraProperties { override val children: List get() = (functions + properties + classlikes) as List override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class Object( override val name: String?, override val dri: DRI, override val documentation: PlatformDependent, override val sources: PlatformDependent, override val functions: List, override val properties: List, override val classlikes: List, override val visibility: PlatformDependent, override val supertypes: PlatformDependent>, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Classlike(), WithSupertypes, WithExtraProperties { override val children: List get() = (functions + properties + classlikes) as List override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class Annotation( override val name: String, override val dri: DRI, override val documentation: PlatformDependent, override val sources: PlatformDependent, override val functions: List, override val properties: List, override val classlikes: List, override val visibility: PlatformDependent, override val companion: Object?, override val constructors: List, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Classlike(), WithCompanion, WithConstructors, WithExtraProperties { override val children: List get() = (functions + properties + classlikes + constructors) as List override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class Property( override val dri: DRI, override val name: String, override val documentation: PlatformDependent, override val sources: PlatformDependent, override val visibility: PlatformDependent, override val type: TypeWrapper, override val receiver: Parameter?, val setter: Function?, val getter: Function?, override val modifier: Modifier, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), Callable, WithExtraProperties { override val children: List get() = emptyList() override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } // TODO: treat named Parameters and receivers differently data class Parameter( override val dri: DRI, override val name: String?, override val documentation: PlatformDependent, val type: TypeWrapper, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val children: List get() = emptyList() override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class TypeParameter( override val dri: DRI, override val name: String, override val documentation: PlatformDependent, val bounds: List, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val children: List get() = emptyList() override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } sealed class Projection sealed class Bound : Projection() data class OtherParameter(val name: String) : Bound() object Star : Projection() data class TypeConstructor(val dri: DRI, val projections: List) : Bound() data class Nullable(val inner: Bound) : Bound() data class Variance(val kind: Kind, val inner: Bound) : Projection() { enum class Kind { In, Out } } enum class ExtraModifiers { STATIC, INLINE, INFIX, SUSPEND, REIFIED, CROSSINLINE, NOINLINE, OVERRIDE, DATA, CONST, DYNAMIC, EXTERNAL, INNER, LATEINIT, OPERATOR, TAILREC, VARARG } private fun String.shorten(maxLength: Int) = lineSequence().first().let { if (it.length != length || it.length > maxLength) it.take(maxLength - 3) + "..." else it } fun Documentable.dfs(predicate: (Documentable) -> Boolean): Documentable? = if (predicate(this)) { this } else { this.children.asSequence().mapNotNull { it.dfs(predicate) }.firstOrNull() } sealed class Visibility(val name: String) sealed class KotlinVisibility(name: String) : Visibility(name) { object Public : KotlinVisibility("public") object Private : KotlinVisibility("private") object Protected : KotlinVisibility("protected") object Internal : KotlinVisibility("internal") } sealed class JavaVisibility(name: String) : Visibility(name) { object Public : JavaVisibility("public") object Private : JavaVisibility("private") object Protected : JavaVisibility("protected") object Default : JavaVisibility("") } fun PlatformDependent?.orEmpty(): PlatformDependent = this ?: PlatformDependent.empty() sealed class DocumentableSource(val path: String) class DescriptorDocumentableSource(val descriptor: DeclarationDescriptor) : DocumentableSource(descriptor.toSourceElement.containingFile.toString()) class PsiDocumentableSource(val psi: PsiNamedElement) : DocumentableSource(psi.containingFile.virtualFile.path)