diff options
-rw-r--r-- | src/Formats/HtmlFormatService.kt | 4 | ||||
-rw-r--r-- | src/Formats/MarkdownFormatService.kt | 2 | ||||
-rw-r--r-- | src/Formats/StructuredFormatService.kt | 28 | ||||
-rw-r--r-- | src/Kotlin/ContentBuilder.kt | 19 | ||||
-rw-r--r-- | src/Kotlin/DocumentationBuilder.kt | 15 | ||||
-rw-r--r-- | src/Kotlin/KotlinLanguageService.kt | 12 | ||||
-rw-r--r-- | src/Model/DocumentationNode.kt | 3 | ||||
-rw-r--r-- | test/data/classes/classWithClassObject.kt | 7 | ||||
-rw-r--r-- | test/data/format/classWithClassObject.html | 44 | ||||
-rw-r--r-- | test/data/format/classWithClassObject.kt | 7 | ||||
-rw-r--r-- | test/data/format/classWithClassObject.md | 30 | ||||
-rw-r--r-- | test/data/format/htmlEscaping.html | 12 | ||||
-rw-r--r-- | test/data/format/htmlEscaping.kt | 4 | ||||
-rw-r--r-- | test/data/format/overloads.html | 24 | ||||
-rw-r--r-- | test/data/format/overloads.kt | 5 | ||||
-rw-r--r-- | test/src/TestAPI.kt | 4 | ||||
-rw-r--r-- | test/src/format/HtmlFormatTest.kt | 27 | ||||
-rw-r--r-- | test/src/format/MarkdownFormatTest.kt | 8 | ||||
-rw-r--r-- | test/src/model/ClassTest.kt | 32 |
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> / <a href="out.html"></a> / <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"><init></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 + + +| [<init>](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> / <a href="out.html"></a> / <a href="out.html">x</a><br/> +<br/> +<h1>x</h1> +<pre><code><span class="keyword">fun </span><span class="symbol"><</span><span class="identifier">T</span><span class="symbol">> </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: < is "less than", > is "greater than", & 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> / <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()) + } + } + } + } +} |