blob: fe0394f948f9ae634002be0437daf48e60f322d8 (
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
|
package org.jetbrains.dokka.tests
import org.jetbrains.dokka.DocumentationNode
import org.jetbrains.dokka.NodeKind
import org.jetbrains.dokka.RefKind
class SelectBuilder {
private val root = ChainFilterNode(SubgraphTraverseFilter(), null)
private var activeNode = root
private val chainEnds = mutableListOf<SelectFilter>()
fun withName(name: String) = matching { it.name == name }
fun withKind(kind: NodeKind) = matching{ it.kind == kind }
fun matching(block: (DocumentationNode) -> Boolean) {
attachFilterAndMakeActive(PredicateFilter(block))
}
fun subgraph() {
attachFilterAndMakeActive(SubgraphTraverseFilter())
}
fun subgraphOf(kind: RefKind) {
attachFilterAndMakeActive(DirectEdgeFilter(kind))
}
private fun attachFilterAndMakeActive(next: SelectFilter) {
activeNode = ChainFilterNode(next, activeNode)
}
private fun endChain() {
chainEnds += activeNode
}
fun build(): SelectFilter {
endChain()
return CombineFilterNode(chainEnds)
}
}
private class ChainFilterNode(val filter: SelectFilter, val previous: SelectFilter?): SelectFilter() {
override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> {
return filter.select(previous?.select(roots) ?: roots)
}
}
private class CombineFilterNode(val previous: List<SelectFilter>): SelectFilter() {
override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> {
return previous.asSequence().flatMap { it.select(roots) }
}
}
abstract class SelectFilter {
abstract fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode>
}
private class SubgraphTraverseFilter: SelectFilter() {
override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> {
val visited = mutableSetOf<DocumentationNode>()
return roots.flatMap {
generateSequence(listOf(it)) { nodes ->
nodes.flatMap { it.allReferences() }
.map { it.to }
.filter { visited.add(it) }
.takeUnless { it.isEmpty() }
}
}.flatten()
}
}
private class PredicateFilter(val condition: (DocumentationNode) -> Boolean): SelectFilter() {
override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> {
return roots.filter(condition)
}
}
private class DirectEdgeFilter(val kind: RefKind): SelectFilter() {
override fun select(roots: Sequence<DocumentationNode>): Sequence<DocumentationNode> {
return roots.flatMap { it.references(kind).asSequence() }.map { it.to }
}
}
fun selectNodes(root: DocumentationNode, block: SelectBuilder.() -> Unit): List<DocumentationNode> {
val builder = SelectBuilder()
builder.apply(block)
return builder.build().select(sequenceOf(root)).toMutableSet().toList()
}
|