aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Formats/HtmlFormatService.kt4
-rw-r--r--src/Formats/MarkdownFormatService.kt2
-rw-r--r--src/Formats/StructuredFormatService.kt28
-rw-r--r--src/Kotlin/ContentBuilder.kt19
-rw-r--r--src/Kotlin/DocumentationBuilder.kt15
-rw-r--r--src/Kotlin/KotlinLanguageService.kt12
-rw-r--r--src/Model/DocumentationNode.kt3
-rw-r--r--test/data/classes/classWithClassObject.kt7
-rw-r--r--test/data/format/classWithClassObject.html44
-rw-r--r--test/data/format/classWithClassObject.kt7
-rw-r--r--test/data/format/classWithClassObject.md30
-rw-r--r--test/data/format/htmlEscaping.html12
-rw-r--r--test/data/format/htmlEscaping.kt4
-rw-r--r--test/data/format/overloads.html24
-rw-r--r--test/data/format/overloads.kt5
-rw-r--r--test/src/TestAPI.kt4
-rw-r--r--test/src/format/HtmlFormatTest.kt27
-rw-r--r--test/src/format/MarkdownFormatTest.kt8
-rw-r--r--test/src/model/ClassTest.kt32
19 files changed, 261 insertions, 26 deletions
diff --git a/src/Formats/HtmlFormatService.kt b/src/Formats/HtmlFormatService.kt
index 48291b48..b23e4a45 100644
--- a/src/Formats/HtmlFormatService.kt
+++ b/src/Formats/HtmlFormatService.kt
@@ -35,7 +35,7 @@ public open class HtmlFormatService(locationService: LocationService,
to.appendln("<h$level>${text}</h$level>")
}
- override fun appendText(to: StringBuilder, text: String) {
+ override fun appendParagraph(to: StringBuilder, text: String) {
to.appendln("<p>${text}</p>")
}
@@ -94,7 +94,7 @@ public open class HtmlFormatService(locationService: LocationService,
}
override fun formatCode(code: String): String {
- return "<code>${code.htmlEscape()}</code>"
+ return "<code>${code}</code>"
}
override fun formatList(text: String): String {
diff --git a/src/Formats/MarkdownFormatService.kt b/src/Formats/MarkdownFormatService.kt
index 9849c674..96f64eec 100644
--- a/src/Formats/MarkdownFormatService.kt
+++ b/src/Formats/MarkdownFormatService.kt
@@ -62,7 +62,7 @@ public open class MarkdownFormatService(locationService: LocationService,
to.appendln(text)
}
- override public fun appendText(to: StringBuilder, text: String) {
+ override public fun appendParagraph(to: StringBuilder, text: String) {
to.appendln()
to.appendln(text)
to.appendln()
diff --git a/src/Formats/StructuredFormatService.kt b/src/Formats/StructuredFormatService.kt
index adfac99c..2d326854 100644
--- a/src/Formats/StructuredFormatService.kt
+++ b/src/Formats/StructuredFormatService.kt
@@ -10,7 +10,7 @@ public abstract class StructuredFormatService(val locationService: LocationServi
abstract public fun appendBlockCode(to: StringBuilder, line: String)
abstract public fun appendBlockCode(to: StringBuilder, lines: Iterable<String>)
abstract public fun appendHeader(to: StringBuilder, text: String, level: Int = 1)
- abstract public fun appendText(to: StringBuilder, text: String)
+ abstract public fun appendParagraph(to: StringBuilder, text: String)
abstract public fun appendLine(to: StringBuilder, text: String)
public abstract fun appendLine(to: StringBuilder)
@@ -41,7 +41,7 @@ public abstract class StructuredFormatService(val locationService: LocationServi
open fun formatText(location: Location, content: ContentNode): String {
return StringBuilder {
when (content) {
- is ContentText -> append(content.text)
+ is ContentText -> append(formatText(content.text))
is ContentSymbol -> append(formatSymbol(content.text))
is ContentKeyword -> append(formatKeyword(content.text))
is ContentIdentifier -> append(formatIdentifier(content.text))
@@ -61,7 +61,7 @@ public abstract class StructuredFormatService(val locationService: LocationServi
append(formatLink(linkText, content.href))
}
is ContentParagraph -> {
- appendText(this, formatText(location, content.children))
+ appendParagraph(this, formatText(location, content.children))
}
is ContentBlockCode -> {
appendBlockCode(this, formatText(location, content.children))
@@ -143,17 +143,23 @@ public abstract class StructuredFormatService(val locationService: LocationServi
for ((memberLocation, members) in membersMap) {
appendTableRow(to) {
appendTableCell(to) {
- appendText(to, formatLink(memberLocation))
+ to.append(formatLink(memberLocation))
}
appendTableCell(to) {
val breakdownBySummary = members.groupBy { formatText(location, it.summary) }
for ((summary, items) in breakdownBySummary) {
- for (signature in items) {
- appendBlockCode(to, formatText(location, languageService.render(signature)))
+ val signatureTexts = items map { signature ->
+ val signature = languageService.render(signature)
+ val signatureAsCode = ContentCode()
+ signatureAsCode.append(signature)
+ formatText(location, signatureAsCode)
}
-
+ signatureTexts.subList(0, signatureTexts.size()-1).forEach {
+ appendLine(to, it)
+ }
+ to.append(signatureTexts.last())
if (!summary.isEmpty()) {
- appendText(to, summary)
+ to.append(summary)
}
}
}
@@ -187,6 +193,8 @@ public abstract class StructuredFormatService(val locationService: LocationServi
appendSection(location, "Constructors", node.members(DocumentationNode.Kind.Constructor), node, to)
appendSection(location, "Properties", node.members(DocumentationNode.Kind.Property), node, to)
appendSection(location, "Functions", node.members(DocumentationNode.Kind.Function), node, to)
+ appendSection(location, "Class Object Properties", node.members(DocumentationNode.Kind.ClassObjectProperty), node, to)
+ appendSection(location, "Class Object Functions", node.members(DocumentationNode.Kind.ClassObjectFunction), node, to)
appendSection(location, "Accessors", node.members(DocumentationNode.Kind.PropertyAccessor), node, to)
appendSection(location, "Other members", node.members.filter {
it.kind !in setOf(
@@ -197,7 +205,9 @@ public abstract class StructuredFormatService(val locationService: LocationServi
DocumentationNode.Kind.Property,
DocumentationNode.Kind.Package,
DocumentationNode.Kind.Function,
- DocumentationNode.Kind.PropertyAccessor
+ DocumentationNode.Kind.PropertyAccessor,
+ DocumentationNode.Kind.ClassObjectProperty,
+ DocumentationNode.Kind.ClassObjectFunction
)
}, node, to)
appendSection(location, "Extensions", node.extensions, node, to)
diff --git a/src/Kotlin/ContentBuilder.kt b/src/Kotlin/ContentBuilder.kt
index 0c82a522..0143feed 100644
--- a/src/Kotlin/ContentBuilder.kt
+++ b/src/Kotlin/ContentBuilder.kt
@@ -101,6 +101,17 @@ public fun DocumentationBuilder.buildContent(tree: MarkdownNode, descriptor: Dec
processChildren()
parent.append(nodeStack.pop())
}
+ MarkdownTokenTypes.COLON -> {
+ // TODO fix markdown parser
+ if (!isColonAfterSectionLabel(node)) {
+ parent.append(ContentText(node.text))
+ }
+ }
+ MarkdownTokenTypes.DOUBLE_QUOTE,
+ MarkdownTokenTypes.LT,
+ MarkdownTokenTypes.GT -> {
+ parent.append(ContentText(node.text))
+ }
else -> {
processChildren()
}
@@ -147,4 +158,10 @@ private fun DocumentationBuilder.resolveInScope(functionName: String, scope: Jet
}
return symbol
-} \ No newline at end of file
+}
+
+private fun isColonAfterSectionLabel(node: MarkdownNode): Boolean {
+ val parent = node.parent
+ return parent != null && parent.type == MarkdownElementTypes.SECTION && parent.children.size() >= 2 &&
+ node == parent.children[1];
+}
diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt
index d2c07200..aeea4a55 100644
--- a/src/Kotlin/DocumentationBuilder.kt
+++ b/src/Kotlin/DocumentationBuilder.kt
@@ -161,11 +161,13 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
if (getKind() != ClassKind.OBJECT) {
node.appendChildren(getTypeConstructor().getParameters(), DocumentationReference.Kind.Detail)
node.appendChildren(getConstructors(), DocumentationReference.Kind.Member)
- val classObjectDescriptor = getClassObjectDescriptor()
- if (classObjectDescriptor != null)
- node.appendChild(classObjectDescriptor, DocumentationReference.Kind.Member)
}
node.appendChildren(getDefaultType().getMemberScope().getAllDescriptors(), DocumentationReference.Kind.Member)
+ val classObjectDescriptor = getClassObjectDescriptor()
+ if (classObjectDescriptor != null) {
+ node.appendChildren(classObjectDescriptor.getDefaultType().getMemberScope().getAllDescriptors(),
+ DocumentationReference.Kind.Member)
+ }
register(this, node)
return node
}
@@ -177,8 +179,11 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
return node
}
+ private fun DeclarationDescriptor.inClassObject() =
+ getContainingDeclaration().let { it is ClassDescriptor && it.getKind() == ClassKind.CLASS_OBJECT }
+
fun FunctionDescriptor.build(): DocumentationNode {
- val node = DocumentationNode(this, Kind.Function)
+ val node = DocumentationNode(this, if (inClassObject()) Kind.ClassObjectFunction else Kind.Function)
node.appendChildren(getTypeParameters(), DocumentationReference.Kind.Detail)
getExtensionReceiverParameter()?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
@@ -201,7 +206,7 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
}
fun PropertyDescriptor.build(): DocumentationNode {
- val node = DocumentationNode(this, Kind.Property)
+ val node = DocumentationNode(this, if (inClassObject()) Kind.ClassObjectProperty else Kind.Property)
node.appendChildren(getTypeParameters(), DocumentationReference.Kind.Detail)
getExtensionReceiverParameter()?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
node.appendType(getReturnType())
diff --git a/src/Kotlin/KotlinLanguageService.kt b/src/Kotlin/KotlinLanguageService.kt
index c9275879..a4016849 100644
--- a/src/Kotlin/KotlinLanguageService.kt
+++ b/src/Kotlin/KotlinLanguageService.kt
@@ -31,8 +31,10 @@ class KotlinLanguageService : LanguageService {
DocumentationNode.Kind.Modifier -> renderModifier(node)
DocumentationNode.Kind.Constructor,
- DocumentationNode.Kind.Function -> renderFunction(node)
- DocumentationNode.Kind.Property -> renderProperty(node)
+ DocumentationNode.Kind.Function,
+ DocumentationNode.Kind.ClassObjectFunction -> renderFunction(node)
+ DocumentationNode.Kind.Property,
+ DocumentationNode.Kind.ClassObjectProperty -> renderProperty(node)
else -> ContentText("${node.kind}: ${node.name}")
}
}
@@ -189,7 +191,8 @@ class KotlinLanguageService : LanguageService {
renderModifiersForNode(node)
when (node.kind) {
DocumentationNode.Kind.Constructor -> identifier(node.owner!!.name)
- DocumentationNode.Kind.Function -> keyword("fun ")
+ DocumentationNode.Kind.Function,
+ DocumentationNode.Kind.ClassObjectFunction -> keyword("fun ")
else -> throw IllegalArgumentException("Node $node is not a function-like object")
}
renderTypeParametersForNode(node)
@@ -216,7 +219,8 @@ class KotlinLanguageService : LanguageService {
private fun ContentNode.renderProperty(node: DocumentationNode) {
renderModifiersForNode(node)
when (node.kind) {
- DocumentationNode.Kind.Property -> keyword("val ")
+ DocumentationNode.Kind.Property,
+ DocumentationNode.Kind.ClassObjectProperty -> keyword("val ")
else -> throw IllegalArgumentException("Node $node is not a property")
}
renderTypeParametersForNode(node)
diff --git a/src/Model/DocumentationNode.kt b/src/Model/DocumentationNode.kt
index c2d7e3fb..86d2ee04 100644
--- a/src/Model/DocumentationNode.kt
+++ b/src/Model/DocumentationNode.kt
@@ -70,6 +70,9 @@ public open class DocumentationNode(val name: String,
Property
PropertyAccessor
+ ClassObjectProperty
+ ClassObjectFunction
+
Parameter
Receiver
TypeParameter
diff --git a/test/data/classes/classWithClassObject.kt b/test/data/classes/classWithClassObject.kt
new file mode 100644
index 00000000..459efad6
--- /dev/null
+++ b/test/data/classes/classWithClassObject.kt
@@ -0,0 +1,7 @@
+class Klass() {
+ class object {
+ val x = 1
+
+ fun foo() {}
+ }
+}
diff --git a/test/data/format/classWithClassObject.html b/test/data/format/classWithClassObject.html
new file mode 100644
index 00000000..79546418
--- /dev/null
+++ b/test/data/format/classWithClassObject.html
@@ -0,0 +1,44 @@
+<HTML>
+<HEAD>
+</HEAD>
+<BODY>
+<a href="out.html">test</a>&nbsp;/&nbsp;<a href="out.html"></a>&nbsp;/&nbsp;<a href="out.html">Klass</a><br/>
+<br/>
+<h1>Klass</h1>
+<pre><code><span class="keyword">class </span><span class="identifier">Klass</span></code></pre><br/>
+<br/>
+<h3>Constructors</h3>
+<table>
+<tbody>
+<tr>
+<td>
+<a href="out.html">&lt;init&gt;</a></td>
+<td>
+<code><span class="keyword">public</span> <span class="identifier">Klass</span><span class="symbol">(</span><span class="symbol">)</span></code></td>
+</tr>
+</tbody>
+</table>
+<h3>Class Object Properties</h3>
+<table>
+<tbody>
+<tr>
+<td>
+<a href="out.html">x</a></td>
+<td>
+<code><span class="keyword">val </span><span class="identifier">x</span><span class="symbol">: </span><span class="identifier">Int</span></code></td>
+</tr>
+</tbody>
+</table>
+<h3>Class Object Functions</h3>
+<table>
+<tbody>
+<tr>
+<td>
+<a href="out.html">foo</a></td>
+<td>
+<code><span class="keyword">fun </span><span class="identifier">foo</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code></td>
+</tr>
+</tbody>
+</table>
+</BODY>
+</HTML>
diff --git a/test/data/format/classWithClassObject.kt b/test/data/format/classWithClassObject.kt
new file mode 100644
index 00000000..459efad6
--- /dev/null
+++ b/test/data/format/classWithClassObject.kt
@@ -0,0 +1,7 @@
+class Klass() {
+ class object {
+ val x = 1
+
+ fun foo() {}
+ }
+}
diff --git a/test/data/format/classWithClassObject.md b/test/data/format/classWithClassObject.md
new file mode 100644
index 00000000..f694a76f
--- /dev/null
+++ b/test/data/format/classWithClassObject.md
@@ -0,0 +1,30 @@
+[test](out.md) / [](out.md) / [Klass](out.md)
+
+
+# Klass
+
+
+```
+class Klass
+```
+
+
+
+
+### Constructors
+
+
+| [&lt;init&gt;](out.md) | `public Klass()` |
+
+
+### Class Object Properties
+
+
+| [x](out.md) | `val x: Int` |
+
+
+### Class Object Functions
+
+
+| [foo](out.md) | `fun foo(): Unit` |
+
diff --git a/test/data/format/htmlEscaping.html b/test/data/format/htmlEscaping.html
new file mode 100644
index 00000000..4f1409c4
--- /dev/null
+++ b/test/data/format/htmlEscaping.html
@@ -0,0 +1,12 @@
+<HTML>
+<HEAD>
+</HEAD>
+<BODY>
+<a href="out.html">test</a>&nbsp;/&nbsp;<a href="out.html"></a>&nbsp;/&nbsp;<a href="out.html">x</a><br/>
+<br/>
+<h1>x</h1>
+<pre><code><span class="keyword">fun </span><span class="symbol">&lt;</span><span class="identifier">T</span><span class="symbol">&gt; </span><span class="identifier">x</span><span class="symbol">(</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">T?</span></code></pre><p>Special characters: &lt; is "less than", &gt; is "greater than", &amp; is "ampersand"</p>
+<br/>
+<br/>
+</BODY>
+</HTML>
diff --git a/test/data/format/htmlEscaping.kt b/test/data/format/htmlEscaping.kt
new file mode 100644
index 00000000..8778d8a5
--- /dev/null
+++ b/test/data/format/htmlEscaping.kt
@@ -0,0 +1,4 @@
+/**
+ * Special characters: < is "less than", > is "greater than", & is "ampersand"
+ */
+fun x<T>(): T? = null
diff --git a/test/data/format/overloads.html b/test/data/format/overloads.html
new file mode 100644
index 00000000..9ea88869
--- /dev/null
+++ b/test/data/format/overloads.html
@@ -0,0 +1,24 @@
+<HTML>
+<HEAD>
+</HEAD>
+<BODY>
+<a href="out.html">test</a>&nbsp;/&nbsp;<a href="out.html"></a><br/>
+<br/>
+<h1></h1>
+<pre><code><span class="keyword">package</span> <span class="identifier"></span></code></pre><br/>
+<br/>
+<h3>Functions</h3>
+<table>
+<tbody>
+<tr>
+<td>
+<a href="out.html">f</a></td>
+<td>
+<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier">x</span><span class="symbol">: </span><span class="identifier">Int</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
+<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier">x</span><span class="symbol">: </span><span class="identifier">String</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><p>Performs an action on x.</p>
+</td>
+</tr>
+</tbody>
+</table>
+</BODY>
+</HTML>
diff --git a/test/data/format/overloads.kt b/test/data/format/overloads.kt
new file mode 100644
index 00000000..dcd2d097
--- /dev/null
+++ b/test/data/format/overloads.kt
@@ -0,0 +1,5 @@
+/** Performs an action on x. */
+fun f(x: Int) { }
+
+/** Performs an action on x. */
+fun f(x: String) { }
diff --git a/test/src/TestAPI.kt b/test/src/TestAPI.kt
index a16a0b57..cc09f001 100644
--- a/test/src/TestAPI.kt
+++ b/test/src/TestAPI.kt
@@ -51,11 +51,11 @@ public fun verifyModel(vararg files: String, verifier: (DocumentationModule) ->
Disposer.dispose(environment)
}
-public fun verifyOutput(path: String, outputGenerator: (DocumentationModule, StringBuilder) -> Unit) {
+public fun verifyOutput(path: String, outputExtension: String, outputGenerator: (DocumentationModule, StringBuilder) -> Unit) {
verifyModel(path) {
val output = StringBuilder()
outputGenerator(it, output)
- val expectedOutput = File(path.replace(".kt", ".md")).readText()
+ val expectedOutput = File(path.replace(".kt", outputExtension)).readText()
assertEquals(expectedOutput, output.toString())
}
}
diff --git a/test/src/format/HtmlFormatTest.kt b/test/src/format/HtmlFormatTest.kt
new file mode 100644
index 00000000..881a7828
--- /dev/null
+++ b/test/src/format/HtmlFormatTest.kt
@@ -0,0 +1,27 @@
+package org.jetbrains.dokka.tests
+
+import org.jetbrains.dokka.KotlinLanguageService
+import org.junit.Test
+import org.jetbrains.dokka.HtmlFormatService
+
+public class HtmlFormatTest {
+ private val htmlService = HtmlFormatService(InMemoryLocationService, KotlinLanguageService())
+
+ Test fun classWithClassObject() {
+ verifyOutput("test/data/format/classWithClassObject.kt", ".html") { model, output ->
+ htmlService.appendNodes(tempLocation, output, model.members.single().members)
+ }
+ }
+
+ Test fun htmlEscaping() {
+ verifyOutput("test/data/format/htmlEscaping.kt", ".html") { model, output ->
+ htmlService.appendNodes(tempLocation, output, model.members.single().members)
+ }
+ }
+
+ Test fun overloads() {
+ verifyOutput("test/data/format/overloads.kt", ".html") { model, output ->
+ htmlService.appendNodes(tempLocation, output, model.members)
+ }
+ }
+}
diff --git a/test/src/format/MarkdownFormatTest.kt b/test/src/format/MarkdownFormatTest.kt
index beb727da..5cdfb8b5 100644
--- a/test/src/format/MarkdownFormatTest.kt
+++ b/test/src/format/MarkdownFormatTest.kt
@@ -9,7 +9,13 @@ public class MarkdownFormatTest {
private val markdownService = MarkdownFormatService(InMemoryLocationService, KotlinLanguageService())
Test fun emptyDescription() {
- verifyOutput("test/data/format/emptyDescription.kt") { model, output ->
+ verifyOutput("test/data/format/emptyDescription.kt", ".md") { model, output ->
+ markdownService.appendNodes(tempLocation, output, model.members.single().members)
+ }
+ }
+
+ Test fun classWithClassObject() {
+ verifyOutput("test/data/format/classWithClassObject.kt", ".md") { model, output ->
markdownService.appendNodes(tempLocation, output, model.members.single().members)
}
}
diff --git a/test/src/model/ClassTest.kt b/test/src/model/ClassTest.kt
index 65363c92..b95a31dc 100644
--- a/test/src/model/ClassTest.kt
+++ b/test/src/model/ClassTest.kt
@@ -136,4 +136,34 @@ public class ClassTest {
}
}
}
-} \ No newline at end of file
+
+ Test fun classWithClassObject() {
+ verifyModel("test/data/classes/classWithClassObject.kt") { model ->
+ with(model.members.single().members.single()) {
+ assertEquals(DocumentationNode.Kind.Class, kind)
+ assertEquals("Klass", name)
+ assertEquals(Content.Empty, content)
+ assertEquals(2, details.count())
+ assertTrue(links.none())
+
+ assertEquals(3, members.count())
+ with(members.elementAt(0)) {
+ assertEquals("<init>", name)
+ assertEquals(Content.Empty, content)
+ }
+ with(members.elementAt(1)) {
+ assertEquals("x", name)
+ assertEquals(DocumentationNode.Kind.ClassObjectProperty, kind)
+ assertTrue(members.none())
+ assertTrue(links.none())
+ }
+ with(members.elementAt(2)) {
+ assertEquals("foo", name)
+ assertEquals(DocumentationNode.Kind.ClassObjectFunction, kind)
+ assertTrue(members.none())
+ assertTrue(links.none())
+ }
+ }
+ }
+ }
+}