From f166bfae0f30b6d7de1e5f7b8dcc312ee981ed76 Mon Sep 17 00:00:00 2001
From: Casey Brooks <cjbrooks12@gmail.com>
Date: Wed, 17 Oct 2018 18:08:44 -0500
Subject: [PATCH] Starts trying to add Dokka class signatures

---
 dokka-json-lib/build.gradle                   | 18 +++++++
 .../copperleaf/dokka/json/models/models.kt    |  5 +-
 .../json/generator/formatter/formatClass.kt   | 30 +++++++++++-
 .../generator/formatter/formatConstructor.kt  | 10 ++--
 .../json/generator/formatter/formatField.kt   | 12 ++---
 .../json/generator/formatter/formatHelpers.kt | 38 ++++++++++++---
 .../json/generator/formatter/formatMethod.kt  | 22 +++++----
 .../generator/formatter/formatParameters.kt   | 45 ++++++++++++-----
 .../dokka/json/test/kotlin/KotlinClass.kt     | 48 +++++++++++++++----
 9 files changed, 179 insertions(+), 49 deletions(-)

diff --git a/dokka-json-lib/build.gradle b/dokka-json-lib/build.gradle
index 3e5643c..4ec12c9 100644
--- a/dokka-json-lib/build.gradle
+++ b/dokka-json-lib/build.gradle
@@ -30,3 +30,21 @@ test {
     }
 }
 test.outputs.upToDateWhen {false}
