-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: generate type converter supported types tables from actual type…
… converters and include the docs dir as a gradle module
- Loading branch information
Showing
14 changed files
with
455 additions
and
57 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,4 +87,4 @@ DEPENDENCIES | |
just-the-docs (= 0.4.2) | ||
|
||
BUNDLED WITH | ||
2.3.9 | ||
2.3.25 |
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,30 @@ | ||
@for $i from 0 through 4 { | ||
$start: 120; | ||
$base: 10; | ||
$columnWidth: $start + $base * $i; | ||
table.fixed-first-column-#{$columnWidth} { | ||
thead th:first-child { | ||
min-width: $columnWidth + 0px; | ||
max-width: $columnWidth + 0px; | ||
width: $columnWidth + 0px; | ||
position: absolute; | ||
} | ||
|
||
tbody td:first-child { | ||
min-width: $columnWidth + 0px; | ||
max-width: $columnWidth + 0px; | ||
width: $columnWidth + 0px; | ||
position: absolute; | ||
} | ||
|
||
tbody td:nth-child(2) { | ||
margin-left: $columnWidth + 0px; | ||
display: block; | ||
} | ||
|
||
thead th:nth-child(2) { | ||
margin-left: $columnWidth + 0px; | ||
display: block; | ||
} | ||
} | ||
} |
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,20 @@ | ||
plugins { | ||
id("konvert.kotlin") | ||
} | ||
|
||
dependencies { | ||
api(project(":converter")) | ||
|
||
// Generate docs... | ||
implementation("net.steppschuh.markdowngenerator:markdowngenerator:1.3.1.1") | ||
} | ||
|
||
val generateMarkdownTablesTask = tasks.create<JavaExec>("generateMarkdownTables") { | ||
classpath = sourceSets.main.get().runtimeClasspath | ||
|
||
mainClass.set("io.mcarle.konvert.internal.docs.GenerateDocumentationKt") | ||
} | ||
|
||
tasks.named("build") { | ||
dependsOn += generateMarkdownTablesTask | ||
} |
283 changes: 283 additions & 0 deletions
283
docs/src/main/kotlin/io/mcarle/konvert/internal/docs/GenerateDocumentation.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,283 @@ | ||
package io.mcarle.konvert.internal.docs | ||
|
||
import io.mcarle.konvert.converter.* | ||
import io.mcarle.konvert.converter.api.TypeConverter | ||
import net.steppschuh.markdowngenerator.table.Table | ||
import net.steppschuh.markdowngenerator.text.emphasis.BoldText | ||
import java.nio.file.Files | ||
import java.nio.file.Path | ||
import java.nio.file.Paths | ||
import java.util.Date | ||
import java.util.ServiceLoader | ||
import kotlin.io.path.createDirectories | ||
import kotlin.reflect.KClass | ||
|
||
fun main() { | ||
val list = ServiceLoader.load(TypeConverter::class.java).toList() | ||
|
||
val outputDir = Paths.get("typeconverter", "gen") | ||
outputDir.createDirectories() | ||
|
||
val basicTypesList = generateBasicTypeConverterTable(outputDir, list) | ||
generateTemporalTypeConverterTable(outputDir, list, basicTypesList) | ||
generateIterablesTypeConverterTable(outputDir, list) | ||
generateEnumTypeConverterTable(outputDir, list, basicTypesList) | ||
generateMapTypeConverterTable(outputDir, list) | ||
} | ||
|
||
const val FROM_TO = "From\\To" | ||
|
||
fun generateBasicTypeConverterTable(outputDir: Path, typeConverters: List<TypeConverter>): List<KClass<*>> { | ||
val basicTypeConverters = typeConverters | ||
.filterIsInstance<BaseTypeConverter>() | ||
.sortedWith(kotlin.comparisons.compareBy({ it.sourceClass.simpleName }, { it.targetClass.simpleName })) | ||
|
||
val basicClasses = (basicTypeConverters.flatMap { listOf(it.sourceClass, it.targetClass) }) | ||
.distinct() | ||
.sortedBy { it.simpleName } | ||
|
||
val builder = Table.Builder() | ||
.withAlignments(Table.ALIGN_CENTER, *basicClasses.map { Table.ALIGN_CENTER }.toTypedArray()) | ||
.addRow(FROM_TO, *basicClasses.map { it.simpleName }.toTypedArray()) | ||
|
||
basicClasses.forEachIndexed { index, clazz -> | ||
builder.addRow( | ||
BoldText(clazz.simpleName), | ||
*basicTypeConverters.filter { it.sourceClass == clazz } | ||
.map { if (it.enabledByDefault) "✔" else "☑" } | ||
.toMutableList().also { | ||
it.add(index, "✔") | ||
} | ||
.toTypedArray() | ||
) | ||
} | ||
|
||
Files.writeString(outputDir.resolve("basic.md"), builder.build().toString() + "\n{: .fixed-first-column-120 }") | ||
|
||
return basicClasses | ||
} | ||
|
||
fun generateTemporalTypeConverterTable(outputDir: Path, typeConverters: List<TypeConverter>, basicTypesList: List<KClass<*>>) { | ||
val map = mutableMapOf<DescriptiveClass, MutableMap<DescriptiveClass, Boolean>>() | ||
typeConverters.filterIsInstance<TemporalToTemporalConverter>().forEach { | ||
map.getOrPut(DescriptiveClass.from(it, it.sourceClass)) { mutableMapOf() }[DescriptiveClass.to(it, it.targetClass)] = | ||
it.enabledByDefault | ||
} | ||
typeConverters.filterIsInstance<TemporalToXConverter>().forEach { | ||
map.getOrPut(DescriptiveClass.from(it, it.sourceClass)) { mutableMapOf() }[DescriptiveClass.to(it, it.targetClass)] = | ||
it.enabledByDefault | ||
} | ||
typeConverters.filterIsInstance<XToTemporalConverter>().forEach { | ||
map.getOrPut(DescriptiveClass.from(it, it.sourceClass)) { mutableMapOf() }[DescriptiveClass.to(it, it.targetClass)] = | ||
it.enabledByDefault | ||
} | ||
typeConverters.filterIsInstance<DateToTemporalConverter>().forEach { | ||
map.getOrPut(DescriptiveClass.from(it, Date::class)) { mutableMapOf() }[DescriptiveClass.to(it, it.targetClass)] = | ||
it.enabledByDefault | ||
} | ||
typeConverters.filterIsInstance<DateToXConverter>().forEach { | ||
map.getOrPut(DescriptiveClass.from(it, Date::class)) { mutableMapOf() }[DescriptiveClass.to(it, it.targetClass)] = | ||
it.enabledByDefault | ||
} | ||
typeConverters.filterIsInstance<TemporalToDateConverter>().forEach { | ||
map.getOrPut(DescriptiveClass.from(it, it.sourceClass)) { mutableMapOf() }[DescriptiveClass.to(it, Date::class)] = | ||
it.enabledByDefault | ||
} | ||
typeConverters.filterIsInstance<XToDateConverter>().forEach { | ||
map.getOrPut(DescriptiveClass.from(it, it.sourceClass)) { mutableMapOf() }[DescriptiveClass.to(it, Date::class)] = | ||
it.enabledByDefault | ||
} | ||
|
||
val from = map.keys.sortedWith(compareBy({ it.clazz.simpleName }, { it.description })) | ||
val to = map.values.flatMap { it.keys }.distinct().sortedWith(compareBy({ it.clazz.simpleName }, { it.description })) | ||
|
||
val toWithoutBasic = to.filterNot { it.clazz in basicTypesList } | ||
|
||
val builder = Table.Builder() | ||
.withAlignments(Table.ALIGN_CENTER, *toWithoutBasic.map { Table.ALIGN_CENTER }.toTypedArray()) | ||
.addRow(FROM_TO, *toWithoutBasic.map { it.toString() }.toTypedArray()) | ||
|
||
from.forEach { fromClass -> | ||
builder.addRow( | ||
BoldText(fromClass.toString()), | ||
*toWithoutBasic.map { toClass -> | ||
if (fromClass == toClass) return@map "✔" | ||
when (map[fromClass]!![toClass]) { | ||
null -> null | ||
true -> "✔" | ||
false -> "☑" | ||
} | ||
}.toTypedArray() | ||
) | ||
|
||
} | ||
|
||
Files.writeString(outputDir.resolve("to_temporal.md"), builder.build().toString() + "\n{: .fixed-first-column-140 }") | ||
|
||
val fromWithoutBasic = from.filterNot { it.clazz in basicTypesList } | ||
val toOnlyBasic = to.filter { it.clazz in basicTypesList } | ||
|
||
val builder2 = Table.Builder() | ||
.withAlignments(Table.ALIGN_CENTER, *toOnlyBasic.map { Table.ALIGN_CENTER }.toTypedArray()) | ||
.addRow(FROM_TO, *toOnlyBasic.map { it.toString() }.toTypedArray()) | ||
|
||
fromWithoutBasic.forEach { fromClass -> | ||
builder2.addRow( | ||
BoldText(fromClass.toString()), | ||
*toOnlyBasic.map { toClass -> | ||
if (fromClass == toClass) return@map "✔" | ||
when (map[fromClass]!![toClass]) { | ||
null -> null | ||
true -> "✔" | ||
false -> "☑" | ||
} | ||
}.toTypedArray() | ||
) | ||
|
||
} | ||
|
||
Files.writeString( | ||
outputDir.resolve("from_temporal.md"), | ||
builder2.build().toString() + "\n{: .fixed-first-column-140 }" | ||
) | ||
} | ||
|
||
fun generateIterablesTypeConverterTable(outputDir: Path, typeConverters: List<TypeConverter>) { | ||
val iterableToIterableConverter = typeConverters | ||
.filterIsInstance<IterableToIterableConverter>() | ||
.first() | ||
|
||
val supportedIterables = IterableToIterableConverter.supported().map { it.substringAfterLast(".") }.sorted() | ||
|
||
val builder = Table.Builder() | ||
.withAlignments(Table.ALIGN_CENTER, *supportedIterables.map { Table.ALIGN_CENTER }.toTypedArray()) | ||
.addRow(FROM_TO, *supportedIterables.toTypedArray()) | ||
|
||
supportedIterables.forEach { clazzName -> | ||
builder.addRow( | ||
BoldText(clazzName), | ||
*supportedIterables | ||
.map { if (iterableToIterableConverter.enabledByDefault) "✔" else "☑" } | ||
.toTypedArray() | ||
) | ||
} | ||
|
||
Files.writeString(outputDir.resolve("iterable.md"), builder.build().toString() + "\n{: .fixed-first-column-160 }") | ||
} | ||
fun generateMapTypeConverterTable(outputDir: Path, typeConverters: List<TypeConverter>) { | ||
val mapToMapConverter = typeConverters | ||
.filterIsInstance<MapToMapConverter>() | ||
.first() | ||
|
||
val supportedMaps = MapToMapConverter.supported().map { it.substringAfterLast(".") }.sorted() | ||
|
||
val builder = Table.Builder() | ||
.withAlignments(Table.ALIGN_CENTER, *supportedMaps.map { Table.ALIGN_CENTER }.toTypedArray()) | ||
.addRow(FROM_TO, *supportedMaps.toTypedArray()) | ||
|
||
supportedMaps.forEach { clazzName -> | ||
builder.addRow( | ||
BoldText(clazzName), | ||
*supportedMaps | ||
.map { if (mapToMapConverter.enabledByDefault) "✔" else "☑" } | ||
.toTypedArray() | ||
) | ||
} | ||
|
||
Files.writeString(outputDir.resolve("map.md"), builder.build().toString() + "\n{: .fixed-first-column-140 }") | ||
} | ||
|
||
fun generateEnumTypeConverterTable(outputDir: Path, typeConverters: List<TypeConverter>, basicTypesList: List<KClass<*>>) { | ||
val map = mutableMapOf<DescriptiveClass, MutableMap<DescriptiveClass, Boolean>>() | ||
typeConverters.filterIsInstance<EnumToEnumConverter>().forEach { | ||
map.getOrPut(DescriptiveClass.from(it, Enum::class)) { mutableMapOf() }[DescriptiveClass.to(it, Enum::class)] = it.enabledByDefault | ||
} | ||
typeConverters.filterIsInstance<EnumToXConverter>().forEach { | ||
map.getOrPut(DescriptiveClass.from(it, Enum::class)) { mutableMapOf() }[DescriptiveClass.to(it, it.targetClass)] = it.enabledByDefault | ||
} | ||
typeConverters.filterIsInstance<XToEnumConverter>().forEach { | ||
map.getOrPut(DescriptiveClass.from(it, it.sourceClass)) { mutableMapOf() }[DescriptiveClass.to(it, Enum::class)] = it.enabledByDefault | ||
} | ||
|
||
val from = map.keys.sortedWith(compareBy({ it.clazz.simpleName }, { it.description })) | ||
val to = map.values.flatMap { it.keys }.distinct().sortedWith(compareBy({ it.clazz.simpleName }, { it.description })) | ||
|
||
val toWithoutBasic = to.filterNot { it.clazz in basicTypesList } | ||
|
||
val builder = Table.Builder() | ||
.withAlignments(Table.ALIGN_CENTER, *toWithoutBasic.map { Table.ALIGN_CENTER }.toTypedArray()) | ||
.addRow(FROM_TO, *toWithoutBasic.map { it.toString() }.toTypedArray()) | ||
|
||
from.forEach { fromClass -> | ||
builder.addRow( | ||
BoldText(fromClass.toString()), | ||
*toWithoutBasic.map { toClass -> | ||
when (map[fromClass]!![toClass]) { | ||
null -> null | ||
true -> "✔" | ||
false -> "☑" | ||
} | ||
}.toTypedArray() | ||
) | ||
} | ||
|
||
Files.writeString(outputDir.resolve("to_enum.md"), builder.build().toString() + "\n{: .fixed-first-column-120 }") | ||
|
||
val fromWithoutBasic = from.filterNot { it.clazz in basicTypesList } | ||
val toWithoutEnum = to.filter { it.clazz != Enum::class } | ||
|
||
val builder2 = Table.Builder() | ||
.withAlignments(Table.ALIGN_CENTER, *toWithoutEnum.map { Table.ALIGN_CENTER }.toTypedArray()) | ||
.addRow(FROM_TO, *toWithoutEnum.map { it.toString() }.toTypedArray()) | ||
|
||
fromWithoutBasic.forEach { fromClass -> | ||
builder2.addRow( | ||
BoldText(fromClass.toString()), | ||
*toWithoutEnum.map { toClass -> | ||
when (map[fromClass]!![toClass]) { | ||
null -> null | ||
true -> "✔" | ||
false -> "☑" | ||
} | ||
}.toTypedArray() | ||
) | ||
} | ||
|
||
Files.writeString(outputDir.resolve("from_enum.md"), builder2.build().toString() + "\n{: .fixed-first-column-120 }") | ||
|
||
} | ||
|
||
data class DescriptiveClass(val description: String?, val clazz: KClass<*>) { | ||
|
||
companion object { | ||
fun from(converter: Any, sourceClass: KClass<*>) = DescriptiveClass( | ||
when (converter) { | ||
is LongEpochMillisToDateConverter -> "epoch ms" | ||
is LongEpochMillisToInstantConverter -> "epoch ms" | ||
is LongEpochSecondsToDateConverter -> "epoch s" | ||
is LongEpochSecondsToInstantConverter -> "epoch s" | ||
else -> null | ||
}, | ||
sourceClass | ||
) | ||
|
||
fun to(converter: Any, targetClazz: KClass<*>) = DescriptiveClass( | ||
when (converter) { | ||
is DateToLongEpochMillisConverter -> "epoch ms" | ||
is InstantToLongEpochMillisConverter -> "epoch ms" | ||
is OffsetDateTimeToLongEpochMillisConverter -> "epoch ms" | ||
is ZonedDateTimeToLongEpochMillisConverter -> "epoch ms" | ||
is DateToLongEpochSecondsConverter -> "epoch s" | ||
is InstantToLongEpochSecondsConverter -> "epoch s" | ||
is OffsetDateTimeToLongEpochSecondsConverter -> "epoch s" | ||
is ZonedDateTimeToLongEpochSecondsConverter -> "epoch s" | ||
else -> null | ||
}, | ||
targetClazz | ||
) | ||
} | ||
|
||
override fun toString(): String { | ||
return clazz.simpleName + if (description != null) " ($description)" else "" | ||
} | ||
} |
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,17 @@ | ||
| From\To | Boolean | Byte | Char | Double | Float | Int | Long | Number | Short | String | UByte | UInt | ULong | UShort | | ||
|:-----------:|:-------:|:----:|:----:|:------:|:-----:|:---:|:----:|:------:|:-----:|:------:|:-----:|:----:|:-----:|:------:| | ||
| **Boolean** | ✔ | ☑ | ☑ | ☑ | ☑ | ☑ | ☑ | ☑ | ☑ | ✔ | ☑ | ☑ | ☑ | ☑ | | ||
| **Byte** | ☑ | ✔ | ☑ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ☑ | ☑ | ☑ | ☑ | | ||
| **Char** | ☑ | ☑ | ✔ | ☑ | ☑ | ☑ | ☑ | ☑ | ☑ | ✔ | ☑ | ☑ | ☑ | ☑ | | ||
| **Double** | ☑ | ☑ | ☑ | ✔ | ☑ | ☑ | ☑ | ✔ | ☑ | ✔ | ☑ | ☑ | ☑ | ☑ | | ||
| **Float** | ☑ | ☑ | ☑ | ✔ | ✔ | ☑ | ☑ | ✔ | ☑ | ✔ | ☑ | ☑ | ☑ | ☑ | | ||
| **Int** | ☑ | ☑ | ☑ | ✔ | ✔ | ✔ | ✔ | ✔ | ☑ | ✔ | ☑ | ☑ | ☑ | ☑ | | ||
| **Long** | ☑ | ☑ | ☑ | ✔ | ☑ | ☑ | ✔ | ✔ | ☑ | ✔ | ☑ | ☑ | ☑ | ☑ | | ||
| **Number** | ☑ | ☑ | ☑ | ☑ | ☑ | ☑ | ☑ | ✔ | ☑ | ✔ | ☑ | ☑ | ☑ | ☑ | | ||
| **Short** | ☑ | ☑ | ☑ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ☑ | ☑ | ☑ | ☑ | | ||
| **String** | ☑ | ☑ | ☑ | ☑ | ☑ | ☑ | ☑ | ☑ | ☑ | ✔ | ☑ | ☑ | ☑ | ☑ | | ||
| **UByte** | ☑ | ☑ | ☑ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | ||
| **UInt** | ☑ | ☑ | ☑ | ✔ | ✔ | ☑ | ✔ | ✔ | ☑ | ✔ | ☑ | ✔ | ✔ | ☑ | | ||
| **ULong** | ☑ | ☑ | ☑ | ✔ | ☑ | ☑ | ☑ | ✔ | ☑ | ✔ | ☑ | ☑ | ✔ | ☑ | | ||
| **UShort** | ☑ | ☑ | ☑ | ✔ | ✔ | ✔ | ✔ | ✔ | ☑ | ✔ | ☑ | ✔ | ✔ | ✔ | | ||
{: .fixed-first-column-120 } |
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,4 @@ | ||
| From\To | Byte | Char | Double | Float | Int | Long | Number | Short | String | UByte | UInt | ULong | UShort | | ||
|:--------:|:----:|:----:|:------:|:-----:|:---:|:----:|:------:|:-----:|:------:|:-----:|:----:|:-----:|:------:| | ||
| **Enum** | ☑ | ☑ | ☑ | ☑ | ✔ | ✔ | ✔ | ✔ | ✔ | ☑ | ✔ | ✔ | ✔ | | ||
{: .fixed-first-column-120 } |
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,11 @@ | ||
| From\To | Long (epoch ms) | Long (epoch s) | String | | ||
|:------------------:|:---------------:|:--------------:|:------:| | ||
| **Date** | ✔ | ☑ | ✔ | | ||
| **Instant** | ✔ | ☑ | ✔ | | ||
| **LocalDate** | | | ✔ | | ||
| **LocalDateTime** | | | ✔ | | ||
| **LocalTime** | | | ✔ | | ||
| **OffsetDateTime** | ✔ | ☑ | ✔ | | ||
| **OffsetTime** | | | ✔ | | ||
| **ZonedDateTime** | ✔ | ☑ | ✔ | | ||
{: .fixed-first-column-140 } |
Oops, something went wrong.