All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.auritylab.graphql.kotlin.toolkit.codegen.Codegen.kt Maven / Gradle / Ivy

There is a newer version: 0.7.3
Show newest version
package com.auritylab.graphql.kotlin.toolkit.codegen

import com.auritylab.graphql.kotlin.toolkit.codegen.generator.EnumGenerator
import com.auritylab.graphql.kotlin.toolkit.codegen.generator.EnvironmentWrapperGenerator
import com.auritylab.graphql.kotlin.toolkit.codegen.generator.FieldResolverGenerator
import com.auritylab.graphql.kotlin.toolkit.codegen.generator.InputObjectGenerator
import com.auritylab.graphql.kotlin.toolkit.codegen.generator.ValueWrapperGenerator
import com.auritylab.graphql.kotlin.toolkit.codegen.helper.KotlinGenerateHelper
import com.auritylab.graphql.kotlin.toolkit.codegen.mapper.GeneratedMapper
import com.auritylab.graphql.kotlin.toolkit.codegen.mapper.KotlinTypeMapper
import com.auritylab.graphql.kotlin.toolkit.codegen.mock.WiringFactoryMock
import graphql.schema.GraphQLEnumType
import graphql.schema.GraphQLInputObjectType
import graphql.schema.GraphQLInterfaceType
import graphql.schema.GraphQLObjectType
import graphql.schema.GraphQLSchema
import graphql.schema.idl.RuntimeWiring
import graphql.schema.idl.SchemaGenerator
import graphql.schema.idl.SchemaParser
import graphql.schema.idl.TypeDefinitionRegistry
import java.nio.file.Files
import java.nio.file.Path

/**
 * Represents the base class for the code generation.
 *
 * directive @kotlinRepresentation(class: String!) on OBJECT | SCALAR
 * directive @kotlinGenerate on FIELD_DEFINITION | ENUM
 */
class Codegen(
    inputOptions: CodegenOptions = CodegenOptions()
) {
    internal val options = mapOptions(inputOptions)
    internal val schema = parseSchemas(options.schemas)
    internal val nameMapper = GeneratedMapper(options)
    internal val kotlinTypeMapper = KotlinTypeMapper(options, nameMapper)
    internal val outputDirectory = getOutputDirectory()

    internal val enumGenerator = EnumGenerator(options, kotlinTypeMapper, nameMapper)
    internal val fieldResolverGenerator = FieldResolverGenerator(options, kotlinTypeMapper, nameMapper)
    internal val inputObjectGenerator = InputObjectGenerator(options, kotlinTypeMapper, nameMapper)
    internal val valueWrapperGenerator = ValueWrapperGenerator(options, kotlinTypeMapper, nameMapper)
    internal val environmentWrapperGenerator = EnvironmentWrapperGenerator(options, kotlinTypeMapper, nameMapper)

    /**
     * Will generate code for the types of the [schema].
     */
    fun generate() {
        // Get all registered types.
        val allTypes = schema.allTypesAsList

        // Create code for all enum types.
        allTypes.filterIsInstance()
            .forEach { enumGenerator.getEnum(it).writeTo(outputDirectory) }

        // Will create code for all input object types.
        allTypes.filterIsInstance()
            .forEach {
                inputObjectGenerator.getInputObject(it)
                    .writeTo(outputDirectory)
            }

        // Will create code for all object types.
        allTypes.filterIsInstance()
            .forEach { objectType ->
                val generatedForObject = KotlinGenerateHelper.shouldGenerate(objectType)

                objectType.fieldDefinitions.forEach { fieldDefinition ->
                    if (options.generateAll || generatedForObject || KotlinGenerateHelper.shouldGenerate(fieldDefinition))
                        fieldResolverGenerator.getFieldResolver(objectType, fieldDefinition)
                            .writeTo(outputDirectory)
                }
            }

        // Will create code for all interface types.
        allTypes.filterIsInstance()
            .forEach { interfaceType ->
                val generatedForInterface = KotlinGenerateHelper.shouldGenerate(interfaceType)

                interfaceType.fieldDefinitions.forEach { fieldDefinition ->
                    if (options.generateAll || generatedForInterface || KotlinGenerateHelper.shouldGenerate(
                            fieldDefinition
                        )
                    )
                        fieldResolverGenerator.getFieldResolver(interfaceType, fieldDefinition)
                            .writeTo(outputDirectory)
                }
            }

        // Will create code for the value wrapper.
        valueWrapperGenerator.getValueWrapper()
            .writeTo(outputDirectory)

        // Will create code for the environment wrapper.
        environmentWrapperGenerator.getEnvironmentWrapper()
            .writeTo(outputDirectory)
    }

    /**
     * Will parse the given [schemaFiles] and return a [GraphQLSchema] which contains all
     * registered definitions from the given schemas.
     */
    private fun parseSchemas(schemaFiles: Collection): GraphQLSchema {
        val parser = SchemaParser()
        val generator = SchemaGenerator()

        // Create a empty registry.
        val baseRegistry = TypeDefinitionRegistry()

        // Parse each schema and merge it with the base registry.
        schemaFiles.forEach {
            baseRegistry.merge(parser.parse(it.toFile()))
        }

        val genOptions = SchemaGenerator.Options.defaultOptions().enforceSchemaDirectives(false)

        return generator.makeExecutableSchema(
            genOptions,
            baseRegistry,
            RuntimeWiring.newRuntimeWiring().wiringFactory(WiringFactoryMock()).build()
        )
    }

    /**
     * Will return the output directory [Path] from the [options].
     * This method will also ensure that the directories exist.
     */
    private fun getOutputDirectory(): Path {
        val directory = options.outputDirectory

        // Ensure the existence of the base output directory.
        Files.createDirectories(directory)

        return directory
    }

    private fun mapOptions(inputOptions: CodegenOptions): CodegenInternalOptions {
        val schemaFiles = inputOptions.schemas
            ?: throw IllegalArgumentException("'schemaFiles' not set")
        val outputDirectory = inputOptions.outputDirectory
            ?: throw IllegalArgumentException("'outputDirectory' not set")
        val generatedGlobalPrefix = inputOptions.generatedGlobalPrefix
        val generatedBasePackage = inputOptions.generatedBasePackage ?: "graphql.kotlin.toolkit.codegen"
        val generateAll = inputOptions.generateAll ?: true

        return CodegenInternalOptions(
            schemaFiles,
            outputDirectory,
            generatedGlobalPrefix,
            generatedBasePackage,
            generateAll
        )
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy