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

io.vrap.codegen.languages.csharp.model.CsharpModelInterfaceRenderer.kt Maven / Gradle / Ivy

Go to download

RAML API client code generators based on the REST Modeling Framework. https://github.com/vrapio/rest-modeling-framework

The newest version!
package io.vrap.codegen.languages.csharp.model

import com.google.common.collect.Lists
import io.vrap.codegen.languages.csharp.extensions.*
import io.vrap.codegen.languages.extensions.EObjectExtensions
import io.vrap.codegen.languages.extensions.hasSubtypes
import io.vrap.codegen.languages.extensions.isPatternProperty
import io.vrap.rmf.codegen.firstUpperCase
import io.vrap.rmf.codegen.di.BasePackageName
import io.vrap.rmf.codegen.io.TemplateFile
import io.vrap.rmf.codegen.rendering.ObjectTypeRenderer
import io.vrap.rmf.codegen.rendering.utils.escapeAll
import io.vrap.rmf.codegen.rendering.utils.keepAngleIndent
import io.vrap.rmf.codegen.rendering.utils.keepIndentation
import io.vrap.rmf.codegen.types.VrapArrayType
import io.vrap.rmf.codegen.types.VrapObjectType
import io.vrap.rmf.codegen.types.VrapTypeProvider
import io.vrap.rmf.raml.model.resources.Resource
import io.vrap.rmf.raml.model.types.*
import io.vrap.rmf.raml.model.types.Annotation
import java.util.*


class CsharpModelInterfaceRenderer constructor(override val vrapTypeProvider: VrapTypeProvider, @BasePackageName private val basePackagePrefix: String) : CsharpObjectTypeExtensions, EObjectExtensions, ObjectTypeRenderer {

    override fun render(type: ObjectType): TemplateFile {
        val vrapType = vrapTypeProvider.doSwitch(type) as VrapObjectType

        val extends = Lists.newArrayList(type.type?.toVrapType()?.simpleName())
            .plus(
                when (val ex = type.getAnnotation("csharp-extends") ) {
                    is Annotation -> {
                        (ex.value as StringInstance).value.escapeAll()
                    }
                    else -> null
                }
            ).filterNotNull()

        var content : String = """
            |${type.usings(vrapTypeProvider, true)}
            |// ReSharper disable CheckNamespace
            |namespace ${vrapType.csharpPackage()}
            |{
            |    <${type.DeserializationAttributes()}>
            |    public partial interface I${vrapType.simpleClassName}${if (extends.isNotEmpty()) { " : ${extends.joinToString(separator = ", ")}" } else ""}
            |    {
            |        <${type.toProperties()}>
            |
            |        <${type.subtypeFactories()}>
            |    }
            |}
            |
        """.trimMargin().keepIndentation().split("\n").joinToString(separator = "\n") { it.trimEnd() }


        if(type.isADictionaryType())
        {
            content = type.renderTypeAsADictionaryType().trimMargin().keepIndentation()
        }

        val relativePath = vrapType.csharpClassRelativePath(true).replace(basePackagePrefix.replace(".", "/"), "").trimStart('/')

        return TemplateFile(
                relativePath = relativePath,
                content = content
        )
    }

    private fun ObjectType.toProperties(indent: String = "") : String = this.properties
            .filterNot { it.deprecated() }
            .filterNot { property -> property.isPatternProperty() }
            .map { it.toCsharpProperty(this) }.joinToString(separator = "\n\n")

    private fun Property.toCsharpProperty(objectType: ObjectType, indent: String = ""): String {
        val propName = this.name.firstUpperCase()
        val typeName = this.type.toVrapType().simpleName()
        val overrideProp = this.shouldOverrideThisProperty(objectType)

        val nullableChar = if(!this.required && this.type.isNullableScalar() && !this.parentRequired(objectType)) "?" else ""
        val newKeyword = if(overrideProp) "new " else ""
        val deprecationAttr = if(this.deprecationAnnotation() == "") "" else this.deprecationAnnotation()+"\n";

        return """
            |${deprecationAttr}${newKeyword}${typeName}$nullableChar $propName { get; set; }${if (this.type.toVrapType() is VrapArrayType) """
            |
            |${deprecationAttr}${newKeyword}IEnumerable\<${(this.type.toVrapType() as VrapArrayType).itemType.simpleName()}\>$nullableChar ${propName}Enumerable { set =\> $propName = value$nullableChar.ToList(); }""" else ""}
            """.trimMargin()
    }

