diff --git a/languages/bruno/src/main/kotlin/io/vrap/codegen/languages/bruno/model/BrunoActionRenderer.kt b/languages/bruno/src/main/kotlin/io/vrap/codegen/languages/bruno/model/BrunoActionRenderer.kt new file mode 100644 index 00000000..1a451223 --- /dev/null +++ b/languages/bruno/src/main/kotlin/io/vrap/codegen/languages/bruno/model/BrunoActionRenderer.kt @@ -0,0 +1,166 @@ +package io.vrap.codegen.languages.bruno.model + +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.google.common.collect.Lists +import io.vrap.codegen.languages.extensions.* +import io.vrap.rmf.codegen.firstUpperCase +import io.vrap.rmf.codegen.io.TemplateFile +import io.vrap.rmf.codegen.rendering.FileProducer +import io.vrap.rmf.codegen.rendering.MethodRenderer +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.VrapObjectType +import io.vrap.rmf.codegen.types.VrapTypeProvider +import io.vrap.rmf.raml.model.modules.Api +import io.vrap.rmf.raml.model.resources.HttpMethod +import io.vrap.rmf.raml.model.resources.Method +import io.vrap.rmf.raml.model.resources.Resource +import io.vrap.rmf.raml.model.types.* +import io.vrap.rmf.raml.model.types.Annotation +import io.vrap.rmf.raml.model.util.StringCaseFormat +import org.eclipse.emf.ecore.EObject + +class BrunoActionRenderer constructor(val api: Api, override val vrapTypeProvider: VrapTypeProvider) : EObjectExtensions, FileProducer { + + val offset = 1 + allResourceMethods().count() + + fun allResourceMethods(): List = api.allContainedResources.flatMap { it.methods } + fun allResources(): List = api.allContainedResources + + override fun produceFiles(): List { + return updateActions(api) + } + + fun updateActions(api: Api): List { + val updatableResources = api.allContainedResources.filter { it.getAnnotation("updateable") != null } + + return updatableResources.flatMap { resourceUpdates(it) } + } + + fun resourceUpdates(resource: Resource): List { + val updateMethod = resource.getUpdateMethod() + return updateMethod?.getActions()?.filterNot { objType -> objType.deprecated() }?.mapIndexed { index, objectType -> renderAction(resource, updateMethod, objectType, index) } ?: return emptyList() + } + + private fun renderAction(resource: Resource, method: Method, type: ObjectType, index: Int): TemplateFile { + val content = """ + |meta { + | name: "${type.discriminatorValue.firstUpperCase()}${if (type.markDeprecated()) " (deprecated)" else ""}" + | type: http + | seq: ${index + offset} + |} + """.trimMargin() + + val relativePath = methodResourcePath(method) + "/Update actions/" + type.discriminatorValue.firstUpperCase() + ".bru" + + return TemplateFile( + relativePath = relativePath, + content = content + ) + } + + private fun ObjectType.markDeprecated() : Boolean { + val anno = this.getAnnotation("markDeprecated") + return (anno != null && (anno.value as BooleanInstance).value) + } + + private fun Resource.getUpdateMethod(): Method? { + val byIdResource = this.resources.find { resource -> resource.relativeUri.template == "/{ID}" } ?: return null + + return byIdResource.getMethod(HttpMethod.POST) + } + + private fun Method.getActions(): List { + val body = this.getBody("application/json") ?: return emptyList() + + val actions = (body.type as ObjectType).getProperty("actions") ?: return emptyList() + + val actionsType = actions.type as ArrayType + val updateActions = if (actionsType.items is UnionType) { + (actionsType.items as UnionType).oneOf[0].subTypes + } else { + actionsType.items.subTypes + } + val actionItems = updateActions.map { action -> action as ObjectType }.sortedBy { action -> action.discriminatorValue } + return actionItems + } + + + private fun methodResourcePath(method: Method): String { + var resourcePathes = resourcePathes(method.resource()) + + var directories = resourcePathes.map { it.displayName?.value ?: it.resourcePathName.firstUpperCase() } + return directories.joinToString("/") + } + + private fun resourcePathes(resource: Resource): List { + if (resource.parent is Resource) { + if (resource.resourcePathName == resource.parent.resourcePathName) { + return resourcePathes(resource.parent) + } + return resourcePathes(resource.parent).plus(resource) + } + return listOf(resource) + } + + + + fun Instance.toJson(): String { + var example = "" + val mapper = ObjectMapper() + + val module = SimpleModule() + module.addSerializer(ObjectInstance::class.java, ObjectInstanceSerializer()) + module.addSerializer(ArrayInstance::class.java, InstanceSerializer()) + module.addSerializer(IntegerInstance::class.java, InstanceSerializer()) + module.addSerializer(BooleanInstance::class.java, InstanceSerializer()) + module.addSerializer(StringInstance::class.java, InstanceSerializer()) + module.addSerializer(NumberInstance::class.java, InstanceSerializer()) + mapper.registerModule(module) + + if (this is StringInstance) { + example = this.value + } else if (this is ObjectInstance) { + try { + example = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this) + } catch (e: JsonProcessingException) { + } + + } + + return example + } + + fun Resource.testScript(param: String = ""): String { + return """ + |tests["Status code " + responseCode.code] = responseCode.code === 200 || responseCode.code === 201; + |var data = JSON.parse(responseBody); + |if(data.results && data.results[0] && data.results[0].id && data.results[0].version){ + | pm.environment.set("${this.resourcePathName.singularize()}-id", data.results[0].id); + | pm.environment.set("${this.resourcePathName.singularize()}-version", data.results[0].version); + |} + |if(data.results && data.results[0] && data.results[0].key){ + | pm.environment.set("${this.resourcePathName.singularize()}-key", data.results[0].key); + |} + |if(data.version){ + | pm.environment.set("${this.resourcePathName.singularize()}-version", data.version); + |} + |if(data.id){ + | pm.environment.set("${this.resourcePathName.singularize()}-id", data.id); + |} + |if(data.key){ + | pm.environment.set("${this.resourcePathName.singularize()}-key", data.key); + |} + |${if (param.isNotEmpty()) """ + |if(data.${param}){ + | pm.environment.set("${this.resourcePathName.singularize()}-${param}", data.${param}); + |} + """.trimMargin() else ""} + """.trimMargin().split("\n").map { it.escapeJson().escapeAll() }.joinToString("\",\n\"", "\"", "\"") + } +} + + diff --git a/languages/bruno/src/main/kotlin/io/vrap/codegen/languages/bruno/model/BrunoModelModule.kt b/languages/bruno/src/main/kotlin/io/vrap/codegen/languages/bruno/model/BrunoModelModule.kt index 19c50d61..29b781e6 100644 --- a/languages/bruno/src/main/kotlin/io/vrap/codegen/languages/bruno/model/BrunoModelModule.kt +++ b/languages/bruno/src/main/kotlin/io/vrap/codegen/languages/bruno/model/BrunoModelModule.kt @@ -12,7 +12,8 @@ object BrunoModelModule : Module { FileGenerator( setOf( BrunoModuleRenderer(generatorModule.provideRamlModel(), generatorModule.vrapTypeProvider()), - BrunoMethodRenderer(generatorModule.provideRamlModel(), generatorModule.vrapTypeProvider()) + BrunoMethodRenderer(generatorModule.provideRamlModel(), generatorModule.vrapTypeProvider()), + BrunoActionRenderer(generatorModule.provideRamlModel(), generatorModule.vrapTypeProvider()) ) ) )