in thrifty-kotlin-codegen/src/main/kotlin/com/microsoft/thrifty/kgen/KotlinCodeGenerator.kt [287:394]
fun generate(schema: Schema): List<FileSpec> {
specsByNamespace.clear()
constantsByNamespace.clear()
typedefsByNamespace.clear()
schema.typedefs.forEach { typedefsByNamespace.put(it.kotlinNamespace, generateTypeAlias(it)) }
schema.enums.forEach { specsByNamespace.put(it.kotlinNamespace, generateEnumClass(it)) }
schema.structs.forEach { specsByNamespace.put(it.kotlinNamespace, generateDataClass(schema, it)) }
schema.unions.forEach {
// NOTE: We can't adequately represent empty unions with sealed classes, because one can't
// _isntantiate_ an empty sealed class. As an ugly hack, we represent empty unions
// as a plain-old class. We could technically make it an object, but I don't really
// care enough to do it. Empty unions themselves are ugly, so this ugly hack is fitting.
val spec = if (it.fields.isNotEmpty()) { generateSealedClass(schema, it) } else { generateDataClass(schema, it) }
specsByNamespace.put(it.kotlinNamespace, spec)
}
schema.exceptions.forEach { specsByNamespace.put(it.kotlinNamespace, generateDataClass(schema, it)) }
val constantNameAllocators = mutableMapOf<String, NameAllocator>()
schema.constants.forEach {
val ns = it.kotlinNamespace
val allocator = constantNameAllocators.getOrPut(ns) { NameAllocator() }
val property = generateConstantProperty(schema, allocator, it)
constantsByNamespace.put(ns, property)
}
if (!omitServiceClients) {
schema.services.forEach {
val iface: TypeSpec
val impl: TypeSpec
if (coroutineServiceClients) {
iface = generateCoroServiceInterface(it)
impl = generateCoroServiceImplementation(schema, it, iface)
} else {
iface = generateServiceInterface(it)
impl = generateServiceImplementation(schema, it, iface)
}
specsByNamespace.put(it.kotlinNamespace, iface)
specsByNamespace.put(it.kotlinNamespace, impl)
}
}
if (generateServer) {
schema.services.forEach {
val iface = generateCoroServiceInterface(it)
specsByNamespace.put(getServerNamespaceFor(it), iface)
specsByNamespace.put(
it.kotlinNamespace,
generateProcessorImplementation(
schema,
it,
iface
)
)
}
}
return when (outputStyle) {
OutputStyle.FILE_PER_NAMESPACE -> {
val namespaces = mutableSetOf<String>().apply {
addAll(specsByNamespace.keys())
addAll(constantsByNamespace.keys())
}
val fileSpecsByNamespace = namespaces
.map { it to makeFileSpecBuilder(it, "ThriftTypes") }
.toMap()
fileSpecsByNamespace.map { (ns, fileSpec) ->
typedefsByNamespace[ns]?.forEach { fileSpec.addTypeAlias(it) }
constantsByNamespace[ns]?.forEach { fileSpec.addProperty(it) }
specsByNamespace[ns]
?.mapNotNull { processor.process(it) }
?.forEach { fileSpec.addType(it) }
fileSpec.build()
}
}
OutputStyle.FILE_PER_TYPE -> {
sequence {
val types = specsByNamespace.entries().asSequence()
for ((ns, type) in types) {
val processedType = processor.process(type) ?: continue
val name = processedType.name ?: throw AssertionError("Top-level TypeSpecs must have names")
val spec = makeFileSpecBuilder(ns, name)
.addType(processedType)
.build()
yield(spec)
}
for ((ns, aliases) in typedefsByNamespace.asMap().entries) {
val spec = makeFileSpecBuilder(ns, "Typedefs")
aliases.forEach { spec.addTypeAlias(it) }
yield(spec.build())
}
for ((ns, props) in constantsByNamespace.asMap().entries) {
val spec = makeFileSpecBuilder(ns, "Constants")
props.forEach { spec.addProperty(it) }
yield(spec.build())
}
}.toList()
}
}
}