+
+
+
+configurations { dokka }
+repositories {
+    maven { url 'https://jitpack.io' }
+}
+dependencies {
+    dokka 'org.jetbrains.dokka:dokka-fatjar:0.9.17'
+}
+task runDefaultDokka(type: JavaExec) {
+    main = "org.jetbrains.dokka.MainKt"
+    classpath = configurations.dokka
+    args = [
+            "-src", "${project(':dokka-json').projectDir}/src/test/kotlin",
+            "-output", "${project(':dokka-json').buildDir}/dokka/default"
+    ]
+}
diff --git a/dokka-json-models/src/main/kotlin/com/copperleaf/dokka/json/models/models.kt b/dokka-json-models/src/main/kotlin/com/copperleaf/dokka/json/models/models.kt
index 91301f4..e809e47 100644
--- a/dokka-json-models/src/main/kotlin/com/copperleaf/dokka/json/models/models.kt
+++ b/dokka-json-models/src/main/kotlin/com/copperleaf/dokka/json/models/models.kt
@@ -27,10 +27,13 @@ data class KotlinClassDoc(
         override val qualifiedName: String,
         override val comment: String,
         override val summaryPos: Int,
+        val modifiers: List<String>,
         val constructors: List<KotlinConstructor>,
         val methods: List<KotlinMethod>,
         val fields: List<KotlinField>,
-        val extensions: List<KotlinMethod>
+        val extensions: List<KotlinMethod>,
+        val signature: List<SignatureComponent>,
+        val simpleSignature: String = signature.map { it.name }.joinToString("")
 ) : KotlinClasslike {
     companion object {
         fun fromJson(json: String): KotlinClassDoc {
diff --git a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatClass.kt b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatClass.kt
index c77125c..7684b89 100644
--- a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatClass.kt
+++ b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatClass.kt
@@ -1,6 +1,7 @@
 package com.copperleaf.dokka.json.generator.formatter
 
 import com.copperleaf.dokka.json.models.KotlinClassDoc
+import com.copperleaf.dokka.json.models.SignatureComponent
 import org.jetbrains.dokka.DocumentationNode
 import org.jetbrains.dokka.NodeKind
 import org.jetbrains.dokka.path
@@ -10,6 +11,8 @@ val DocumentationNode.classLike: Boolean get() = NodeKind.classLike.contains(thi
 fun DocumentationNode.toClassDoc(deep: Boolean = false): KotlinClassDoc {
     assert(this.classLike) { "node must be a Class-like" }
 
+    val modifiers = this.modifiers
+
     return KotlinClassDoc(
             this,
             this.path.map { it.name }.filterNot { it.isEmpty() }.first(),
@@ -18,9 +21,34 @@ fun DocumentationNode.toClassDoc(deep: Boolean = false): KotlinClassDoc {
             this.qualifiedName,
             this.contentText,
             this.summary.textLength,
+            modifiers,
             if (deep) this.members.filter { it.isConstructor }.map { it.toConstructor() } else emptyList(),
             if (deep) this.members.filter { it.isMethod }.map { it.toMethod() } else emptyList(),
             if (deep) this.members.filter { it.isField }.map { it.toField() } else emptyList(),
-            if (deep) this.extensions.filter { it.isMethod }.map { it.toMethod() } else emptyList()
+            if (deep) this.extensions.filter { it.isMethod }.map { it.toMethod() } else emptyList(),
+            this.classSignature(
+                    modifiers
+            )
+    )
+}
+
+fun DocumentationNode.classSignature(
+        modifiers: List<String>
+): List<SignatureComponent> {
+    val list = mutableListOf<SignatureComponent>()
+
+    list.addAll(modifiers.toModifierListSignature())
+    list.add(SignatureComponent("keyword", "class ", ""))
+    list.add(SignatureComponent("type", this.simpleName, this.qualifiedName))
+//    list.addAll(this.toTypeParameterDeclarationSignature())
+//    list.addAll(this.toSuperclassDeclarationSignature())
+
+    return list
+}
+
+fun DocumentationNode.toSuperclassDeclarationSignature(): List<SignatureComponent> {
+    return this.details(NodeKind.Supertype).toListSignature(
+            childMapper = { it.toTypeSignature() },
+            prefix = listOf(SignatureComponent("punctuation", ": ", ""))
     )
 }
\ No newline at end of file
diff --git a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatConstructor.kt b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatConstructor.kt
index 304770c..267738f 100644
--- a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatConstructor.kt
+++ b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatConstructor.kt
@@ -31,11 +31,11 @@ fun DocumentationNode.constructorSignature(
         modifiers: List<String>,
         parameters: List<KotlinParameter>
 ): List<SignatureComponent> {
-    val signatureComponents = mutableListOf<SignatureComponent>()
+    val list = mutableListOf<SignatureComponent>()
 
-    signatureComponents.addAll(modifiers.toModifierListSignature())
-    signatureComponents.add(SignatureComponent("keyword", "constructor", ""))
-    signatureComponents.addAll(parameters.toParameterListSignature())
+    list.addAll(modifiers.toModifierListSignature())
+    list.add(SignatureComponent("keyword", "constructor", ""))
+    list.addAll(parameters.toParameterListSignature())
 
-    return signatureComponents
+    return list
 }
\ No newline at end of file
diff --git a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatField.kt b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatField.kt
index 01e10d3..26a0a04 100644
--- a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatField.kt
+++ b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatField.kt
@@ -30,12 +30,12 @@ fun DocumentationNode.fieldSignature(
         modifiers: List<String>,
         type: DocumentationNode
 ): List<SignatureComponent> {
-    val signatureComponents = mutableListOf<SignatureComponent>()
+    val list = mutableListOf<SignatureComponent>()
 
-    signatureComponents.addAll(modifiers.toModifierListSignature())
-    signatureComponents.add(SignatureComponent("name", this.simpleName, ""))
-    signatureComponents.add(SignatureComponent("punctuation", ": ", ""))
-    signatureComponents.addAll(type.asType().toTypeSignature())
+    list.addAll(modifiers.toModifierListSignature())
+    list.add(SignatureComponent("name", this.simpleName, ""))
+    list.add(SignatureComponent("punctuation", ": ", ""))
+    list.addAll(type.asType().toTypeSignature())
 
-    return signatureComponents
+    return list
 }
\ No newline at end of file
diff --git a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatHelpers.kt b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatHelpers.kt
index 082701b..6050612 100644
--- a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatHelpers.kt
+++ b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatHelpers.kt
@@ -6,9 +6,10 @@ import org.jetbrains.dokka.NodeKind
 import org.jetbrains.dokka.path
 import org.jetbrains.dokka.qualifiedNameFromType
 
-val DocumentationNode.modifiers: List<String> get() = this.details(NodeKind.Modifier)
-        .map { it.name }
-        .filter { !arrayOf("public", "final").contains(it) }
+val DocumentationNode.modifiers: List<String>
+    get() = this.details(NodeKind.Modifier)
+            .map { it.name }
+            .filter { !arrayOf("public", "final").contains(it) }
 
 val DocumentationNode.simpleName: String
     get() {
@@ -17,7 +18,7 @@ val DocumentationNode.simpleName: String
 
 val DocumentationNode.qualifiedName: String
     get() {
-        return if(kind == NodeKind.Type) {
+        return if (kind == NodeKind.Type) {
             this.qualifiedNameFromType()
         }
         else {
@@ -26,8 +27,11 @@ val DocumentationNode.qualifiedName: String
     }
 
 fun DocumentationNode.asType(): DocumentationNode {
-        return if (kind == NodeKind.Type) this else this.detail(NodeKind.Type)
-    }
+    return if (kind == NodeKind.Type) this else this.detailOrNull(NodeKind.Type) ?: {
+        println("other node requesting type: ${this.kind} ${this.name}")
+        this
+    }()
+}
 
 val DocumentationNode.simpleType: String
     get() {
@@ -47,3 +51,25 @@ val DocumentationNode.nullable: Boolean
 fun List<String>.toModifierListSignature(): List<SignatureComponent> {
     return this.map { SignatureComponent("modifier", "$it ", "") }
 }
+
+fun List<DocumentationNode>.toListSignature(
+        childMapper: (DocumentationNode) -> List<SignatureComponent>,
+        prefix: List<SignatureComponent> = emptyList(),
+        postfix: List<SignatureComponent> = emptyList(),
+        separator: List<SignatureComponent> = listOf(SignatureComponent("punctuation", ", ", ""))
+): List<SignatureComponent> {
+    val list = mutableListOf<SignatureComponent>()
+
+    if (this.isNotEmpty()) {
+        list.addAll(prefix)
+        this.forEachIndexed { index, superclass ->
+            list.addAll(childMapper(superclass))
+            if (index < this.size - 1) {
+                list.addAll(separator)
+            }
+        }
+        list.addAll(postfix)
+    }
+
+    return list
+}
\ No newline at end of file
diff --git a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatMethod.kt b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatMethod.kt
index 5b2ec0d..e74b88e 100644
--- a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatMethod.kt
+++ b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatMethod.kt
@@ -41,25 +41,27 @@ fun DocumentationNode.methodSignature(
         receiverType: KotlinReceiverType?,
         returnType: KotlinReturnType
 ): List<SignatureComponent> {
-    val signatureComponents = mutableListOf<SignatureComponent>()
+    val list = mutableListOf<SignatureComponent>()
 
-    signatureComponents.addAll(modifiers.toModifierListSignature())
-    signatureComponents.add(SignatureComponent("keyword", "fun ", ""))
+    list.addAll(modifiers.toModifierListSignature())
+    list.add(SignatureComponent("keyword", "fun ", ""))
+
+    list.addAll(this.toTypeParameterDeclarationSignature())
 
     if (receiverType != null) {
-        signatureComponents.addAll(receiverType.signature)
-        signatureComponents.add(SignatureComponent("punctuation", ".", ""))
+        list.addAll(receiverType.signature)
+        list.add(SignatureComponent("punctuation", ".", ""))
     }
 
-    signatureComponents.add(SignatureComponent("name", this.simpleName, ""))
-    signatureComponents.addAll(parameters.toParameterListSignature())
+    list.add(SignatureComponent("name", this.simpleName, ""))
+    list.addAll(parameters.toParameterListSignature())
 
     if (returnType.name != "Unit") {
-        signatureComponents.add(SignatureComponent("punctuation", ": ", ""))
-        signatureComponents.addAll(returnType.signature)
+        list.add(SignatureComponent("punctuation", ": ", ""))
+        list.addAll(returnType.signature)
     }
 
-    return signatureComponents
+    return list
 }
 
 val DocumentationNode.returnType: KotlinReturnType
diff --git a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatParameters.kt b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatParameters.kt
index 1ecfde7..f298c55 100644
--- a/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatParameters.kt
+++ b/dokka-json/src/main/kotlin/com/copperleaf/dokka/json/generator/formatter/formatParameters.kt
@@ -71,17 +71,11 @@ fun DocumentationNode.toNonFunctionalTypeSignature(): List<SignatureComponent> {
 
     list.add(SignatureComponent("type", this.simpleType, this.qualifiedType))
 
-    val typeArguments = this.details(NodeKind.Type)
-    if (typeArguments.isNotEmpty()) {
-        list.add(SignatureComponent("punctuation", "<", ""))
-        typeArguments.forEachIndexed { index, parameter ->
-            list.addAll(parameter.toTypeSignature())
-            if (index < typeArguments.size - 1) {
-                list.add(SignatureComponent("punctuation", ", ", ""))
-            }
-        }
-        list.add(SignatureComponent("punctuation", ">", ""))
-    }
+    this.details(NodeKind.Type).toListSignature(
+            childMapper = { it.toTypeSignature() },
+            prefix = listOf(SignatureComponent("punctuation", "<", "")),
+            postfix = listOf(SignatureComponent("punctuation", ">", ""))
+    )
 
     if (this.nullable) {
         list.add(SignatureComponent("punctuation", "?", ""))
@@ -123,3 +117,32 @@ fun DocumentationNode.toFunctionalTypeSignature(): List<SignatureComponent> {
 
     return list
 }
+
+
+// Type Params
+//----------------------------------------------------------------------------------------------------------------------
+
+fun DocumentationNode.toTypeParameterDeclarationSignature(): List<SignatureComponent> {
+    val list = mutableListOf<SignatureComponent>()
+
+    val typeArguments = this.details(NodeKind.TypeParameter)
+    if (typeArguments.isNotEmpty()) {
+        list.add(SignatureComponent("punctuation", "<", ""))
+        typeArguments.forEachIndexed { index, typeParameter ->
+            list.add(SignatureComponent("name", typeParameter.name, ""))
+
+            val upperBound = typeParameter.detailOrNull(NodeKind.UpperBound)
+            if (upperBound != null) {
+                list.add(SignatureComponent("punctuation", " : ", ""))
+                list.addAll(upperBound.asType().toTypeSignature())
+            }
+
+            if (index < typeArguments.size - 1) {
+                list.add(SignatureComponent("punctuation", ", ", ""))
+            }
+        }
+        list.add(SignatureComponent("punctuation", "> ", ""))
+    }
+
+    return list
+}
diff --git a/dokka-json/src/test/kotlin/com/copperleaf/dokka/json/test/kotlin/KotlinClass.kt b/dokka-json/src/test/kotlin/com/copperleaf/dokka/json/test/kotlin/KotlinClass.kt
index d1e8aee..ae37297 100644
--- a/dokka-json/src/test/kotlin/com/copperleaf/dokka/json/test/kotlin/KotlinClass.kt
+++ b/dokka-json/src/test/kotlin/com/copperleaf/dokka/json/test/kotlin/KotlinClass.kt
@@ -1,5 +1,7 @@
 package com.copperleaf.dokka.json.test.kotlin
 
+import java.io.Serializable
+
 /**
  * This is a Kotlin class
  */
@@ -40,7 +42,7 @@ class KotlinClass(
     /**
      * This is a property defined in the class body, using an internal type
      */
-    lateinit var genericProperty: List<(String?)->String>
+    lateinit var genericProperty: List<(String?) -> String>
 
     /**
      * This is a method defined in the class body
@@ -93,7 +95,7 @@ class KotlinClass(
      * @param param This is the param1 for the method
      * @return This is the returned string value
      */
-    fun classMethodWithFunctionParameter(param: (String)->String): String? {
+    fun classMethodWithFunctionParameter(param: (String) -> String): String? {
         return null
     }
 
@@ -103,7 +105,7 @@ class KotlinClass(
      * @param param This is the param1 for the method
      * @return This is the returned string value
      */
-    fun classMethodWithInternalFunctionParameter(param: (KotlinInterface?, (String?, Int)->String?)->KotlinMarkdown?): KotlinMarkdown? {
+    fun classMethodWithInternalFunctionParameter(param: (KotlinInterface?, (String?, Int) -> String?) -> KotlinMarkdown?): KotlinMarkdown? {
         return null
     }
 
@@ -113,7 +115,7 @@ class KotlinClass(
      * @param param This is the param1 for the method
      * @return This is the returned string value
      */
-    fun classMethodWithReceiverFunctionParameter(param: KotlinInterface.(String?)->KotlinMarkdown?): KotlinMarkdown? {
+    fun classMethodWithReceiverFunctionParameter(param: KotlinInterface.(String?) -> KotlinMarkdown?): KotlinMarkdown? {
         return null
     }
 
@@ -123,7 +125,7 @@ class KotlinClass(
      * @param param This is the param1 for the method
      * @return This is the returned string value
      */
-    fun classMethodWithGenericReceiverFunctionParameter(param: List<String?>?.(List<String?>?)->List<String?>?): List<String?>? {
+    fun classMethodWithGenericReceiverFunctionParameter(param: List<String?>?.(List<String?>?) -> List<String?>?): List<String?>? {
         return null
     }
 
@@ -143,7 +145,7 @@ class KotlinClass(
      * @receiver This is the receiver for the method
      * @return This is the returned string value
      */
-    fun  String?.methodWithReceiver() {
+    fun String?.methodWithReceiver() {
 
     }
 
@@ -153,7 +155,7 @@ class KotlinClass(
      * @receiver This is the receiver for the method
      * @return This is the returned string value
      */
-    fun  List<String>.methodWithReceiverTypeParameter() {
+    fun List<String>.methodWithReceiverTypeParameter() {
 
     }
 
@@ -163,7 +165,7 @@ class KotlinClass(
      * @receiver This is the receiver for the method
      * @return This is the returned string value
      */
-    fun  KotlinMarkdown?.methodWithInternalReceiver() {
+    fun KotlinMarkdown?.methodWithInternalReceiver() {
 
     }
 
@@ -185,4 +187,32 @@ class KotlinClass(
         return null
     }
 
-}
\ No newline at end of file
+}
+
+@Suppress("UNUSED_PARAMETER")
+open class KotlinClass2
+
+@Suppress("UNUSED_PARAMETER")
+abstract class KotlinClass3
+
+@Suppress("UNUSED_PARAMETER")
+public class KotlinClass4
+
+@Suppress("UNUSED_PARAMETER")
+private class KotlinClass5
+
+@Suppress("UNUSED_PARAMETER")
+internal class KotlinClass6
+
+@Suppress("UNUSED_PARAMETER")
+data class KotlinClass7(val s: String)
+
+@Suppress("UNUSED_PARAMETER")
+sealed class KotlinClass8
+
+@Suppress("UNUSED_PARAMETER")
+enum class KotlinClass9
+
+@Suppress("UNUSED_PARAMETER")
+abstract class KotlinClass10<T : List<U>, U> : KotlinClass8(), List<T>, Serializable
+