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

com.apollographql.apollo3.gradle.internal.ApolloGenerateSourcesTask.kt Maven / Gradle / Ivy

package com.apollographql.apollo3.gradle.internal

import com.apollographql.apollo3.annotations.ApolloExperimental
import com.apollographql.apollo3.compiler.APOLLO_VERSION
import com.apollographql.apollo3.compiler.ApolloMetadata
import com.apollographql.apollo3.compiler.CommonMetadata
import com.apollographql.apollo3.compiler.ApolloCompiler
import com.apollographql.apollo3.compiler.IncomingOptions
import com.apollographql.apollo3.compiler.IncomingOptions.Companion.resolveSchema
import com.apollographql.apollo3.compiler.MODELS_OPERATION_BASED
import com.apollographql.apollo3.compiler.MODELS_RESPONSE_BASED
import com.apollographql.apollo3.compiler.OperationOutputGenerator
import com.apollographql.apollo3.compiler.Options
import com.apollographql.apollo3.compiler.Options.Companion.defaultAlwaysGenerateTypesMatching
import com.apollographql.apollo3.compiler.Options.Companion.defaultCodegenModels
import com.apollographql.apollo3.compiler.Options.Companion.defaultFailOnWarnings
import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateAsInternal
import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateFilterNotNull
import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateFragmentImplementations
import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateOptionalOperationVariables
import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateQueryDocument
import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateResponseFields
import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateSchema
import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateTestBuilders
import com.apollographql.apollo3.compiler.Options.Companion.defaultSealedClassesForEnumsMatching
import com.apollographql.apollo3.compiler.Options.Companion.defaultUseSemanticNaming
import com.apollographql.apollo3.compiler.Options.Companion.defaultWarnOnDeprecatedUsages
import com.apollographql.apollo3.compiler.PackageNameGenerator
import com.apollographql.apollo3.compiler.TargetLanguage
import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskAction
import javax.inject.Inject

@CacheableTask
@OptIn(ApolloExperimental::class)
abstract class ApolloGenerateSourcesTask : DefaultTask() {
  @get:OutputFile
  @get:Optional
  abstract val operationOutputFile: RegularFileProperty

  @get:OutputFile
  @get:Optional
  abstract val metadataOutputFile: RegularFileProperty

  @get:InputFiles
  @get:PathSensitive(PathSensitivity.RELATIVE)
  abstract val graphqlFiles: ConfigurableFileCollection

  /**
   * It's ok to have schemaFiles empty if there is some metadata
   */
  @get:InputFiles
  @get:PathSensitive(PathSensitivity.RELATIVE)
  abstract val schemaFiles: ConfigurableFileCollection

  @get:InputFiles
  @get:PathSensitive(PathSensitivity.RELATIVE)
  abstract val metadataFiles: ConfigurableFileCollection

  @get:Input
  abstract val rootFolders: ListProperty

  @get:Input
  @get:Optional
  abstract val alwaysGenerateTypesMatching: SetProperty

  @get:Internal
  lateinit var packageNameGenerator: PackageNameGenerator

  @Input
  fun getPackageNameGeneratorVersion() = packageNameGenerator.version

  @get:Internal
  lateinit var operationOutputGenerator: OperationOutputGenerator

  @Input
  fun getOperationOutputGeneratorVersion() = operationOutputGenerator.version

  @get:Input
  @get:Optional
  abstract val customScalarsMapping: MapProperty

  @get:Input
  @get:Optional
  abstract val useSemanticNaming: Property

  @get:Input
  @get:Optional
  abstract val generateKotlinModels: Property

  @get:Input
  @get:Optional
  abstract val languageVersion: Property

  @get:Input
  @get:Optional
  abstract val generateQueryDocument: Property

  @get:Input
  @get:Optional
  abstract val generateSchema: Property

  @get:Input
  @get:Optional
  abstract val generateResponseFields: Property

  @get:Internal
  abstract val warnOnDeprecatedUsages: Property

  @get:Internal
  abstract val failOnWarnings: Property

  @get:OutputDirectory
  abstract val outputDir: DirectoryProperty

  @get:OutputDirectory
  abstract val testDir: DirectoryProperty

  @get:OutputDirectory
  @get:Optional
  abstract val debugDir: DirectoryProperty

  @get:Input
  @get:Optional
  abstract val generateAsInternal: Property

  @get:Input
  @get:Optional
  abstract val generateFilterNotNull: Property

  @get:Input
  @get:Optional
  abstract val generateFragmentImplementations: Property

  @get:Input
  @get:Optional
  abstract val codegenModels: Property

  @get:Input
  @get:Optional
  abstract val flattenModels: Property

  @get:Input
  @get:Optional
  abstract val sealedClassesForEnumsMatching: ListProperty

  @get:Input
  @get:Optional
  abstract val generateOptionalOperationVariables: Property

  @get:Input
  @get:Optional
  abstract val generateTestBuilders: Property

  @get:Inject
  abstract val objectFactory: ObjectFactory

  @get:Input
  abstract val projectName: Property

