fun generate()

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()
            }
        }
    }