    //override if it's already exists in the parent type
    private fun Property.shouldOverrideThisProperty(objectType: ObjectType): Boolean  {
        val hasParent = objectType.type != null;
        if(hasParent)
        {
            val parent = objectType.type as ObjectType
            if(parent.allProperties.any { it.name.equals(this.name) })
                return true
        }
        return false
    }

    private fun Property.parentRequired(objectType: ObjectType): Boolean  {
        val hasParent = objectType.type != null;
        if(hasParent)
        {
            val parent = objectType.type as ObjectType
            return parent.allProperties.find { it.name.equals(this.name) }?.parentRequired(parent) ?: false
        }
        return this.required
    }

    fun ObjectType.renderTypeAsADictionaryType() : String {
        val vrapType = vrapTypeProvider.doSwitch(this) as VrapObjectType

        val property = this.properties[0]

        return  """
            |${this.usings(vrapTypeProvider, true, true)}
            |
            |namespace ${vrapType.csharpPackage()}
            |{
            |    <${this.DeserializationAttributes()}>
            |    public interface I${vrapType.simpleClassName} : IDictionary\
            |    {
            |    }
            |}
            |
        """
    }

    private fun ObjectType.subtypeFactories(): String {
        return if (this.hasSubtypes())
            """
            |<${this.subTypes.plus(this.subTypes.flatMap { it.subTypes }).distinctBy { it.name }
                .asSequence()
                .filterIsInstance()
                .filter { it.getAnnotation("deprecated") == null }
                .filter { it.discriminatorValue != null }
                .sortedBy { anyType -> anyType.discriminatorValue.lowercase(Locale.getDefault()) }
                .map { it.subtypeFactory(this) }
                .joinToString(separator = "\n")}>
            """.trimMargin()
        else ""
    }

    private fun ObjectType.subtypeFactory(parentType: ObjectType): String {
        val vrapType = vrapTypeProvider.doSwitch(this) as VrapObjectType
        val className = "${vrapType.`package`.toCsharpPackage()}.${this.objectClassName()}"
        var subTypeName = this.discriminatorValue.upperCamelCase()
        if (parentType.allProperties.any { it.name.lowercase() == subTypeName.lowercase() }) {
            subTypeName = "_$subTypeName"
        }
        return """
            |static $className $subTypeName(Action\<$className\> init = null) {
            |    var t = new $className();
            |    init?.Invoke(t);
            |    return t;
            |}
            """.trimMargin()
    }

    fun ObjectType.DeserializationAttributes(): String {
        val vrapType = vrapTypeProvider.doSwitch(this) as VrapObjectType

        return if (hasSubtypes())
            """
            |[TypeDiscriminator(nameof(${this.discriminator.firstUpperCase()}))]
            |[DefaultTypeDiscriminator(typeof(${vrapType.csharpPackage()}.${this.objectClassName()}))]
            |<${this.subTypes.plus(this.subTypes.flatMap { it.subTypes }).distinctBy { it.name }
                    .asSequence()
                    .filterIsInstance()
                    .filter { it.getAnnotation("deprecated") == null }
                    .filter { it.discriminatorValue != null }
                    .sortedBy { anyType -> anyType.discriminatorValue.lowercase(Locale.getDefault()) }
                    .map {
                        val vrapObjectType = vrapTypeProvider.doSwitch(it) as VrapObjectType
                        "[SubTypeDiscriminator(\"${it.discriminatorValue}\", typeof(${vrapObjectType.`package`.toCsharpPackage()}.${it.objectClassName()}))]"
                    }
                    .joinToString(separator = "\n")}>
            """.trimMargin()
        else
            """
            |[DeserializeAs(typeof(${vrapType.`package`.toCsharpPackage()}.${this.objectClassName()}))]
            """.trimMargin()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy