package org.jetbrains.dokka.model interface WithChildren { val children: List } inline fun WithChildren<*>.firstChildOfTypeOrNull(): T? = children.filterIsInstance().firstOrNull() inline fun WithChildren<*>.firstChildOfTypeOrNull(predicate: (T) -> Boolean): T? = children.filterIsInstance().firstOrNull(predicate) inline fun WithChildren<*>.firstChildOfType(): T = children.filterIsInstance().first() inline fun WithChildren<*>.childrenOfType(): List = children.filterIsInstance() inline fun WithChildren<*>.firstChildOfType(predicate: (T) -> Boolean): T = children.filterIsInstance().first(predicate) inline fun WithChildren>.firstMemberOfType(): T where T : WithChildren<*> { return withDescendants().filterIsInstance().first() } inline fun WithChildren>.firstMemberOfType( predicate: (T) -> Boolean ): T where T : WithChildren<*> = withDescendants().filterIsInstance().first(predicate) inline fun WithChildren>.firstMemberOfTypeOrNull(): T? where T : WithChildren<*> { return withDescendants().filterIsInstance().firstOrNull() } fun T.withDescendants(): Sequence where T : WithChildren { return sequence { yield(this@withDescendants) children.forEach { child -> yieldAll(child.withDescendants()) } } } @JvmName("withDescendantsProjection") fun WithChildren<*>.withDescendants(): Sequence { return sequence { yield(this@withDescendants) children.forEach { child -> if (child is WithChildren<*>) { yieldAll(child.withDescendants()) } } } } @JvmName("withDescendantsAny") fun WithChildren.withDescendants(): Sequence { return sequence { yield(this@withDescendants) children.forEach { child -> if (child is WithChildren<*>) { yieldAll(child.withDescendants().filterNotNull()) } } } } fun T.dfs(predicate: (T) -> Boolean): T? where T : WithChildren = if (predicate(this)) { this } else { children.asSequence().mapNotNull { it.dfs(predicate) }.firstOrNull() } fun > T.asPrintableTree( nodeNameBuilder: Appendable.(T) -> Unit = { append(it.toString()) } ): String { fun Appendable.append(element: T, ownPrefix: String, childPrefix: String) { append(ownPrefix) nodeNameBuilder(element) appendLine() element.children.takeIf(Collection<*>::isNotEmpty)?.also { children -> val newOwnPrefix = "$childPrefix├─ " val lastOwnPrefix = "$childPrefix└─ " val newChildPrefix = "$childPrefix│ " val lastChildPrefix = "$childPrefix " children.forEachIndexed { n, e -> if (n != children.lastIndex) append(e, newOwnPrefix, newChildPrefix) else append(e, lastOwnPrefix, lastChildPrefix) } } } return buildString { append(this@asPrintableTree, "", "") } }