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.descriptors.Visibility 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() companion object { fun empty() = PlatformDependent(mapOf()) } } interface WithExpectActual { val actual: PlatformDependent } interface WithScope { val functions: List val properties: List val classlikes: List } interface WithPackages { val packages: List } interface WithVisibility { val visibility: PlatformDependent // TODO custom visibility } interface WithType { val type: TypeWrapper } interface WithAbstraction { val modifier: Modifier enum class Modifier { Abstract, Open, Final } } 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, override val packages: List, override val documentation: PlatformDependent, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithPackages, 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 packages: List, override val documentation: PlatformDependent, override val platformData: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithPackages, WithExtraProperties { override val name = dri.packageName.orEmpty() override val children: List get() = (properties + functions + classlikes + packages) 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 actual: PlatformDependent, override val visibility: PlatformDependent, override val companion: Object?, override val generics: List, override val supertypes: PlatformDependent>, override val documentation: PlatformDependent, override val modifier: WithAbstraction.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 + listOfNotNull(companion) + 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 actual: 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 + listOfNotNull(companion) + 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 actual: PlatformDependent, override val visibility: PlatformDependent, override val type: TypeWrapper, override val generics: List, override val receiver: Parameter?, override val modifier: WithAbstraction.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 actual: 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 + listOfNotNull(companion)) 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 actual: 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 actual: 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 + listOfNotNull(companion)) 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 actual: PlatformDependent, override val visibility: PlatformDependent, override val type: TypeWrapper, override val receiver: Parameter?, val setter: Function?, val getter: Function, override val modifier: WithAbstraction.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 { data class OtherParameter(val name: String) : Projection() object Star : Projection() data class TypeConstructor(val dri: DRI, val projections: List) : Projection() data class Nullable(val inner: Projection) : Projection() } 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 DocumentableSource(val path: String) class DescriptorDocumentableSource(val descriptor: DeclarationDescriptor) : DocumentableSource(descriptor.toSourceElement.containingFile.toString()) class PsiDocumentableSource(val psi: PsiNamedElement) : DocumentableSource(psi.containingFile.virtualFile.path)