aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
diff options
context:
space:
mode:
authorSimon Ogorodnik <Simon.Ogorodnik@jetbrains.com>2018-01-18 03:45:26 +0300
committerSimon Ogorodnik <Simon.Ogorodnik@jetbrains.com>2018-01-18 03:45:26 +0300
commit1ffced5e6af4d04597c0a02e138785c25b2f1e5f (patch)
tree3a9d6bdd063c2f49dfa6a1e6df27dd73181edf5d /core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
parentbf2945df90b7cbed5b713a396585fc1376fb1a9a (diff)
downloaddokka-1ffced5e6af4d04597c0a02e138785c25b2f1e5f.tar.gz
Refactor OutputBuilder to decouple data extraction from structure
Diffstat (limited to 'core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt')
-rw-r--r--core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt713
1 files changed, 444 insertions, 269 deletions
diff --git a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
index 1116c6c59..9ea5e9e4d 100644
--- a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
+++ b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
@@ -12,19 +12,90 @@ import javax.inject.Inject
open class JavaLayoutHtmlFormatOutputBuilder(
- val output: Appendable,
- val languageService: LanguageService,
- val uriProvider: JavaLayoutHtmlUriProvider,
- val templateService: JavaLayoutHtmlTemplateService,
- val logger: DokkaLogger,
- val uri: URI
+ val output: Appendable,
+ val languageService: LanguageService,
+ val uriProvider: JavaLayoutHtmlUriProvider,
+ val templateService: JavaLayoutHtmlTemplateService,
+ val logger: DokkaLogger,
+ val uri: URI
) {
val htmlConsumer = output.appendHTML()
- val contentToHtmlBuilder = ContentToHtmlBuilder(uriProvider, uri)
- open fun <T> FlowContent.summaryNodeGroup(nodes: Iterable<T>, header: String, headerAsRow: Boolean = false, row: TBODY.(T) -> Unit) {
+ private fun FlowContent.hN(
+ level: Int,
+ classes: String? = null,
+ block: CommonAttributeGroupFacadeFlowHeadingPhrasingContent.() -> Unit
+ ) {
+ when (level) {
+ 1 -> h1(classes, block)
+ 2 -> h2(classes, block)
+ 3 -> h3(classes, block)
+ 4 -> h4(classes, block)
+ 5 -> h5(classes, block)
+ 6 -> h6(classes, block)
+ }
+ }
+
+ fun FlowContent.metaMarkup(content: List<ContentNode>): Unit = content.forEach { metaMarkup(it) }
+ fun FlowContent.metaMarkup(content: ContentNode) {
+ when (content) {
+ is ContentText -> +content.text
+ is ContentSymbol -> span("symbol") { +content.text }
+ is ContentKeyword -> span("keyword") { +content.text }
+ is ContentIdentifier -> span("identifier") {
+ content.signature?.let { id = it }
+ +content.text
+ }
+
+ is ContentHeading -> hN(level = content.level) { metaMarkup(content.children) }
+
+ is ContentEntity -> +content.text
+
+ is ContentStrong -> strong { metaMarkup(content.children) }
+ is ContentStrikethrough -> del { metaMarkup(content.children) }
+ is ContentEmphasis -> em { metaMarkup(content.children) }
+
+ is ContentOrderedList -> ol { metaMarkup(content.children) }
+ is ContentUnorderedList -> ul { metaMarkup(content.children) }
+ is ContentListItem -> consumer.li {
+ (content.children.singleOrNull() as? ContentParagraph)
+ ?.let { paragraph -> metaMarkup(paragraph.children) }
+ ?: metaMarkup(content.children)
+ }
+
+
+ is ContentCode -> pre { code { metaMarkup(content.children) } }
+ is ContentBlockSampleCode -> pre { code {} }
+ is ContentBlockCode -> pre { code {} }
+
+
+ is ContentNonBreakingSpace -> +nbsp
+ is ContentSoftLineBreak, is ContentIndentedSoftLineBreak -> {
+ }
+
+ is ContentParagraph -> p { metaMarkup(content.children) }
+
+ is ContentNodeLink -> {
+ val href = content.node?.let { uriProvider.linkTo(it, uri) } ?: "#"
+ a(href = href) { metaMarkup(content.children) }
+ }
+ is ContentExternalLink -> {
+ a(href = content.href) { metaMarkup(content.children) }
+ }
+
+ is ContentBlock -> metaMarkup(content.children)
+ }
+ }
+
+
+ protected open fun <T> FlowContent.summaryNodeGroup(
+ nodes: Iterable<T>,
+ header: String,
+ headerAsRow: Boolean = true,
+ row: TBODY.(T) -> Unit
+ ) {
if (nodes.none()) return
if (!headerAsRow) {
h2 { +header }
@@ -39,38 +110,31 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
- fun FlowContent.metaMarkup(content: ContentNode) = with(contentToHtmlBuilder) {
- appendContent(content)
- }
-
- fun FlowContent.metaMarkup(content: List<ContentNode>) = with(contentToHtmlBuilder) {
- appendContent(content)
- }
- open fun TBODY.classLikeRow(node: DocumentationNode) = tr {
+ protected open fun TBODY.classLikeRow(node: DocumentationNode) = tr {
td { a(href = uriProvider.linkTo(node, uri)) { +node.simpleName() } }
td { metaMarkup(node.summary) }
}
- fun FlowContent.modifiers(node: DocumentationNode) {
+ protected fun FlowContent.modifiers(node: DocumentationNode) {
for (modifier in node.details(NodeKind.Modifier)) {
renderedSignature(modifier, SUMMARY)
}
}
- fun FlowContent.shortFunctionParametersList(func: DocumentationNode) {
+ protected fun FlowContent.shortFunctionParametersList(func: DocumentationNode) {
val params = func.details(NodeKind.Parameter)
- .map { languageService.render(it, FULL) }
- .run {
- drop(1).fold(listOfNotNull(firstOrNull())) { acc, node ->
- acc + ContentText(", ") + node
- }
+ .map { languageService.render(it, FULL) }
+ .run {
+ drop(1).fold(listOfNotNull(firstOrNull())) { acc, node ->
+ acc + ContentText(", ") + node
}
+ }
metaMarkup(listOf(ContentText("(")) + params + listOf(ContentText(")")))
}
- open fun TBODY.functionLikeSummaryRow(node: DocumentationNode) = tr {
+ protected open fun TBODY.functionLikeSummaryRow(node: DocumentationNode) = tr {
if (node.kind != NodeKind.Constructor) {
td {
modifiers(node)
@@ -85,7 +149,7 @@ open class JavaLayoutHtmlFormatOutputBuilder(
renderedSignature(receiver.detail(NodeKind.Type), SUMMARY)
+"."
}
- a(href = uriProvider.linkTo(node, uri)) { +node.name }
+ a(href = node) { +node.name }
shortFunctionParametersList(node)
}
}
@@ -94,7 +158,7 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
- open fun TBODY.propertyLikeSummaryRow(node: DocumentationNode) = tr {
+ protected open fun TBODY.propertyLikeSummaryRow(node: DocumentationNode) = tr {
td {
modifiers(node)
renderedSignature(node.detail(NodeKind.Type), SUMMARY)
@@ -102,7 +166,7 @@ open class JavaLayoutHtmlFormatOutputBuilder(
td {
div {
code {
- a(href = uriProvider.linkTo(node, uri)) { +node.name }
+ a(href = node) { +node.name }
}
}
@@ -110,14 +174,14 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
- open fun TBODY.nestedClassSummaryRow(node: DocumentationNode) = tr {
+ protected open fun TBODY.nestedClassSummaryRow(node: DocumentationNode) = tr {
td {
modifiers(node)
}
td {
div {
code {
- a(href = uriProvider.linkTo(node, uri)) { +node.name }
+ a(href = node) { +node.name }
}
}
@@ -125,11 +189,14 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
- open fun TBODY.inheritRow(entry: Map.Entry<DocumentationNode, List<DocumentationNode>>, summaryRow: TBODY.(DocumentationNode) -> Unit) = tr {
+ protected open fun TBODY.inheritRow(
+ entry: Map.Entry<DocumentationNode, List<DocumentationNode>>,
+ summaryRow: TBODY.(DocumentationNode) -> Unit
+ ) = tr {
td {
val (from, nodes) = entry
+"From class "
- a(href = uriProvider.linkTo(from.owner!!, uri)) { +from.qualifiedName() }
+ a(href = from.owner!!) { +from.qualifiedName() }
table {
tbody {
for (node in nodes) {
@@ -140,11 +207,14 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
- open fun TBODY.extensionRow(entry: Map.Entry<DocumentationNode, List<DocumentationNode>>, summaryRow: TBODY.(DocumentationNode) -> Unit) = tr {
+ protected open fun TBODY.extensionRow(
+ entry: Map.Entry<DocumentationNode, List<DocumentationNode>>,
+ summaryRow: TBODY.(DocumentationNode) -> Unit
+ ) = tr {
td {
val (from, nodes) = entry
+"From "
- a(href = uriProvider.linkTo(from, uri)) { +from.qualifiedName() }
+ a(href = from) { +from.qualifiedName() }
table {
tbody {
for (node in nodes) {
@@ -155,63 +225,53 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
- private fun FlowContent.renderedSignature(node: DocumentationNode, mode: LanguageService.RenderMode = SUMMARY) {
- metaMarkup(languageService.render(node, mode))
+ protected open fun FlowContent.a(href: DocumentationNode, classes: String? = null, block: A.() -> Unit) {
+ val hrefText = if (href.kind == NodeKind.ExternalLink)
+ href.name
+ else
+ uriProvider.linkTo(href, uri)
+ a(href = hrefText, classes = classes, block = block)
}
- open fun FlowContent.memberDocs(node: DocumentationNode) {
- div {
- id = node.signatureForAnchor(logger)
- h3 { +node.name }
- pre { renderedSignature(node, FULL) }
- metaMarkup(node.content)
- for ((name, sections) in node.content.sections.groupBy { it.tag }) {
- table {
- thead { tr { td { h3 { +name } } } }
- tbody {
- sections.forEach {
- tr {
- td { it.subjectName?.let { +it } }
- td {
- metaMarkup(it.children)
- }
- }
- }
- }
- }
- }
- }
+ protected open fun FlowContent.renderedSignature(node: DocumentationNode, mode: LanguageService.RenderMode = SUMMARY) {
+ metaMarkup(languageService.render(node, mode))
}
- fun appendPackage(node: DocumentationNode) = templateService.composePage(
- listOf(node),
- htmlConsumer,
- headContent = {
-
- },
- bodyContent = {
- h1 { +node.name }
- metaMarkup(node.content)
- summaryNodeGroup(node.members(NodeKind.Class), "Classes") { classLikeRow(it) }
- summaryNodeGroup(node.members(NodeKind.Exception), "Exceptions") { classLikeRow(it) }
- summaryNodeGroup(node.members(NodeKind.TypeAlias), "Type-aliases") { classLikeRow(it) }
- summaryNodeGroup(node.members(NodeKind.AnnotationClass), "Annotations") { classLikeRow(it) }
- summaryNodeGroup(node.members(NodeKind.Enum), "Enums") { classLikeRow(it) }
-
- summaryNodeGroup(node.members(NodeKind.Function), "Top-level functions summary") { functionLikeSummaryRow(it) }
- summaryNodeGroup(node.members(NodeKind.Property), "Top-level properties summary") { propertyLikeSummaryRow(it) }
-
-
- fullDocs(node.members(NodeKind.Function), "Top-level functions") { memberDocs(it) }
- fullDocs(node.members(NodeKind.Property), "Top-level properties") { memberDocs(it) }
- }
+ protected open fun generatePackage(page: Page.PackagePage) = templateService.composePage(
+ page,
+ htmlConsumer,
+ headContent = {
+
+ },
+ bodyContent = {
+ h1 { +page.node.name }
+ metaMarkup(page.node.content)
+ summaryNodeGroup(page.classes, "Classes", headerAsRow = false) { classLikeRow(it) }
+ summaryNodeGroup(page.exceptions, "Exceptions", headerAsRow = false) { classLikeRow(it) }
+ summaryNodeGroup(page.typeAliases, "Type-aliases", headerAsRow = false) { classLikeRow(it) }
+ summaryNodeGroup(page.annotations, "Annotations", headerAsRow = false) { classLikeRow(it) }
+ summaryNodeGroup(page.enums, "Enums", headerAsRow = false) { classLikeRow(it) }
+
+ summaryNodeGroup(
+ page.functions,
+ "Top-level functions summary",
+ headerAsRow = false
+ ) { functionLikeSummaryRow(it) }
+ summaryNodeGroup(
+ page.properties,
+ "Top-level properties summary",
+ headerAsRow = false
+ ) { propertyLikeSummaryRow(it) }
+
+
+ fullMemberDocs(page.functions, "Top-level functions")
+ fullMemberDocs(page.properties, "Top-level properties")
+ }
)
- fun FlowContent.qualifiedTypeReference(node: DocumentationNode) {
+ protected fun FlowContent.qualifiedTypeReference(node: DocumentationNode) {
if (node.kind in classLike) {
- a(href = uriProvider.linkTo(node, uri)) {
- +node.qualifiedName()
- }
+ a(href = node) { +node.qualifiedName() }
return
}
@@ -222,12 +282,7 @@ open class JavaLayoutHtmlFormatOutputBuilder(
return
}
- val href = if (targetLink.kind == NodeKind.ExternalLink)
- targetLink.name
- else
- uriProvider.linkTo(targetLink, uri)
-
- a(href = href) {
+ a(href = targetLink) {
+node.qualifiedNameFromType()
}
val typeParameters = node.details(NodeKind.Type)
@@ -243,9 +298,7 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
- open fun FlowContent.classHierarchy(node: DocumentationNode) {
-
- val superclasses = (sequenceOf(node) + node.superclassTypeSequence).toList().asReversed()
+ protected open fun FlowContent.classHierarchy(superclasses: List<DocumentationNode>) {
table {
superclasses.forEach {
tr {
@@ -262,7 +315,7 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
- open fun FlowContent.subclasses(inheritors: List<DocumentationNode>, direct: Boolean) {
+ protected open fun FlowContent.subclasses(inheritors: List<DocumentationNode>, direct: Boolean) {
if (inheritors.isEmpty()) return
div {
table {
@@ -277,13 +330,13 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
tbody {
- inheritors.forEach {
+ inheritors.forEach { inheritor ->
tr {
td {
- a(href = uriProvider.linkTo(it, uri)) { +it.classNodeNameWithOuterClass() }
+ a(href = inheritor) { +inheritor.classNodeNameWithOuterClass() }
}
td {
- metaMarkup(it.summary)
+ metaMarkup(inheritor.summary)
}
}
}
@@ -292,152 +345,161 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
- fun appendClassLike(node: DocumentationNode) = templateService.composePage(
- listOf(node),
- htmlConsumer,
- headContent = {
-
- },
- bodyContent = {
- h1 { +node.name }
- pre { renderedSignature(node, FULL) }
- classHierarchy(node)
-
- val inheritors = generateSequence(node.inheritors) { inheritors ->
- inheritors
- .flatMap { it.inheritors }
- .takeUnless { it.isEmpty() }
- }
- subclasses(inheritors.first(), true)
- subclasses(inheritors.drop(1).flatten().toList(), false)
-
-
- metaMarkup(node.content)
-
- h2 { +"Summary" }
-
- val isCompanion = node.details(NodeKind.Modifier).any { it.name == "companion" }
- val hasMeaningfulCompanion = !isCompanion && node.companion != null
-
- fun DocumentationNode.thisTypeExtension() = detail(NodeKind.Receiver).detail(NodeKind.Type).links.any { it == node }
-
- val functionKind = if (!isCompanion) NodeKind.Function else NodeKind.CompanionObjectFunction
- val propertyKind = if (!isCompanion) NodeKind.Property else NodeKind.CompanionObjectProperty
+ protected open fun FlowContent.classLikeSummaries(page: Page.ClassPage) = with(page) {
+ summaryNodeGroup(
+ nestedClasses,
+ "Nested classes",
+ headerAsRow = true
+ ) {
+ nestedClassSummaryRow(it)
+ }
- fun DocumentationNode.isFunction() = kind == functionKind
- fun DocumentationNode.isProperty() = kind == propertyKind
+ summaryNodeGroup(
+ constructors,
+ "Constructors",
+ headerAsRow = true
+ ) {
+ functionLikeSummaryRow(it)
+ }
- val functions = node.members(functionKind)
- val properties = node.members(propertyKind)
- val inheritedFunctionsByReceiver = node.inheritedMembers(functionKind).groupBy { it.owner!! }
- val inheritedPropertiesByReceiver = node.inheritedMembers(propertyKind).groupBy { it.owner!! }
+ summaryNodeGroup(functions, "Functions", headerAsRow = true) { functionLikeSummaryRow(it) }
+ summaryNodeGroup(
+ companionFunctions,
+ "Companion functions",
+ headerAsRow = true
+ ) {
+ functionLikeSummaryRow(it)
+ }
+ summaryNodeGroup(
+ inheritedFunctionsByReceiver.entries,
+ "Inherited functions",
+ headerAsRow = true
+ ) {
+ inheritRow(it) {
+ functionLikeSummaryRow(it)
+ }
+ }
+ summaryNodeGroup(
+ extensionFunctions.entries,
+ "Extension functions",
+ headerAsRow = true
+ ) {
+ extensionRow(it) {
+ functionLikeSummaryRow(it)
+ }
+ }
+ summaryNodeGroup(
+ inheritedExtensionFunctions.entries,
+ "Inherited extension functions",
+ headerAsRow = true
+ ) {
+ extensionRow(it) {
+ functionLikeSummaryRow(it)
+ }
+ }
- val originalExtensions = if (!isCompanion) node.extensions else node.owner!!.extensions
- val (extensions, inheritedExtensions) = originalExtensions.partition { it.thisTypeExtension() }
- val extensionFunctions = extensions.filter(DocumentationNode::isFunction).groupBy { it.owner!! }
- val extensionProperties = extensions.filter(DocumentationNode::isProperty).groupBy { it.owner!! }
- val inheritedExtensionFunctions = inheritedExtensions.filter(DocumentationNode::isFunction).groupBy { it.owner!! }
- val inheritedExtensionProperties = inheritedExtensions.filter(DocumentationNode::isProperty).groupBy { it.owner!! }
+ summaryNodeGroup(properties, "Properties", headerAsRow = true) { propertyLikeSummaryRow(it) }
+ summaryNodeGroup(
+ companionProperties,
+ "Companion properties",
+ headerAsRow = true
+ ) {
+ propertyLikeSummaryRow(it)
+ }
- val companionFunctions = node.members(NodeKind.CompanionObjectFunction)
- val companionProperties = node.members(NodeKind.CompanionObjectProperty)
+ summaryNodeGroup(
+ inheritedPropertiesByReceiver.entries,
+ "Inherited properties",
+ headerAsRow = true
+ ) {
+ inheritRow(it) {
+ propertyLikeSummaryRow(it)
+ }
+ }
+ summaryNodeGroup(
+ extensionProperties.entries,
+ "Extension properties",
+ headerAsRow = true
+ ) {
+ extensionRow(it) {
+ propertyLikeSummaryRow(it)
+ }
+ }
+ summaryNodeGroup(
+ inheritedExtensionProperties.entries,
+ "Inherited extension properties",
+ headerAsRow = true
+ ) {
+ extensionRow(it) {
+ propertyLikeSummaryRow(it)
+ }
+ }
+ }
- summaryNodeGroup(node.members.filter { it.kind in NodeKind.classLike }, "Nested classes", headerAsRow = true) { nestedClassSummaryRow(it) }
+ protected open fun FlowContent.classLikeFullMemberDocs(page: Page.ClassPage) = with(page) {
+ fullMemberDocs(constructors, "Constructors")
+ fullMemberDocs(functions, "Functions")
+ fullMemberDocs(properties, "Properties")
+ if (!hasMeaningfulCompanion) {
+ fullMemberDocs(companionFunctions, "Companion functions")
+ fullMemberDocs(companionProperties, "Companion properties")
+ }
+ }
- summaryNodeGroup(node.members(NodeKind.Constructor), "Constructors", headerAsRow = true) { functionLikeSummaryRow(it) }
+ protected open fun generateClassLike(page: Page.ClassPage) = templateService.composePage(
+ page,
+ htmlConsumer,
+ headContent = {
- summaryNodeGroup(functions, "Functions", headerAsRow = true) { functionLikeSummaryRow(it) }
- if (!isCompanion) {
- summaryNodeGroup(companionFunctions, "Companion functions", headerAsRow = true) { functionLikeSummaryRow(it) }
- }
- summaryNodeGroup(inheritedFunctionsByReceiver.entries, "Inherited functions", headerAsRow = true) { inheritRow(it) { functionLikeSummaryRow(it) } }
- summaryNodeGroup(extensionFunctions.entries, "Extension functions", headerAsRow = true) { extensionRow(it) { functionLikeSummaryRow(it) } }
- summaryNodeGroup(inheritedExtensionFunctions.entries, "Inherited extension functions", headerAsRow = true) { extensionRow(it) { functionLikeSummaryRow(it) } }
+ },
+ bodyContent = {
+ val node = page.node
+ with(page) {
+ h1 { +node.name }
+ pre { renderedSignature(node, FULL) }
+ classHierarchy(page.superclasses)
+ subclasses(page.directInheritors, true)
+ subclasses(page.indirectInheritors, false)
- summaryNodeGroup(properties, "Properties", headerAsRow = true) { propertyLikeSummaryRow(it) }
- if (!isCompanion) {
- summaryNodeGroup(companionProperties, "Companion properties", headerAsRow = true) { propertyLikeSummaryRow(it) }
- }
- summaryNodeGroup(inheritedPropertiesByReceiver.entries, "Inherited properties", headerAsRow = true) { inheritRow(it) { propertyLikeSummaryRow(it) } }
- summaryNodeGroup(extensionProperties.entries, "Extension properties", headerAsRow = true) { extensionRow(it) { propertyLikeSummaryRow(it) } }
- summaryNodeGroup(inheritedExtensionProperties.entries, "Inherited extension properties", headerAsRow = true) { extensionRow(it) { propertyLikeSummaryRow(it) } }
+ metaMarkup(node.content)
+ h2 { +"Summary" }
+ classLikeSummaries(page)
- fullDocs(node.members(NodeKind.Constructor), "Constructors") { memberDocs(it) }
- fullDocs(functions, "Functions") { memberDocs(it) }
- fullDocs(properties, "Properties") { memberDocs(it) }
- if (!isCompanion && !hasMeaningfulCompanion) {
- fullDocs(companionFunctions, "Companion functions") { memberDocs(it) }
- fullDocs(companionProperties, "Companion properties") { memberDocs(it) }
- }
+ classLikeFullMemberDocs(page)
}
+ }
)
- fun generateClassesIndex(allTypesNode: DocumentationNode) = templateService.composePage(
- listOf(allTypesNode),
- htmlConsumer,
- headContent = {
-
- },
- bodyContent = {
- h1 { +"Class Index" }
+ protected open fun generateClassIndex(page: Page.ClassIndex) = templateService.composePage(
+ page,
+ htmlConsumer,
+ headContent = {
- fun DocumentationNode.classWithNestedClasses(): List<DocumentationNode> =
- members.filter { it.kind in classLike }.flatMap(DocumentationNode::classWithNestedClasses) + this
+ },
+ bodyContent = {
+ h1 { +"Class Index" }
- val classesByFirstLetter = allTypesNode.members
- .filterNot { it.kind == NodeKind.ExternalClass }
- .flatMap(DocumentationNode::classWithNestedClasses)
- .groupBy {
- it.classNodeNameWithOuterClass().first().toString()
- }
- .entries
- .sortedBy { (letter) -> letter }
- ul {
- classesByFirstLetter.forEach { (letter) ->
- li { a(href = "#letter_$letter") { +letter } }
- }
- }
-
- classesByFirstLetter.forEach { (letter, nodes) ->
- h2 {
- id = "letter_$letter"
- +letter
- }
- table {
- tbody {
- for (node in nodes.sortedBy { it.classNodeNameWithOuterClass() }) {
- tr {
- td {
- a(href = uriProvider.linkTo(node, uri)) { +node.classNodeNameWithOuterClass() }
- }
- td {
- metaMarkup(node.content)
- }
- }
- }
- }
- }
+ ul {
+ page.classesByFirstLetter.forEach { (letter) ->
+ li { a(href = "#letter_$letter") { +letter } }
}
}
- )
-
- fun generatePackageIndex(nodes: List<DocumentationNode>) = templateService.composePage(nodes,
- htmlConsumer,
- headContent = {
- },
- bodyContent = {
- h1 { +"Package Index" }
+ page.classesByFirstLetter.forEach { (letter, classes) ->
+ h2 {
+ id = "letter_$letter"
+ +letter
+ }
table {
tbody {
- for (node in nodes.sortedBy { it.name }) {
+ for (node in classes) {
tr {
td {
- a(href = uriProvider.linkTo(node, uri)) { +node.name }
+ a(href = uriProvider.linkTo(node, uri)) { +node.classNodeNameWithOuterClass() }
}
td {
metaMarkup(node.content)
@@ -447,93 +509,206 @@ open class JavaLayoutHtmlFormatOutputBuilder(
}
}
}
+ }
)
- private fun FlowContent.fullDocs(
- nodes: List<DocumentationNode>,
- header: String,
- renderNode: FlowContent.(DocumentationNode) -> Unit
+ protected open fun generatePackageIndex(page: Page.PackageIndex) = templateService.composePage(
+ page,
+ htmlConsumer,
+ headContent = {
+
+ },
+ bodyContent = {
+ h1 { +"Package Index" }
+ table {
+ tbody {
+ for (node in page.packages) {
+ tr {
+ td {
+ a(href = uriProvider.linkTo(node, uri)) { +node.name }
+ }
+ td {
+ metaMarkup(node.content)
+ }
+ }
+ }
+ }
+ }
+ }
+ )
+
+ fun generatePage(page: Page) {
+ when (page) {
+ is Page.PackageIndex -> generatePackageIndex(page)
+ is Page.ClassIndex -> generateClassIndex(page)
+ is Page.ClassPage -> generateClassLike(page)
+ is Page.PackagePage -> generatePackage(page)
+ }
+ }
+
+ protected fun FlowContent.fullMemberDocs(
+ nodes: List<DocumentationNode>,
+ header: String
) {
if (nodes.none()) return
h2 {
+header
}
for (node in nodes) {
- renderNode(node)
+ fullMemberDocs(node)
}
}
-}
-
-class ContentToHtmlBuilder(val uriProvider: JavaLayoutHtmlUriProvider, val uri: URI) {
- fun FlowContent.appendContent(content: List<ContentNode>): Unit = content.forEach { appendContent(it) }
- private fun FlowContent.hN(level: Int, classes: String? = null, block: CommonAttributeGroupFacadeFlowHeadingPhrasingContent.() -> Unit) {
- when (level) {
- 1 -> h1(classes, block)
- 2 -> h2(classes, block)
- 3 -> h3(classes, block)
- 4 -> h4(classes, block)
- 5 -> h5(classes, block)
- 6 -> h6(classes, block)
+ protected open fun FlowContent.fullMemberDocs(node: DocumentationNode) {
+ div {
+ id = node.signatureForAnchor(logger)
+ h3 { +node.name }
+ pre { renderedSignature(node, FULL) }
+ metaMarkup(node.content)
+ for ((name, sections) in node.content.sections.groupBy { it.tag }) {
+ table {
+ thead { tr { td { h3 { +name } } } }
+ tbody {
+ sections.forEach {
+ tr {
+ td { it.subjectName?.let { +it } }
+ td {
+ metaMarkup(it.children)
+ }
+ }
+ }
+ }
+ }
+ }
}
}
- fun FlowContent.appendContent(content: ContentNode) {
- when (content) {
- is ContentText -> +content.text
- is ContentSymbol -> span("symbol") { +content.text }
- is ContentKeyword -> span("keyword") { +content.text }
- is ContentIdentifier -> span("identifier") {
- content.signature?.let { id = it }
- +content.text
+ sealed class Page {
+ class PackageIndex(packages: List<DocumentationNode>) : Page() {
+ init {
+ assert(packages.all { it.kind == NodeKind.Package })
}
- is ContentHeading -> hN(level = content.level) { appendContent(content.children) }
+ val packages = packages.sortedBy { it.name }
+ }
- is ContentEntity -> +content.text
+ class ClassIndex(allTypesNode: DocumentationNode) : Page() {
+ init {
+ assert(allTypesNode.kind == NodeKind.AllTypes)
+ }
- is ContentStrong -> strong { appendContent(content.children) }
- is ContentStrikethrough -> del { appendContent(content.children) }
- is ContentEmphasis -> em { appendContent(content.children) }
+ // Wide-collect all nested classes
+ val classes: List<DocumentationNode> =
+ generateSequence(listOf(allTypesNode)) { nodes ->
+ nodes
+ .flatMap { it.members.filter { it.kind in NodeKind.classLike } }
+ .takeUnless { it.isEmpty() }
+ }.drop(1)
+ .flatten()
+ .sortedBy { it.classNodeNameWithOuterClass() }
+ .toList()
+
+
+ // Group all classes by it's first letter and sort
+ val classesByFirstLetter =
+ classes
+ .groupBy {
+ it.classNodeNameWithOuterClass().first().toString()
+ }
+ .entries
+ .sortedBy { (letter) -> letter }
+ }
- is ContentOrderedList -> ol { appendContent(content.children) }
- is ContentUnorderedList -> ul { appendContent(content.children) }
- is ContentListItem -> consumer.li {
- (content.children.singleOrNull() as? ContentParagraph)
- ?.let { paragraph -> appendContent(paragraph.children) }
- ?: appendContent(content.children)
+ class ClassPage(val node: DocumentationNode) : Page() {
+
+ init {
+ assert(node.kind in NodeKind.classLike)
}
+ val superclasses = (sequenceOf(node) + node.superclassTypeSequence).toList().asReversed()
- is ContentCode -> pre { code { appendContent(content.children) } }
- is ContentBlockSampleCode -> pre { code {} }
- is ContentBlockCode -> pre { code {} }
+ val directInheritors: List<DocumentationNode>
+ val indirectInheritors: List<DocumentationNode>
- is ContentNonBreakingSpace -> +nbsp
- is ContentSoftLineBreak, is ContentIndentedSoftLineBreak -> {
+ init {
+ // Wide-collect all inheritors
+ val inheritors = generateSequence(node.inheritors) { inheritors ->
+ inheritors
+ .flatMap { it.inheritors }
+ .takeUnless { it.isEmpty() }
+ }
+ directInheritors = inheritors.first()
+ indirectInheritors = inheritors.drop(1).flatten().toList()
}
- is ContentParagraph -> p { appendContent(content.children) }
+ val isCompanion = node.details(NodeKind.Modifier).any { it.name == "companion" }
+ val hasMeaningfulCompanion = !isCompanion && node.companion != null
- is ContentNodeLink -> {
- a(href = content.node?.let { uriProvider.linkTo(it, uri) }
- ?: "#unresolved") { appendContent(content.children) }
+ private fun DocumentationNode.thisTypeExtension() =
+ detail(NodeKind.Receiver).detail(NodeKind.Type).links.any { it == node }
+
+ val functionKind = if (!isCompanion) NodeKind.Function else NodeKind.CompanionObjectFunction
+ val propertyKind = if (!isCompanion) NodeKind.Property else NodeKind.CompanionObjectProperty
+
+ private fun DocumentationNode.isFunction() = kind == functionKind
+ private fun DocumentationNode.isProperty() = kind == propertyKind
+
+
+ val nestedClasses = node.members.filter { it.kind in NodeKind.classLike }
+ val constructors = node.members(NodeKind.Constructor)
+ val functions = node.members(functionKind)
+ val properties = node.members(propertyKind)
+ val inheritedFunctionsByReceiver = node.inheritedMembers(functionKind).groupBy { it.owner!! }
+ val inheritedPropertiesByReceiver = node.inheritedMembers(propertyKind).groupBy { it.owner!! }
+
+ val originalExtensions = if (!isCompanion) node.extensions else node.owner!!.extensions
+
+ val extensionFunctions: Map<DocumentationNode, List<DocumentationNode>>
+ val extensionProperties: Map<DocumentationNode, List<DocumentationNode>>
+ val inheritedExtensionFunctions: Map<DocumentationNode, List<DocumentationNode>>
+ val inheritedExtensionProperties: Map<DocumentationNode, List<DocumentationNode>>
+
+ init {
+ val (extensions, inheritedExtensions) = originalExtensions.partition { it.thisTypeExtension() }
+ extensionFunctions = extensions.filter { it.isFunction() }.groupBy { it.owner!! }
+ extensionProperties = extensions.filter { it.isProperty() }.groupBy { it.owner!! }
+ inheritedExtensionFunctions =
+ inheritedExtensions.filter { it.isFunction() }.groupBy { it.owner!! }
+ inheritedExtensionProperties =
+ inheritedExtensions.filter { it.isProperty() }.groupBy { it.owner!! }
}
- is ContentExternalLink -> {
- a(href = content.href) { appendContent(content.children) }
+
+ val companionFunctions = node.members(NodeKind.CompanionObjectFunction).takeUnless { isCompanion }.orEmpty()
+ val companionProperties =
+ node.members(NodeKind.CompanionObjectProperty).takeUnless { isCompanion }.orEmpty()
+
+
+ }
+
+ class PackagePage(val node: DocumentationNode) : Page() {
+
+ init {
+ assert(node.kind == NodeKind.Package)
}
- is ContentBlock -> appendContent(content.children)
+ val classes = node.members(NodeKind.Class)
+ val exceptions = node.members(NodeKind.Exception)
+ val typeAliases = node.members(NodeKind.TypeAlias)
+ val annotations = node.members(NodeKind.AnnotationClass)
+ val enums = node.members(NodeKind.Enum)
+
+ val functions = node.members(NodeKind.Function)
+ val properties = node.members(NodeKind.Property)
}
}
}
class JavaLayoutHtmlFormatOutputBuilderFactoryImpl @Inject constructor(
- val uriProvider: JavaLayoutHtmlUriProvider,
- val languageService: LanguageService,
- val templateService: JavaLayoutHtmlTemplateService,
- val logger: DokkaLogger
+ val uriProvider: JavaLayoutHtmlUriProvider,
+ val languageService: LanguageService,
+ val templateService: JavaLayoutHtmlTemplateService,
+ val logger: DokkaLogger
) : JavaLayoutHtmlFormatOutputBuilderFactory {
override fun createOutputBuilder(output: Appendable, node: DocumentationNode): JavaLayoutHtmlFormatOutputBuilder {
return createOutputBuilder(output, uriProvider.mainUri(node))