aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt
blob: 6b6127338c5e2ea90b2d1635c337991890acee69 (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
108
109
110
111
112
113
114
115
package org.jetbrains.dokka.base.transformers.documentables

import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.model.Enum
import org.jetbrains.dokka.model.Function
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.transformers.documentation.DocumentableMerger

internal object DefaultDocumentableMerger : DocumentableMerger {
    override fun invoke(modules: Collection<Module>, context: DokkaContext): Module {
        if (!modules.all { it.name == modules.first().name })
            context.logger.error("All module names need to be the same")
        return Module(
            modules.first().name,
            merge(
                modules.flatMap { it.packages },
                Package::mergeWith
            )
        )
    }
}

private fun <T : Documentable> merge(elements: List<T>, reducer: (T, T) -> T): List<T> =
    elements.groupingBy { it.dri }
        .reduce { _, left, right -> reducer(left, right) }
        .values.toList()

fun PlatformInfo.mergeWith(other: PlatformInfo?) = BasePlatformInfo(
    documentationNode,
    (platformData + (other?.platformData ?: emptyList())).distinct()
)

fun ClassPlatformInfo.mergeWith(other: ClassPlatformInfo?) = ClassPlatformInfo(
    info.mergeWith(other?.info),
    (inherited + (other?.inherited ?: emptyList())).distinct()
)

fun List<ClassPlatformInfo>.mergeClassPlatformInfo(): List<ClassPlatformInfo> =
    groupingBy { it.documentationNode.children + it.inherited }.reduce { _, left, right ->
        left.mergeWith(right)
    }.values.toList()

fun List<PlatformInfo>.merge(): List<PlatformInfo> =
    groupingBy { it.documentationNode }.reduce { _, left, right ->
        left.mergeWith(right)
    }.values.toList()

fun Function.mergeWith(other: Function): Function = Function(
    dri,
    name,
    returnType,
    isConstructor,
    other.receiver?.let { receiver?.mergeWith(it) },
    merge(parameters + other.parameters, Parameter::mergeWith),
    expected?.mergeWith(other.expected),
    (actual + other.actual).merge(),
    visibility = (visibility + other.visibility)
)

fun Property.mergeWith(other: Property) = Property(
    dri,
    name,
    other.receiver?.let { receiver?.mergeWith(it) },
    expected?.mergeWith(other.expected),
    (actual + other.actual).merge(),
    accessors = (this.accessors + other.accessors).distinct(),
    visibility = (visibility + other.visibility)
)

fun Classlike.mergeWith(other: Classlike): Classlike = when {
    this is Class && other is Class -> mergeWith(other)
    this is Enum && other is Enum -> mergeWith(other)
    else -> throw IllegalStateException("${this::class.qualifiedName} ${this.name} cannot be merged with ${other::class.qualifiedName} ${other.name}")
}

fun Class.mergeWith(other: Class) = Class(
    dri = dri,
    name = name,
    kind = kind,
    constructors = merge(constructors + other.constructors, Function::mergeWith),
    functions = merge(functions + other.functions, Function::mergeWith),
    properties = merge(properties + other.properties, Property::mergeWith),
    classlikes = merge(classlikes + other.classlikes, Classlike::mergeWith),
    expected = expected?.mergeWith(other.expected),
    actual = (actual + other.actual).mergeClassPlatformInfo(),
    visibility = (visibility + other.visibility)
)

fun Enum.mergeWith(other: Enum) = Enum(
    dri = dri,
    name = name,
    functions = merge(functions + other.functions, Function::mergeWith),
    properties = merge(properties + other.properties, Property::mergeWith),
    classlikes = merge(classlikes + other.classlikes, Classlike::mergeWith),
    expected = expected?.mergeWith(other.expected),
    actual = (actual + other.actual).mergeClassPlatformInfo(),
    entries = (this.entries + other.entries.distinctBy { it.dri }.toList()),
    constructors = merge(constructors + other.constructors, Function::mergeWith),
    visibility = visibility
)

fun Parameter.mergeWith(other: Parameter) = Parameter(
    dri,
    name,
    type,
    expected?.mergeWith(other.expected),
    (actual + other.actual).merge()
)

fun Package.mergeWith(other: Package): Package = Package(
    dri,
    merge(functions + other.functions, Function::mergeWith),
    merge(properties + other.properties, Property::mergeWith),
    merge(classlikes + other.classlikes, Classlike::mergeWith)
)