fun generateResources()

in generator/src/main/kotlin/space/jetbrains/api/generator/GenerateResources.kt [13:122]


fun generateResources(model: HttpApiEntitiesById): List<FileSpec> {
    return model.resources.values.groupBy { displayPath(it, model) }.map { (displayPath, resourceGroup) ->
        val className = ClassName(
            resourcePackage(displayPath.dropLast(1)),
            resourceGroup.first().displayPlural.displayNameToClassName()
        )
        FileSpec.builder(className.packageName, className.simpleName).also { fileBuilder ->
            fileBuilder.indent(INDENT)

            fileBuilder.addAnnotation(
                AnnotationSpec.builder(Suppress::class)
                    .addMember("%S", "UNUSED_VARIABLE")
                    .build()
            )

            fileBuilder.addAnnotation(
                AnnotationSpec.builder(ClassName("kotlin", "OptIn")).also { ann ->
                    model.featureFlags.values.forEach {
                        ann.addMember("%T::class", it.annotationClassName())
                    }
                }.build()
            )

            if (displayPath.size == 1) { // top-level resource
                fileBuilder.addProperty(
                    PropertySpec.builder(resourceGroup.first().displayPlural.displayNameToMemberName(), className)
                        .receiver(clientType)
                        .getter(FunSpec.getterBuilder().addStatement("return %T(this)", className).build())
                        .build()
                )
            }

            fileBuilder.addType(TypeSpec.classBuilder(className).also { typeBuilder ->
                typeBuilder.primaryConstructor(FunSpec.constructorBuilder().addParameter("client", clientType).build())
                typeBuilder.superclass(restResourceType)
                typeBuilder.addSuperclassConstructorParameter("client")

                typeBuilder.addProperties(
                    resourceGroup.asSequence()
                        .flatMap { it.nestedResources.asSequence() }
                        .groupBy { displayPath(it, model) }
                        .values
                        .map { nestedGroup ->
                            val nestedName = nestedGroup.first().displayPlural
                            val nestedType = ClassName(resourcePackage(displayPath), nestedName.displayNameToClassName())
                            PropertySpec
                                .builder(nestedName.displayNameToMemberName(), nestedType)
                                .initializer("%T(client)", nestedType)
                                .build()
                        }
                )

                typeBuilder.addFunctions(resourceGroup.flatMap { it.endpoints }.map { endpoint ->
                    val urlParams = endpoint.parameters.sortedBy { !it.path }.map { it.field }
                    val queryParams = endpoint.parameters.filter { !it.path }.map { it.field }
                    val bodyParams = (endpoint.requestBody as? HA_Type.Object)?.fields
                    val returnType = endpoint.responseBody?.kotlinPoet(model)
                    val (partial, batch) = endpoint.responseBody.partial()
                    val partialInterface = partial?.partialToPartialInterface(model)
                    val hasUrlBatchInfo = queryParams.any {
                        it.name == META_PARAMETERS_PREFIX + "skip" || it.name == META_PARAMETERS_PREFIX + "top"
                    }

                    val funcParams = getFuncParams(model, urlParams, bodyParams, hasUrlBatchInfo, partialInterface).let {
                        if (endpoint.requestBody is HA_RawRequestPayload)
                            it + (ParameterSpec.builder("payload", outgoingContentType).build() to "Request payload")
                        else
                            it
                    }

                    val fullPath = endpoint.path.segments.asReversed().plus(
                        ancestors(model.resources.getValue(endpoint.resource.id), model)
                            .flatMap { it.path.segments.asReversed().asSequence() }
                    ).asReversed()

                    FunSpec.builder(endpoint.functionName).also { funcBuilder ->
                        val kDoc = buildString {
                            buildKDoc(endpoint.description)?.let {
                                append(it)
                            }
                            funcParams.mapNotNull { it.second }.joinToString("").takeUnless { it.isBlank() }?.let {
                                append(it)
                            }
                        }

                        kDoc.takeUnless { it.isBlank() }?.let { funcBuilder.addKdoc(it) }
                        funcBuilder.annotations.deprecation(endpoint.deprecation)
                        funcBuilder.annotations.featureFlag(endpoint.featureFlag, model)
                        funcBuilder.addModifiers(KModifier.PUBLIC, KModifier.SUSPEND)
                        funcBuilder.addParameters(funcParams.map { it.first })
                        if (returnType != null) funcBuilder.returns(returnType)

                        funcBuilder.addCode(
                            buildFnBody(
                                partialInterface,
                                batch,
                                endpoint,
                                fullPath,
                                queryParams,
                                hasUrlBatchInfo,
                                model,
                                partial
                            ).build()
                        )
                    }.build()
                })
            }.build())
        }.build()
    }
}