plugin docstring parsing now respect @param, @retunm, @throws and general support for such tags introduced

This commit is contained in:
sergeych committed 2026-01-12 11:55:39 +01:00
1 parent 1efa96a990
commit 9924d02cb4
5 files changed
+170 -17

No files matched your search

@@ -116,10 +116,8 @@ class Compiler(
private fun consumePendingDoc(): MiniDoc? {
if (pendingDocLines.isEmpty()) return null
val raw = pendingDocLines.joinToString("\n").trimEnd()
val summary = raw.lines().firstOrNull { it.isNotBlank() }?.trim()
val start = pendingDocStart ?: cc.currentPos()
val doc = MiniDoc(MiniRange(start, start), raw = raw, summary = summary)
val doc = MiniDoc.parse(MiniRange(start, start), pendingDocLines)
clearPendingDoc()
return doc
}
@@ -255,8 +255,7 @@ class ClassDocsBuilder internal constructor(private val className: String) {
private fun builtinRange() = MiniRange(Pos.builtIn, Pos.builtIn)
private fun miniDoc(text: String, tags: Map<String, List<String>>): MiniDoc {
val summary = text.lineSequence().map { it.trim() }.firstOrNull { it.isNotEmpty() }
return MiniDoc(range = builtinRange(), raw = text, summary = summary, tags = tags)
return MiniDoc.parse(builtinRange(), listOf(text), tags)
}
private fun TypeDoc.toDisplayName(): String = when (this) {
@@ -39,7 +39,56 @@ data class MiniDoc(
val raw: String,
val summary: String?,
val tags: Map<String, List<String>> = emptyMap()
)
) {
companion object {
fun parse(range: MiniRange, lines: Iterable<String>, extraTags: Map<String, List<String>> = emptyMap()): MiniDoc {
val parsedTags = mutableMapOf<String, MutableList<String>>()
var currentTag: String? = null
val currentContent = StringBuilder()
fun flush() {
currentTag?.let { tag ->
parsedTags.getOrPut(tag) { mutableListOf() }.add(currentContent.toString().trim())
}
currentContent.setLength(0)
}
val descriptionLines = mutableListOf<String>()
var inTags = false
for (rawLine in lines) {
for (line in rawLine.lines()) {
val trimmed = line.trim()
if (trimmed.startsWith("@")) {
inTags = true
flush()
val parts = trimmed.substring(1).split(Regex("\\s+"), 2)
currentTag = parts[0]
currentContent.append(parts.getOrNull(1) ?: "")
} else {
if (inTags) {
if (currentContent.isNotEmpty()) currentContent.append("\n")
currentContent.append(line)
} else {
descriptionLines.add(line)
}
}
}
}
flush()
val raw = descriptionLines.joinToString("\n").trimEnd()
val summary = raw.lines().firstOrNull { it.isNotBlank() }?.trim()
val finalTags = parsedTags.toMutableMap()
extraTags.forEach { (k, v) ->
finalTags.getOrPut(k) { mutableListOf() }.addAll(v)
}
return MiniDoc(range, raw, summary, finalTags)
}
}
}
sealed interface MiniNode { val range: MiniRange }
@@ -473,4 +473,58 @@ class MiniAstTest {
assertEquals("a", fn.params[0].name)
assertEquals("b", fn.params[1].name)
}
@Test
fun miniAst_captures_dokka_tags() = runTest {
val code = """
/**
* Testing tags.
* @param x the x value
* @param y the y value
* @return some string
* @throws Exception if failed
*/
fun tagged(x: Int, y: Int): String { "" }
""".trimIndent()
val (_, sink) = compileWithMini(code)
val mini = sink.build()
assertNotNull(mini)
val fn = mini.declarations.filterIsInstance<MiniFunDecl>().firstOrNull { it.name == "tagged" }
assertNotNull(fn)
val doc = fn.doc
assertNotNull(doc)
assertEquals("Testing tags.", doc.summary)
val tags = doc.tags
assertTrue(tags.containsKey("param"), "should have @param tags")
assertEquals(listOf("x the x value", "y the y value"), tags["param"])
assertEquals(listOf("some string"), tags["return"])
assertEquals(listOf("Exception if failed"), tags["throws"])
}
@Test
fun miniAst_captures_multiline_tags() = runTest {
val code = """
/**
* Multi line tag.
* @param x first line of x
* second line of x
* @return return value
*/
fun multiline(x: Int): Int { 0 }
""".trimIndent()
val (_, sink) = compileWithMini(code)
val mini = sink.build()
assertNotNull(mini)
val fn = mini.declarations.filterIsInstance<MiniFunDecl>().firstOrNull { it.name == "multiline" }
assertNotNull(fn)
val doc = fn.doc
assertNotNull(doc)
val tags = doc.tags
assertTrue(tags.containsKey("param"), "should have @param tags")
val xParam = tags["param"]?.first() ?: ""
assertTrue(xParam.contains("first line of x"), "should contain first line")
assertTrue(xParam.contains("second line of x"), "should contain second line")
}
}