-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
34 changed files
with
543 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
plugins { | ||
kotlin("jvm") version "1.9.22" | ||
} | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
implementation("com.fasterxml.jackson.core:jackson-annotations:2.16.1") | ||
implementation("com.fasterxml.jackson.core:jackson-core:2.16.1") | ||
implementation("com.fasterxml.jackson.core:jackson-databind:2.16.1") | ||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.16.1") | ||
implementation("net.sourceforge.plantuml:plantuml:1.2024.3") | ||
} |
124 changes: 124 additions & 0 deletions
124
buildSrc/src/main/kotlin/documentation/DetailedDiagramGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package documentation | ||
|
||
import documentation.model.Component | ||
import documentation.model.Component.Relationship.CLOSE | ||
import documentation.model.Component.Relationship.EXTERNAL | ||
import documentation.model.Component.Relationship.OWNED | ||
import documentation.model.Component.Type.BACKEND | ||
import documentation.model.Component.Type.DATABASE | ||
import documentation.model.Component.Type.FRONTEND | ||
import documentation.model.Dependent | ||
import documentation.model.DiagramComponent | ||
import documentation.model.DiagramRelationship | ||
import documentation.model.RootComponent | ||
|
||
class DetailedDiagramGenerator(private val rootComponent: RootComponent) { | ||
|
||
private val components: List<Component> | ||
private val incomingRelationships: List<DiagramRelationship> | ||
private val outgoingRelationships: List<DiagramRelationship> | ||
|
||
private val systemAndContextMap: Map<SystemAndContextId, List<String>> | ||
|
||
init { | ||
components = rootComponent.dependents + rootComponent + rootComponent.dependencies | ||
|
||
incomingRelationships = rootComponent.dependents | ||
.map { source -> diagramRelationship(source, rootComponent) } | ||
outgoingRelationships = rootComponent.dependencies | ||
.map { target -> diagramRelationship(rootComponent, target) } | ||
|
||
systemAndContextMap = components | ||
.groupBy(::systemAndContextId, ::diagramComponentId) | ||
} | ||
|
||
fun generate(): String = | ||
buildString { | ||
appendLine("@startuml") | ||
appendLine("'https://plantuml.com/deployment-diagram") | ||
appendLine() | ||
systemAndContextMap.keys.forEach { (systemId, contextId) -> | ||
if (systemId != null) appendLine("""folder "${systemName(systemId)}" {""") | ||
if (contextId != null) appendLine("""frame "${contextName(contextId)}" {""") | ||
|
||
components | ||
.filter { it.systemId == systemId && it.contextId == contextId } | ||
.map(::diagramComponent) | ||
.forEach { appendLine(it) } | ||
|
||
if (contextId != null) appendLine("}") | ||
if (systemId != null) appendLine("}") | ||
} | ||
appendLine() | ||
incomingRelationships.forEach { appendLine(it) } | ||
outgoingRelationships.forEach { appendLine(it) } | ||
appendLine() | ||
appendLine("@enduml") | ||
} | ||
|
||
// common functions | ||
|
||
private fun StringBuilder.appendLine(component: DiagramComponent) = | ||
with(component) { | ||
appendLine("""$type "$name" as $id $style""") | ||
} | ||
|
||
private fun StringBuilder.appendLine(relationship: DiagramRelationship) = | ||
with(relationship) { | ||
appendLine("""$source $link $target""") | ||
} | ||
|
||
private fun diagramComponent(description: Component) = | ||
DiagramComponent( | ||
id = diagramComponentId(description), | ||
type = type(description), | ||
name = name(description), | ||
style = style(description) | ||
) | ||
|
||
private fun systemAndContextId(it: Component): SystemAndContextId = | ||
SystemAndContextId(it.systemId, it.contextId) | ||
|
||
private fun diagramComponentId(component: Component): String = | ||
component.id.replace('-', '_').lowercase() | ||
|
||
private fun type(component: Component): String { | ||
return when (component.type) { | ||
BACKEND, FRONTEND -> "rectangle" | ||
DATABASE -> "database" | ||
else -> "circle" | ||
} | ||
} | ||
|
||
private fun name(component: Component): String = | ||
componentName(component.id) | ||
|
||
private fun style(component: Component): String { | ||
if (component is RootComponent) return "#skyblue;line.bold" | ||
if (component is Dependent) return "#lightgrey" | ||
if (component.type == DATABASE) return "" | ||
|
||
return when (component.relationship) { | ||
OWNED -> "#lightblue" | ||
CLOSE -> "#moccasin" | ||
EXTERNAL -> "#lightcoral" | ||
else -> "" | ||
} | ||
} | ||
|
||
private fun diagramRelationship(source: Component, target: Component): DiagramRelationship = | ||
DiagramRelationship( | ||
source = diagramComponentId(source), | ||
target = diagramComponentId(target), | ||
link = when (target.type) { | ||
DATABASE -> "-d->" | ||
else -> when (target.relationship) { | ||
OWNED -> "-r->" | ||
CLOSE -> "-d->" | ||
else -> "-->" | ||
} | ||
} | ||
) | ||
|
||
data class SystemAndContextId(val systemId: String?, val contextId: String?) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package documentation | ||
|
||
import net.sourceforge.plantuml.FileFormat | ||
import net.sourceforge.plantuml.FileFormatOption | ||
import net.sourceforge.plantuml.SourceStringReader | ||
import java.io.File | ||
import java.io.FileOutputStream | ||
|
||
object ImageGenerator { | ||
|
||
fun generateDiagramImage(inputFile: File, outputFolder: File, format: FileFormat) { | ||
val diagramSource = inputFile.readText() | ||
val fileName = inputFile.nameWithoutExtension | ||
generateDiagramImage(diagramSource, outputFolder, fileName, format) | ||
} | ||
|
||
fun generateDiagramImage(diagramSource: String, outputFolder: File, fileName: String, format: FileFormat) { | ||
val outputFile = File(outputFolder, fileName + format.fileSuffix) | ||
val fileFormatOption = FileFormatOption(format, false) | ||
val reader = SourceStringReader(diagramSource) | ||
|
||
outputFolder.mkdirs() | ||
|
||
FileOutputStream(outputFile, false) | ||
.use { reader.outputImage(it, fileFormatOption) } | ||
} | ||
} |
106 changes: 106 additions & 0 deletions
106
buildSrc/src/main/kotlin/documentation/OverviewDiagramGenerator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package documentation | ||
|
||
import documentation.model.Component | ||
import documentation.model.Component.Relationship.CLOSE | ||
import documentation.model.Component.Relationship.EXTERNAL | ||
import documentation.model.Component.Relationship.OWNED | ||
import documentation.model.Component.Type.BACKEND | ||
import documentation.model.Component.Type.DATABASE | ||
import documentation.model.Component.Type.FRONTEND | ||
import documentation.model.DiagramComponent | ||
import documentation.model.DiagramRelationship | ||
import documentation.model.RootComponent | ||
|
||
class OverviewDiagramGenerator(rootComponents: List<RootComponent>) { | ||
|
||
private val relevantTypes = setOf(BACKEND, FRONTEND) | ||
|
||
private val rootComponentIds = rootComponents.map { it.id }.toSet() | ||
private val diagramRootComponents = rootComponents | ||
.map { diagramComponent(it) } | ||
private val additionalDiagramComponents = rootComponents | ||
.asSequence() | ||
.flatMap { it.dependencies } | ||
.filter { it.id !in rootComponentIds } | ||
.filter { it.type in relevantTypes } | ||
.distinctBy { it.id } | ||
.map { diagramComponent(it) } | ||
.toList() | ||
private val diagramRelationships = rootComponents | ||
.flatMap { source -> | ||
source.dependencies | ||
.filter { it.type in relevantTypes } | ||
.map { target -> source to target } | ||
} | ||
.map { (source, target) -> diagramRelationship(source, target) } | ||
|
||
fun generate(): String = | ||
buildString { | ||
appendLine("@startuml") | ||
appendLine("'https://plantuml.com/deployment-diagram") | ||
appendLine() | ||
appendLine("left to right direction") | ||
appendLine() | ||
diagramRootComponents.forEach { appendLine(it) } | ||
additionalDiagramComponents.forEach { appendLine(it) } | ||
appendLine() | ||
diagramRelationships.forEach { appendLine(it) } | ||
appendLine() | ||
appendLine("@enduml") | ||
} | ||
|
||
// common functions | ||
|
||
private fun StringBuilder.appendLine(component: DiagramComponent) = | ||
with(component) { | ||
appendLine("""$type "$name" as $id ${if (style != null) "#$style" else ""}""") | ||
} | ||
|
||
private fun StringBuilder.appendLine(relationship: DiagramRelationship) = | ||
with(relationship) { | ||
appendLine("""$source $link $target""") | ||
} | ||
|
||
private fun diagramComponent(description: Component) = | ||
DiagramComponent( | ||
id = id(description), | ||
type = type(description), | ||
name = name(description), | ||
style = color(description) | ||
) | ||
|
||
private fun id(description: Component): String = | ||
description.id.replace('-', '_').lowercase() | ||
|
||
private fun type(description: Component): String { | ||
return when (description.type) { | ||
BACKEND, FRONTEND -> "rectangle" | ||
DATABASE -> "database" | ||
else -> "circle" | ||
} | ||
} | ||
|
||
private fun name(description: Component): String = | ||
description.id | ||
|
||
private fun color(description: Component): String? = | ||
when (description.type) { | ||
DATABASE -> null | ||
else -> when (description.relationship) { | ||
OWNED -> "lightblue" | ||
CLOSE -> "moccasin" | ||
EXTERNAL -> "lightcoral" | ||
else -> null | ||
} | ||
} | ||
|
||
private fun diagramRelationship(source: Component, target: Component): DiagramRelationship { | ||
val sourceComponent = diagramComponent(source) | ||
val targetComponent = diagramComponent(target) | ||
return DiagramRelationship( | ||
source = sourceComponent.id, | ||
target = targetComponent.id, | ||
link = "-->" | ||
) | ||
} | ||
} |
Oops, something went wrong.