  @TaskAction
  fun taskAction() {
    val metadata = metadataFiles.files.toList().map { ApolloMetadata.readFrom(it) }

    val commonMetadatas = metadata.mapNotNull { it.commonMetadata }

    check(commonMetadatas.size <= 1) {
      "Apollo: multiple schemas found in metadata"
    }

    val commonMetadata = commonMetadatas.singleOrNull()
    var outputCommonMetadata: CommonMetadata? = null

    val targetLanguage = if (generateKotlinModels.get()) {
      getKotlinTargetLanguage(project, languageVersion.orNull)
    } else {
      TargetLanguage.JAVA
    }
    val incomingOptions = if (commonMetadata != null) {
      check(schemaFiles.files.isEmpty()) {
        "Specifying 'schemaFiles' has no effect as an upstream module already provided a schema"
      }
      check(!codegenModels.isPresent) {
        "Specifying 'codegenModels' has no effect as an upstream module already provided a codegenModels"
      }
      IncomingOptions.fromMetadata(commonMetadata, packageNameGenerator)
    } else {
      val codegenModels = codegenModels.getOrElse(defaultCodegenModels)
      val (schema, mainSchemaFilePath) = resolveSchema(schemaFiles.files, rootFolders.get())

      outputCommonMetadata = CommonMetadata(
          schema = schema,
          codegenModels = codegenModels,
          schemaPath = mainSchemaFilePath,
          pluginVersion = APOLLO_VERSION
      )

      IncomingOptions(
          schema = schema,
          schemaPackageName = packageNameGenerator.packageName(mainSchemaFilePath),
          codegenModels = codegenModels,
      )
    }

    val logger = object : ApolloCompiler.Logger {
      override fun warning(message: String) {
        logger.lifecycle(message)
      }
    }

    val flattenModels = when {
      targetLanguage == TargetLanguage.JAVA -> {
        check(flattenModels.isPresent.not()) {
          "Java codegen does not support flattenModels"
        }
        true
      }
      else -> flattenModels.getOrElse(incomingOptions.codegenModels != MODELS_RESPONSE_BASED)
    }
    val codegenModels = when {
      targetLanguage == TargetLanguage.JAVA -> {
        check(incomingOptions.codegenModels == MODELS_OPERATION_BASED) {
          "Java codegen does not support codegenModels=${incomingOptions.codegenModels}"
        }
        MODELS_OPERATION_BASED
      }
      else -> incomingOptions.codegenModels
    }

    val options = Options(
        executableFiles = graphqlFiles.files,
        outputDir = outputDir.asFile.get(),
        testDir = testDir.asFile.get(),
        debugDir = debugDir.asFile.orNull,
        alwaysGenerateTypesMatching = alwaysGenerateTypesMatching.getOrElse(defaultAlwaysGenerateTypesMatching),
        operationOutputFile = operationOutputFile.asFile.orNull,
        operationOutputGenerator = operationOutputGenerator,
        useSemanticNaming = useSemanticNaming.getOrElse(defaultUseSemanticNaming),
        warnOnDeprecatedUsages = warnOnDeprecatedUsages.getOrElse(defaultWarnOnDeprecatedUsages),
        failOnWarnings = failOnWarnings.getOrElse(defaultFailOnWarnings),
        packageNameGenerator = packageNameGenerator,
        generateAsInternal = generateAsInternal.getOrElse(defaultGenerateAsInternal),
        generateFilterNotNull = generateFilterNotNull.getOrElse(defaultGenerateFilterNotNull),
        generateFragmentImplementations = generateFragmentImplementations.getOrElse(defaultGenerateFragmentImplementations),
        generateQueryDocument = generateQueryDocument.getOrElse(defaultGenerateQueryDocument),
        generateSchema = generateSchema.getOrElse(defaultGenerateSchema),
        generateResponseFields = generateResponseFields.getOrElse(defaultGenerateResponseFields),
        logger = logger,
        moduleName = projectName.get(),
        // Response-based models generate a lot of models and therefore a lot of name clashes if flattened
        flattenModels = flattenModels,
        incomingCompilerMetadata = metadata.map { it.compilerMetadata },
        schema = incomingOptions.schema,
        codegenModels = codegenModels,
        schemaPackageName = incomingOptions.schemaPackageName,
        customScalarsMapping = customScalarsMapping.getOrElse(emptyMap()),
        targetLanguage = targetLanguage,
        generateTestBuilders = generateTestBuilders.getOrElse(defaultGenerateTestBuilders),
        sealedClassesForEnumsMatching = sealedClassesForEnumsMatching.getOrElse(defaultSealedClassesForEnumsMatching),
        generateOptionalOperationVariables = generateOptionalOperationVariables.getOrElse(defaultGenerateOptionalOperationVariables)
    )

    val outputCompilerMetadata = ApolloCompiler.write(options)

    val metadataOutputFile = metadataOutputFile.asFile.orNull
    if (metadataOutputFile != null) {
      ApolloMetadata(
          commonMetadata = outputCommonMetadata,
          compilerMetadata = outputCompilerMetadata,
          moduleName = project.name
      ).writeTo(metadataOutputFile)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy