Skip to content

Commit 986dc0d

Browse files
authored
Merge pull request #52 from samtkit/generator-register
Add API to register generators
2 parents ec49d95 + 71a62ba commit 986dc0d

File tree

8 files changed

+74
-27
lines changed

8 files changed

+74
-27
lines changed

cli/src/main/kotlin/tools/samt/cli/CliCompiler.kt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tools.samt.cli
22

33
import tools.samt.codegen.Codegen
4+
import tools.samt.codegen.http.HttpTransportConfigurationParser
45
import tools.samt.common.DiagnosticController
56
import tools.samt.common.DiagnosticException
67
import tools.samt.common.collectSamtFiles
@@ -11,6 +12,9 @@ import tools.samt.semantic.SemanticModel
1112
import java.io.IOException
1213
import kotlin.io.path.isDirectory
1314
import kotlin.io.path.notExists
15+
import tools.samt.codegen.kotlin.KotlinTypesGenerator
16+
import tools.samt.codegen.kotlin.ktor.KotlinKtorConsumerGenerator
17+
import tools.samt.codegen.kotlin.ktor.KotlinKtorProviderGenerator
1418

1519
internal fun compile(command: CompileCommand, controller: DiagnosticController) {
1620
val (configuration ,_) = CliConfigParser.readConfig(command.file, controller) ?: return
@@ -65,12 +69,17 @@ internal fun compile(command: CompileCommand, controller: DiagnosticController)
6569
return
6670
}
6771

68-
for (generator in configuration.generators) {
69-
val files = Codegen.generate(model, generator, controller)
72+
Codegen.registerGenerator(KotlinTypesGenerator)
73+
Codegen.registerGenerator(KotlinKtorProviderGenerator)
74+
Codegen.registerGenerator(KotlinKtorConsumerGenerator)
75+
Codegen.registerTransportParser(HttpTransportConfigurationParser)
76+
77+
for (generatorConfig in configuration.generators) {
78+
val files = Codegen.generate(model, generatorConfig, controller)
7079
try {
71-
OutputWriter.write(generator.output, files)
80+
OutputWriter.write(generatorConfig.output, files)
7281
} catch (e: IOException) {
73-
controller.reportGlobalError("Failed to write output for generator '${generator.name}': ${e.message}")
82+
controller.reportGlobalError("Failed to write output for generator '${generatorConfig.name}': ${e.message}")
7483
}
7584
}
7685
}

codegen/src/main/kotlin/tools/samt/codegen/Codegen.kt

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,33 @@ import tools.samt.api.plugin.Generator
55
import tools.samt.api.plugin.GeneratorParams
66
import tools.samt.api.plugin.TransportConfigurationParser
77
import tools.samt.api.types.SamtPackage
8-
import tools.samt.codegen.http.HttpTransportConfigurationParser
9-
import tools.samt.codegen.kotlin.KotlinTypesGenerator
10-
import tools.samt.codegen.kotlin.ktor.KotlinKtorConsumerGenerator
11-
import tools.samt.codegen.kotlin.ktor.KotlinKtorProviderGenerator
128
import tools.samt.common.DiagnosticController
139
import tools.samt.common.SamtGeneratorConfiguration
1410
import tools.samt.semantic.SemanticModel
1511

1612
object Codegen {
17-
private val generators: List<Generator> = listOf(
18-
KotlinTypesGenerator,
19-
KotlinKtorProviderGenerator,
20-
KotlinKtorConsumerGenerator,
21-
)
13+
private val generators: MutableList<Generator> = mutableListOf()
2214

23-
private val transports: List<TransportConfigurationParser> = listOf(
24-
HttpTransportConfigurationParser,
25-
)
15+
/**
16+
* Register the [generator] to be used when generating code.
17+
* The generator is called when a user configures it within their `samt.yaml` configuration, where the generator is referenced by its [Generator.name].
18+
* Only generators registered here will be considered when calling [generate].
19+
*/
20+
@JvmStatic
21+
fun registerGenerator(generator: Generator) {
22+
generators += generator
23+
}
24+
25+
private val transports: MutableList<TransportConfigurationParser> = mutableListOf()
26+
27+
/**
28+
* Register the [parser] as a transport configuration, which will be used to parse the `transport` section of a SAMT provider.
29+
* Only transport configurations registered here will be considered when calling [generate].
30+
*/
31+
@JvmStatic
32+
fun registerTransportParser(parser: TransportConfigurationParser) {
33+
transports += parser
34+
}
2635

2736
internal class SamtGeneratorParams(
2837
semanticModel: SemanticModel,
@@ -45,6 +54,12 @@ object Codegen {
4554
}
4655
}
4756

57+
/**
58+
* Run the appropriate generator for the given [configuration], using the given [semanticModel].
59+
* To ensure binary compatibility, the types within the [semanticModel] will be mapped to their [tools.samt.api] equivalents.
60+
* @return a list of generated files
61+
*/
62+
@JvmStatic
4863
fun generate(
4964
semanticModel: SemanticModel,
5065
configuration: SamtGeneratorConfiguration,

codegen/src/main/kotlin/tools/samt/codegen/PublicApiMapper.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,10 @@ class PublicApiMapper(
142142
else -> controller.reportGlobalError("Multiple transport configuration parsers found for transport '$name'")
143143
}
144144

145-
return object : TransportConfiguration {}
145+
return object : TransportConfiguration {
146+
override val name: String
147+
get() = this@toPublicTransport.name
148+
}
146149
}
147150

148151
private fun tools.samt.semantic.ProviderType.Implements.toPublicImplements() = object : ProvidedService {
@@ -169,7 +172,7 @@ class PublicApiMapper(
169172
override val name get() = this@toPublicAlias.name
170173
override val qualifiedName by unsafeLazy { this@toPublicAlias.getQualifiedName() }
171174
override val aliasedType by unsafeLazy { this@toPublicAlias.aliasedType.toPublicTypeReference() }
172-
override val fullyResolvedType by unsafeLazy { this@toPublicAlias.fullyResolvedType.toPublicTypeReference() }
175+
override val runtimeType by unsafeLazy { this@toPublicAlias.fullyResolvedType.toPublicTypeReference() }
173176
}
174177

175178
private inline fun <reified T : tools.samt.semantic.ResolvedTypeReference.Constraint> List<tools.samt.semantic.ResolvedTypeReference.Constraint>.findConstraint() =

codegen/src/main/kotlin/tools/samt/codegen/http/HttpTransport.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import tools.samt.api.transports.http.SerializationMode
99
import tools.samt.api.transports.http.TransportMode
1010

1111
object HttpTransportConfigurationParser : TransportConfigurationParser {
12-
override val transportName: String
13-
get() = "http"
12+
override val transportName: String get() = HttpTransportConfiguration.name
1413

1514
private val isValidRegex = Regex("""\w+\s+\S+(\s+\{.*?\s+in\s+\S+})*""")
1615
private val methodEndpointRegex = Regex("""(\w+)\s+(\S+)(.*)""")
@@ -212,6 +211,8 @@ class HttpTransportConfiguration(
212211
override val serializationMode: SerializationMode,
213212
val services: List<ServiceConfiguration>,
214213
) : SamtHttpTransport {
214+
override val name: String = HttpTransportConfiguration.name
215+
215216
class ServiceConfiguration(
216217
val name: String,
217218
val path: String,
@@ -284,4 +285,8 @@ class HttpTransportConfiguration(
284285
TransportMode.Body
285286
}
286287
}
288+
289+
companion object {
290+
const val name = "http"
291+
}
287292
}

codegen/src/main/kotlin/tools/samt/codegen/kotlin/ktor/KotlinKtorGeneratorUtilities.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,16 @@ private fun StringBuilder.appendDecodeRecordField(field: RecordField, options: M
121121
private fun StringBuilder.appendEncodeAlias(alias: AliasType, options: Map<String, String>) {
122122
appendLine("/** Encode alias ${alias.qualifiedName} to JSON */")
123123
appendLine("fun `encode ${alias.name}`(value: ${alias.getQualifiedName(options)}): JsonElement =")
124-
appendLine(" ${encodeJsonElement(alias.fullyResolvedType, options, valueName = "value")}")
124+
appendLine(" ${encodeJsonElement(alias.runtimeType, options, valueName = "value")}")
125125
}
126126

127127
private fun StringBuilder.appendDecodeAlias(alias: AliasType, options: Map<String, String>) {
128128
appendLine("/** Decode alias ${alias.qualifiedName} from JSON */")
129-
appendLine("fun `decode ${alias.name}`(json: JsonElement): ${alias.fullyResolvedType.getQualifiedName(options)} {")
130-
if (alias.fullyResolvedType.isRuntimeOptional) {
129+
appendLine("fun `decode ${alias.name}`(json: JsonElement): ${alias.runtimeType.getQualifiedName(options)} {")
130+
if (alias.runtimeType.isRuntimeOptional) {
131131
appendLine(" if (json is JsonNull) return null")
132132
}
133-
appendLine(" return ${decodeJsonElement(alias.fullyResolvedType, options, valueName = "json")}")
133+
appendLine(" return ${decodeJsonElement(alias.runtimeType, options, valueName = "json")}")
134134
appendLine("}")
135135
}
136136

codegen/src/test/kotlin/tools/samt/codegen/CodegenTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tools.samt.codegen
22

33
import tools.samt.api.plugin.CodegenFile
4+
import tools.samt.codegen.http.HttpTransportConfigurationParser
45
import tools.samt.common.DiagnosticController
56
import tools.samt.common.collectSamtFiles
67
import tools.samt.common.readSamtSource
@@ -13,6 +14,9 @@ import kotlin.io.path.Path
1314
import kotlin.test.Test
1415
import kotlin.test.assertEquals
1516
import kotlin.test.assertFalse
17+
import tools.samt.codegen.kotlin.KotlinTypesGenerator
18+
import tools.samt.codegen.kotlin.ktor.KotlinKtorConsumerGenerator
19+
import tools.samt.codegen.kotlin.ktor.KotlinKtorProviderGenerator
1620

1721
class CodegenTest {
1822
private val testDirectory = Path("src/test/resources/generator-test-model")
@@ -43,6 +47,11 @@ class CodegenTest {
4347

4448
assertFalse(controller.hasErrors())
4549

50+
Codegen.registerGenerator(KotlinTypesGenerator)
51+
Codegen.registerGenerator(KotlinKtorProviderGenerator)
52+
Codegen.registerGenerator(KotlinKtorConsumerGenerator)
53+
Codegen.registerTransportParser(HttpTransportConfigurationParser)
54+
4655
val actualFiles = mutableListOf<CodegenFile>()
4756
for (generator in configuration.generators) {
4857
actualFiles += Codegen.generate(model, generator, controller).map { it.copy(filepath = generator.output.resolve(it.filepath).toString()) }

public-api/src/main/kotlin/tools/samt/api/plugin/Transport.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ interface TransportConfigurationParser {
2626
* A base interface for transport configurations.
2727
* This interface is intended to be sub-typed and extended by transport configuration implementations.
2828
*/
29-
interface TransportConfiguration
29+
interface TransportConfiguration {
30+
/**
31+
* The name of this transport protocol.
32+
* Can be used to display to a user.
33+
*/
34+
val name: String
35+
}
3036

3137
/**
3238
* The parameters for a [TransportConfigurationParser].

public-api/src/main/kotlin/tools/samt/api/types/UserTypes.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ interface AliasType : UserType {
2020
val aliasedType: TypeReference
2121

2222
/**
23-
* The fully resolved type, will not contain any type aliases anymore, just the underlying merged type
23+
* The runtime type, which will not contain any type aliases, just the underlying merged type
2424
*/
25-
val fullyResolvedType: TypeReference
25+
val runtimeType: TypeReference
2626
}
2727

2828
/**

0 commit comments

Comments
 (0)