1 package org.jetbrains.dokka.javadoc
2
3 import com.sun.javadoc.*
4 import org.jetbrains.dokka.*
5 import java.util.*
6
7 class TagImpl(val holder: Doc, val name: String, val text: String): Tag {
textnull8 override fun text(): String? = text
9
10 override fun holder(): Doc = holder
11 override fun firstSentenceTags(): Array<out Tag>? = arrayOf()
12 override fun inlineTags(): Array<out Tag>? = arrayOf()
13
14 override fun name(): String = name
15 override fun kind(): String = name
16
17 override fun position(): SourcePosition = holder.position()
18 }
19
20 class TextTag(val holder: Doc, val content: ContentText) : Tag {
21 val plainText: String
22 get() = content.text
23
24 override fun name(): String = "Text"
25 override fun kind(): String = name()
26 override fun text(): String? = plainText
27 override fun inlineTags(): Array<out Tag> = arrayOf(this)
28 override fun holder(): Doc = holder
29 override fun firstSentenceTags(): Array<out Tag> = arrayOf(this)
30 override fun position(): SourcePosition = holder.position()
31 }
32
33 abstract class SeeTagAdapter(val holder: Doc, val content: ContentNodeLink) : SeeTag {
positionnull34 override fun position(): SourcePosition? = holder.position()
35 override fun name(): String = "@see"
36 override fun kind(): String = "@see"
37 override fun holder(): Doc = holder
38
39 override fun text(): String? = content.node?.name ?: "(?)"
40 }
41
42 class SeeExternalLinkTagAdapter(val holder: Doc, val link: ContentExternalLink) : SeeTag {
43 override fun position(): SourcePosition = holder.position()
44 override fun text(): String = label()
45 override fun inlineTags(): Array<out Tag> = emptyArray() // TODO
46
47 override fun label(): String {
48 val label = link.asText() ?: link.href
49 return "<a href=\"${link.href}\">$label</a>"
50 }
51
52 override fun referencedPackage(): PackageDoc? = null
53 override fun referencedClass(): ClassDoc? = null
54 override fun referencedMemberName(): String? = null
55 override fun referencedClassName(): String? = null
56 override fun referencedMember(): MemberDoc? = null
57 override fun holder(): Doc = holder
58 override fun firstSentenceTags(): Array<out Tag> = inlineTags()
59 override fun name(): String = "@link"
60 override fun kind(): String = "@see"
61 }
62
ContentBlocknull63 fun ContentBlock.asText(): String? {
64 val contentText = children.singleOrNull() as? ContentText
65 return contentText?.text
66 }
67
68 class SeeMethodTagAdapter(holder: Doc, val method: MethodAdapter, content: ContentNodeLink) : SeeTagAdapter(holder, content) {
referencedMembernull69 override fun referencedMember(): MemberDoc = method
70 override fun referencedMemberName(): String = method.name()
71 override fun referencedPackage(): PackageDoc? = null
72 override fun referencedClass(): ClassDoc? = method.containingClass()
73 override fun referencedClassName(): String = method.containingClass()?.name() ?: ""
74 override fun label(): String = "${method.containingClass()?.name()}.${method.name()}"
75
76 override fun inlineTags(): Array<out Tag> = emptyArray() // TODO
77 override fun firstSentenceTags(): Array<out Tag> = inlineTags() // TODO
78 }
79
80 class SeeClassTagAdapter(holder: Doc, val clazz: ClassDocumentationNodeAdapter, content: ContentNodeLink) : SeeTagAdapter(holder, content) {
81 override fun referencedMember(): MemberDoc? = null
82 override fun referencedMemberName(): String? = null
83 override fun referencedPackage(): PackageDoc? = null
84 override fun referencedClass(): ClassDoc = clazz
85 override fun referencedClassName(): String = clazz.name()
86 override fun label(): String = "${clazz.classNode.kind.name.toLowerCase()} ${clazz.name()}"
87
88 override fun inlineTags(): Array<out Tag> = emptyArray() // TODO
89 override fun firstSentenceTags(): Array<out Tag> = inlineTags() // TODO
90 }
91
92 class ParamTagAdapter(val module: ModuleNodeAdapter,
93 val holder: Doc,
94 val parameterName: String,
95 val typeParameter: Boolean,
96 val content: List<ContentNode>) : ParamTag {
97
98 constructor(module: ModuleNodeAdapter, holder: Doc, parameterName: String, isTypeParameter: Boolean, content: ContentNode)
99 : this(module, holder, parameterName, isTypeParameter, listOf(content)) {
100 }
101
namenull102 override fun name(): String = "@param"
103 override fun kind(): String = name()
104 override fun holder(): Doc = holder
105 override fun position(): SourcePosition? = holder.position()
106
107 override fun text(): String = "@param $parameterName ${parameterComment()}" // Seems has no effect, so used for debug
108 override fun inlineTags(): Array<out Tag> = buildInlineTags(module, holder, content).toTypedArray()
109 override fun firstSentenceTags(): Array<out Tag> = arrayOf(TextTag(holder, ContentText(text())))
110
111 override fun isTypeParameter(): Boolean = typeParameter
112 override fun parameterComment(): String = content.toString() // TODO
113 override fun parameterName(): String = parameterName
114 }
115
116
117 class ThrowsTagAdapter(val holder: Doc, val type: ClassDocumentationNodeAdapter, val content: List<ContentNode>) : ThrowsTag {
118 override fun name(): String = "@throws"
119 override fun kind(): String = name()
120 override fun holder(): Doc = holder
121 override fun position(): SourcePosition? = holder.position()
122
123 override fun text(): String = "${name()} ${exceptionName()} ${exceptionComment()}"
124 override fun inlineTags(): Array<out Tag> = buildInlineTags(type.module, holder, content).toTypedArray()
125 override fun firstSentenceTags(): Array<out Tag> = emptyArray()
126
127 override fun exceptionComment(): String = content.toString()
128 override fun exceptionType(): Type = type
129 override fun exception(): ClassDoc = type
130 override fun exceptionName(): String = type.qualifiedTypeName()
131 }
132
133 class ReturnTagAdapter(val module: ModuleNodeAdapter, val holder: Doc, val content: List<ContentNode>) : Tag {
namenull134 override fun name(): String = "@return"
135 override fun kind() = name()
136 override fun holder() = holder
137 override fun position(): SourcePosition? = holder.position()
138
139 override fun text(): String = "@return $content" // Seems has no effect, so used for debug
140 override fun inlineTags(): Array<Tag> = buildInlineTags(module, holder, content).toTypedArray()
141 override fun firstSentenceTags(): Array<Tag> = inlineTags()
142 }
143
144 fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, tags: List<ContentNode>): List<Tag> = ArrayList<Tag>().apply { tags.forEach { buildInlineTags(module, holder, it, this) } }
145
<lambda>null146 fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, root: ContentNode): List<Tag> = ArrayList<Tag>().apply { buildInlineTags(module, holder, root, this) }
147
buildInlineTagsnull148 private fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, nodes: List<ContentNode>, result: MutableList<Tag>) {
149 nodes.forEach {
150 buildInlineTags(module, holder, it, result)
151 }
152 }
153
154
buildInlineTagsnull155 private fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, node: ContentNode, result: MutableList<Tag>) {
156 fun surroundWith(module: ModuleNodeAdapter, holder: Doc, prefix: String, postfix: String, node: ContentBlock, result: MutableList<Tag>) {
157 if (node.children.isNotEmpty()) {
158 val open = TextTag(holder, ContentText(prefix))
159 val close = TextTag(holder, ContentText(postfix))
160
161 result.add(open)
162 buildInlineTags(module, holder, node.children, result)
163
164 if (result.last() === open) {
165 result.removeAt(result.lastIndex)
166 } else {
167 result.add(close)
168 }
169 }
170 }
171
172 fun surroundWith(module: ModuleNodeAdapter, holder: Doc, prefix: String, postfix: String, node: ContentNode, result: MutableList<Tag>) {
173 if (node !is ContentEmpty) {
174 val open = TextTag(holder, ContentText(prefix))
175 val close = TextTag(holder, ContentText(postfix))
176
177 result.add(open)
178 buildInlineTags(module, holder, node, result)
179 if (result.last() === open) {
180 result.removeAt(result.lastIndex)
181 } else {
182 result.add(close)
183 }
184 }
185 }
186
187 when (node) {
188 is ContentText -> result.add(TextTag(holder, node))
189 is ContentNodeLink -> {
190 val target = node.node
191 when (target?.kind) {
192 NodeKind.Function -> result.add(SeeMethodTagAdapter(holder, MethodAdapter(module, node.node!!), node))
193
194 in NodeKind.classLike -> result.add(SeeClassTagAdapter(holder, ClassDocumentationNodeAdapter(module, node.node!!), node))
195
196 else -> buildInlineTags(module, holder, node.children, result)
197 }
198 }
199 is ContentExternalLink -> result.add(SeeExternalLinkTagAdapter(holder, node))
200 is ContentSpecialReference -> surroundWith(module, holder, "<aside class=\"note\">", "</aside>", node, result)
201 is ContentCode -> surroundWith(module, holder, "<code>", "</code>", node, result)
202 is ContentBlockCode -> surroundWith(module, holder, "<code><pre>", "</pre></code>", node, result)
203 is ContentEmpty -> {}
204 is ContentEmphasis -> surroundWith(module, holder, "<em>", "</em>", node, result)
205 is ContentHeading -> surroundWith(module, holder, "<h${node.level}>", "</h${node.level}>", node, result)
206 is ContentEntity -> result.add(TextTag(holder, ContentText(node.text))) // TODO ??
207 is ContentIdentifier -> result.add(TextTag(holder, ContentText(node.text))) // TODO
208 is ContentKeyword -> result.add(TextTag(holder, ContentText(node.text))) // TODO
209 is ContentListItem -> surroundWith(module, holder, "<li>", "</li>", node, result)
210 is ContentOrderedList -> surroundWith(module, holder, "<ol>", "</ol>", node, result)
211 is ContentUnorderedList -> surroundWith(module, holder, "<ul>", "</ul>", node, result)
212 is ContentParagraph -> surroundWith(module, holder, "<p>", "</p>", node, result)
213
214 is ContentDescriptionList -> surroundWith(module, holder, "<dl>", "</dl>", node, result)
215 is ContentDescriptionTerm -> surroundWith(module, holder, "<dt>", "</dt>", node, result)
216 is ContentDescriptionDefinition -> surroundWith(module, holder, "<dd>", "</dd>", node, result)
217
218 is ContentTable -> surroundWith(module, holder, "<table>", "</table>", node, result)
219 is ContentTableBody -> surroundWith(module, holder, "<tbody>", "</tbody>", node, result)
220 is ContentTableRow -> surroundWith(module, holder, "<tr>", "</tr>", node, result)
221 is ContentTableHeader -> surroundWith(module, holder, "<th>", "</th>", node, result)
222 is ContentTableCell -> surroundWith(module, holder, "<td>", "</td>", node, result)
223
224 is ContentSection -> surroundWith(module, holder, "<p>", "</p>", node, result) // TODO how section should be represented?
225 is ContentNonBreakingSpace -> result.add(TextTag(holder, ContentText(" ")))
226 is ContentStrikethrough -> surroundWith(module, holder, "<strike>", "</strike>", node, result)
227 is ContentStrong -> surroundWith(module, holder, "<strong>", "</strong>", node, result)
228 is ContentSymbol -> result.add(TextTag(holder, ContentText(node.text))) // TODO?
229 is Content -> {
230 surroundWith(module, holder, "<p>", "</p>", node.summary, result)
231 surroundWith(module, holder, "<p>", "</p>", node.description, result)
232 }
233 is ContentBlock -> {
234 surroundWith(module, holder, "", "", node, result)
235 }
236 is ContentHardLineBreak -> result.add(TextTag(holder, ContentText("<br/>")))
237
238 else -> result.add(TextTag(holder, ContentText("$node")))
239 }
240 }