aboutsummaryrefslogtreecommitdiff
path: root/src/Model/Content.kt
blob: 1b00bd34712c621dbf66e7a1e3cefdcbc139103c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package org.jetbrains.dokka

import kotlin.properties.Delegates

public abstract class ContentNode {
    val children = arrayListOf<ContentNode>()

    class object {
        val empty = ContentEmpty
    }

    fun append(node : ContentNode) : ContentNode {
        children.add(node)
        return this
    }

    fun isEmpty() = children.isEmpty()
}

public object ContentEmpty : ContentNode()

public class ContentText(val text: String) : ContentNode()
public class ContentKeyword(val text: String) : ContentNode()
public class ContentIdentifier(val text: String) : ContentNode()
public class ContentSymbol(val text: String) : ContentNode()
public class ContentBlock() : ContentNode()
public class ContentEmphasis() : ContentNode()
public class ContentStrong() : ContentNode()
public class ContentList() : ContentNode()
public class ContentSection(public val label: String) : ContentNode()

fun content(body: ContentNode.() -> Unit): ContentNode {
    val block = ContentBlock()
    block.body()
    return block
}

fun ContentNode.text(value: String) = append(ContentText(value))
fun ContentNode.keyword(value: String) = append(ContentKeyword(value))
fun ContentNode.symbol(value: String) = append(ContentSymbol(value))
fun ContentNode.identifier(value: String) = append(ContentIdentifier(value))

public class Content() : ContentNode() {
    public val sections: Map<String, ContentSection> by Delegates.lazy {
        val map = hashMapOf<String, ContentSection>()
        for (child in children) {
            if (child is ContentSection)
                map.put(child.label, child)
        }

        if ("\$summary" !in map && "\$description" !in map) {
            // no explicit summary and description, convert anonymous section
            val anonymous = map[""]
            if (anonymous != null) {
                map.remove("")
                val summary = ContentSection("\$summary")
                val description = ContentSection("\$description")

                val summaryNodes = anonymous.children.take(1)
                val descriptionNodes = anonymous.children.drop(1)

                if (summaryNodes.any()) {
                    summary.children.addAll(summaryNodes)
                    map.put("\$summary", summary)
                }

                if (descriptionNodes.any()) {
                    description.children.addAll(descriptionNodes)
                    map.put("\$description", description)
                }
            }
        }
        map
    }

    public val summary: ContentNode get() = sections["\$summary"] ?: ContentNode.empty
    public val description: ContentNode get() = sections["\$description"] ?: ContentNode.empty

    override fun equals(other: Any?): Boolean {
        if (other !is Content)
            return false
        if (sections.size != other.sections.size)
            return false
        for (keys in sections.keySet())
            if (sections[keys] != other.sections[keys])
                return false

        return true
    }

    override fun hashCode(): Int {
        return sections.map { it.hashCode() }.sum()
    }

    override fun toString(): String {
        if (sections.isEmpty())
            return "<empty>"
        return sections.values().joinToString()
    }

    val isEmpty: Boolean
        get() = sections.none()

    class object {
        val Empty = Content()
    }
}