Add setting for Kotlin package to codegen (#194)

This commit is contained in:
Sam Gammon
2024-02-23 02:54:05 -08:00
committed by GitHub
parent 48a000aa1a
commit 7f404fff49
7 changed files with 145 additions and 8 deletions

View File

@@ -29,6 +29,9 @@ data class CliKotlinCodeGeneratorOptions(
/** The characters to use for indenting generated source code. */
val indent: String = " ",
/** Kotlin package to use for generated code; if none is provided, the root package is used. */
val kotlinPackage: String = "",
/** Whether to generate Kdoc based on doc comments for Pkl modules, classes, and properties. */
val generateKdoc: Boolean = false,
@@ -39,5 +42,11 @@ data class CliKotlinCodeGeneratorOptions(
val implementSerializable: Boolean = false
) {
fun toKotlinCodegenOptions(): KotlinCodegenOptions =
KotlinCodegenOptions(indent, generateKdoc, generateSpringBootConfig, implementSerializable)
KotlinCodegenOptions(
indent = indent,
generateKdoc = generateKdoc,
generateSpringBootConfig = generateSpringBootConfig,
implementSerializable = implementSerializable,
kotlinPackage = kotlinPackage,
)
}

View File

@@ -27,6 +27,9 @@ data class KotlinCodegenOptions(
/** The characters to use for indenting generated Kotlin code. */
val indent: String = " ",
/** Kotlin package to use for generated code; if none is provided, the root package is used. */
val kotlinPackage: String = "",
/** Whether to generate KDoc based on doc comments for Pkl modules, classes, and properties. */
val generateKdoc: Boolean = false,
@@ -111,6 +114,9 @@ class KotlinCodeGenerator(
append("lin/${relativeOutputPathFor(moduleSchema.moduleName)}")
}
val kotlinPackage: String?
get() = options.kotlinPackage.ifEmpty { null }
val kotlinFile: String
get() {
if (moduleSchema.moduleUri.scheme == "pkl") {
@@ -123,6 +129,7 @@ class KotlinCodeGenerator(
val hasProperties = pModuleClass.properties.any { !it.value.isHidden }
val isGenerateClass = hasProperties || pModuleClass.isOpen || pModuleClass.isAbstract
val packagePrefix = kotlinPackage?.let { "$it." } ?: ""
val moduleType =
if (isGenerateClass) {
generateTypeSpec(pModuleClass, moduleSchema)
@@ -172,7 +179,9 @@ class KotlinCodeGenerator(
val packageName = if (index == -1) "" else moduleName.substring(0, index)
val moduleTypeName = moduleName.substring(index + 1).replaceFirstChar { it.titlecaseChar() }
val fileSpec = FileSpec.builder(packageName, moduleTypeName).indent(options.indent)
val packagePath =
if (packagePrefix.isNotBlank()) "$packagePrefix.$packageName" else packageName
val fileSpec = FileSpec.builder(packagePath, moduleTypeName).indent(options.indent)
for (typeAlias in moduleSchema.typeAliases.values) {
if (typeAlias.aliasedType is PType.Alias) {
@@ -638,10 +647,14 @@ class KotlinCodeGenerator(
val index = moduleName.lastIndexOf(".")
val packageName = if (index == -1) "" else moduleName.substring(0, index)
val moduleTypeName = moduleName.substring(index + 1).replaceFirstChar { it.titlecaseChar() }
val packagePrefix = kotlinPackage?.let { "$it." } ?: ""
val renderedPackage =
if (packagePrefix.isNotBlank()) "$packagePrefix.$packageName" else packageName
return if (isModuleClass) {
ClassName(packageName, moduleTypeName)
ClassName(renderedPackage, moduleTypeName)
} else {
ClassName(packageName, moduleTypeName, simpleName)
ClassName(renderedPackage, moduleTypeName, simpleName)
}
}

View File

@@ -133,7 +133,8 @@ class KotlinCodeGeneratorTest {
pklCode: String,
generateKdoc: Boolean = false,
generateSpringBootConfig: Boolean = false,
implementSerializable: Boolean = false
implementSerializable: Boolean = false,
kotlinPackage: String? = null,
): String {
val module = Evaluator.preconfigured().evaluateSchema(ModuleSource.text(pklCode))
@@ -144,7 +145,8 @@ class KotlinCodeGeneratorTest {
KotlinCodegenOptions(
generateKdoc = generateKdoc,
generateSpringBootConfig = generateSpringBootConfig,
implementSerializable = implementSerializable
implementSerializable = implementSerializable,
kotlinPackage = kotlinPackage ?: "",
)
)
return generator.kotlinFile
@@ -553,6 +555,92 @@ class KotlinCodeGeneratorTest {
assertCompilesSuccessfully(kotlinCode)
}
@Test
fun `custom kotlin package prefix`() {
val kotlinCode =
generateKotlinCode(
"""
module my.mod
class Person {
name: String
age: Int
hobbies: List<String>
friends: Map<String, Person>
sibling: Person?
}
""",
kotlinPackage = "cool.pkg.path",
)
assertEqualTo(
"""
package cool.pkg.path.my
import kotlin.Long
import kotlin.String
import kotlin.collections.List
import kotlin.collections.Map
object Mod {
data class Person(
val name: String,
val age: Long,
val hobbies: List<String>,
val friends: Map<String, Person>,
val sibling: Person?
)
}
""",
kotlinCode
)
assertCompilesSuccessfully(kotlinCode)
}
@Test
fun `empty kotlin package prefix`() {
val kotlinCode =
generateKotlinCode(
"""
module my.mod
class Person {
name: String
age: Int
hobbies: List<String>
friends: Map<String, Person>
sibling: Person?
}
""",
kotlinPackage = "",
)
assertEqualTo(
"""
package my
import kotlin.Long
import kotlin.String
import kotlin.collections.List
import kotlin.collections.Map
object Mod {
data class Person(
val name: String,
val age: Long,
val hobbies: List<String>,
val friends: Map<String, Person>,
val sibling: Person?
)
}
""",
kotlinCode
)
assertCompilesSuccessfully(kotlinCode)
}
@Test
fun `recursive types`() {
val kotlinCode =