diff --git a/languages/oas/src/main/kotlin/io/vrap/codegen/languages/oas/model/OasResourceRenderer.kt b/languages/oas/src/main/kotlin/io/vrap/codegen/languages/oas/model/OasResourceRenderer.kt index e6a347b61..8d6fdf464 100644 --- a/languages/oas/src/main/kotlin/io/vrap/codegen/languages/oas/model/OasResourceRenderer.kt +++ b/languages/oas/src/main/kotlin/io/vrap/codegen/languages/oas/model/OasResourceRenderer.kt @@ -30,7 +30,8 @@ class OasResourceRenderer constructor(val api: Api, val vrapTypeProvider: VrapTy | description: |- | <<${type.description.value.trim()}>>""" else ""}${if (type.fullUriParameters.size > 0) """ | parameters: - | <<${type.fullUriParameters.joinToString("\n") { it.renderUriParameter() }}>>""" else ""} + | <<${type.fullUriParameters.joinToString("\n") { it.renderUriParameter() }}>>""" else ""}${if (type.annotations.isNotEmpty()) """ + | <<${type.annotations.joinToString("\n") { it.renderAnnotation() }} >>""" else ""} | <<${type.methods.joinToString("\n") { renderMethod(it) }}>> """.trimMargin().keepAngleIndent() val relativePath = "resources/" + type.toResourceName()+ ".raml" @@ -42,6 +43,7 @@ class OasResourceRenderer constructor(val api: Api, val vrapTypeProvider: VrapTy private fun renderMethod(method: Method): String { val bodies = method.bodies.filter { it.type != null }.filterNot { it.type is FileType }.plus(method.bodies.firstOrNull { it.type is FileType }).filterNotNull() + val annotations = method.annotations.plus(method.`is`.flatMap { it.trait.annotations }).distinctBy { it.type.name } return """ |${method.methodName}:${if (method.securedBy.isNotEmpty()) """ | security: @@ -50,9 +52,10 @@ class OasResourceRenderer constructor(val api: Api, val vrapTypeProvider: VrapTy | description: |- | <<${method.description.value.trim()}>>""" else ""}${if (method.queryParameters.isNotEmpty()) """ | parameters: - | <<${method.queryParameters.joinToString("\n") { renderQueryParameter(it) }}>>""" else ""}${if (method.bodies.any { it.type != null }) """ + | <<${method.queryParameters.joinToString("\n") { renderQueryParameter(method,it) }}>>""" else ""}${if (method.bodies.any { it.type != null }) """ | requestBody: - | <<${bodies.joinToString("\n") { renderBody(it, method) } }>>""" else ""} + | <<${bodies.joinToString("\n") { renderBody(it, method) } }>>""" else ""}${if (annotations.isNotEmpty()) """ + | <<${annotations.joinToString("\n") { it.renderAnnotation() }} >>""" else ""} | responses: | <<${method.responses.joinToString("\n") { renderResponse(it, method) }}>> """.trimMargin().keepAngleIndent() @@ -157,19 +160,27 @@ class OasResourceRenderer constructor(val api: Api, val vrapTypeProvider: VrapTy } public fun renderUriParameter(uriParameter: UriParameter): String { + val annotations = uriParameter.annotations.plus(uriParameter.type.annotations).distinctBy { it.type.name } return """ |${uriParameter.name}:${if (uriParameter.type.enum.size > 0) """ | enum: - | <<${uriParameter.type.enum.joinToString("\n") { "- ${it.value}"}}>>""" else ""} + | <<${uriParameter.type.enum.joinToString("\n") { "- ${it.value}"}}>>""" else ""}${if (annotations.isNotEmpty()) """ + | <<${annotations.joinToString("\n") { it.renderAnnotation() }} >>""" else ""} | <<${uriParameter.type.renderType()}>> | required: ${uriParameter.required} """.trimMargin().keepAngleIndent() } - private fun renderQueryParameter(queryParameter: QueryParameter): String { + private fun renderQueryParameter(method: Method, queryParameter: QueryParameter): String { + val traitAnnotations = method.`is` + .flatMap { it.trait.queryParameters } + .filter { it.name == queryParameter.name } + .flatMap { it.annotations.plus(it.type.annotations) } + val annotations = queryParameter.annotations.plus(queryParameter.type.annotations).plus(traitAnnotations).distinctBy { it.type.name } return """ |- name: ${queryParameter.name}${if (queryParameter.type.default != null) """ - | x-annotation-default: ${queryParameter.type.default.toYaml()}""" else ""} + | x-annotation-default: ${queryParameter.type.default.toYaml()}""" else ""}${if (annotations.isNotEmpty()) """ + | <<${ annotations.joinToString("\n") { it.renderAnnotation() } } >>""" else ""} | in: query | required: ${queryParameter.required} | style: form diff --git a/languages/oas/src/test/kotlin/languages/oas/TestCodeGenerator.kt b/languages/oas/src/test/kotlin/languages/oas/TestCodeGenerator.kt index 96733f552..4c459f64a 100644 --- a/languages/oas/src/test/kotlin/languages/oas/TestCodeGenerator.kt +++ b/languages/oas/src/test/kotlin/languages/oas/TestCodeGenerator.kt @@ -75,4 +75,30 @@ class TestCodeGenerator { private fun cleanFolder(path: String) { Paths.get(path).toFile().deleteRecursively() } + + @Test + fun betaAnnotationRender() { + val generatorConfig = CodeGeneratorConfig( + basePackageName = "com/commercetools/importer", + outputFolder = Paths.get("build/gensrc") + ) + + val apiProvider = RamlApiProvider(Paths.get("src/test/resources/beta-annotation.raml")) + + val dataSink = MemoryDataSink() + val generatorModule = RamlGeneratorModule(apiProvider, generatorConfig, OasBaseTypes, dataSink = dataSink) + val generatorComponent = RamlGeneratorComponent(generatorModule, OasModelModule) + generatorComponent.generateFiles() + + Assertions.assertThat(dataSink.files).hasSize(1) + + Assertions.assertThat( + DiffUtils.diff( + "src/test/resources/fixtures/beta-annotation.yaml".readFileLines(), + dataSink.files.get("openapi.yaml")?.trim()?.lines(), + ).deltas).`as`("openapi.yaml").isEmpty() + + Assertions.assertThat(dataSink.files.get("openapi.yaml")?.trim()) + .isEqualTo("src/test/resources/fixtures/beta-annotation.yaml".readFile()) + } } diff --git a/languages/oas/src/test/resources/beta-annotation-test-direct.raml b/languages/oas/src/test/resources/beta-annotation-test-direct.raml new file mode 100644 index 000000000..4d1b40c9b --- /dev/null +++ b/languages/oas/src/test/resources/beta-annotation-test-direct.raml @@ -0,0 +1,21 @@ +#%RAML 1.0 +title: Beta Annotation Test API (direct, no trait) +baseUri: https://example.com/{version} +version: v1 +mediaType: application/json + +annotationTypes: + beta: + type: boolean + allowedTargets: [ TypeDeclaration ] + +/test: + get: + queryParameters: + priceRecurrencePolicy?: + type: string + (beta): true + description: | + `id` of an existing RecurrencePolicy used for Product price selection. + responses: + 200: diff --git a/languages/oas/src/test/resources/beta-annotation-test-method.raml b/languages/oas/src/test/resources/beta-annotation-test-method.raml new file mode 100644 index 000000000..c83aae23b --- /dev/null +++ b/languages/oas/src/test/resources/beta-annotation-test-method.raml @@ -0,0 +1,21 @@ +#%RAML 1.0 +title: Beta Method Annotation Test API +baseUri: https://example.com/{version} +version: v1 +mediaType: application/json + +annotationTypes: + beta: + type: boolean + allowedTargets: [ Method, Trait ] + +traits: + betaTrait: + (beta): true + description: a trait that marks any method using it as beta + +/test: + get: + is: [ betaTrait ] + responses: + 200: diff --git a/languages/oas/src/test/resources/beta-annotation-test.raml b/languages/oas/src/test/resources/beta-annotation-test.raml new file mode 100644 index 000000000..dbff76368 --- /dev/null +++ b/languages/oas/src/test/resources/beta-annotation-test.raml @@ -0,0 +1,26 @@ + +#%RAML 1.0 +title: Beta Annotation Test API +baseUri: https://example.com/{version} +version: v1 +mediaType: application/json + +annotationTypes: + beta: + type: boolean + allowedTargets: [ TypeDeclaration ] + +traits: + priceSelecting: + queryParameters: + priceRecurrencePolicy?: + type: string + (beta): true + description: | + `id` of an existing RecurrencePolicy used for Product price selection. + +/test: + get: + is: [ priceSelecting ] + responses: + 200: diff --git a/languages/oas/src/test/resources/beta-annotation.raml b/languages/oas/src/test/resources/beta-annotation.raml new file mode 100644 index 000000000..2e14763f8 --- /dev/null +++ b/languages/oas/src/test/resources/beta-annotation.raml @@ -0,0 +1,28 @@ +#%RAML 1.0 +title: Beta Annotation Regression Test API +baseUri: https://example.com/{version} +version: v1 +mediaType: application/json + +annotationTypes: + beta: + type: boolean + allowedTargets: [ Method, Trait, TypeDeclaration ] + +traits: + priceSelecting: + queryParameters: + priceRecurrencePolicy?: + type: string + (beta): true + description: | + `id` of an existing RecurrencePolicy used for Product price selection. + betaTrait: + (beta): true + description: a trait that marks any method using it as beta + +/test: + get: + is: [ priceSelecting, betaTrait ] + responses: + 200: diff --git a/languages/oas/src/test/resources/fixtures/beta-annotation.yaml b/languages/oas/src/test/resources/fixtures/beta-annotation.yaml new file mode 100644 index 000000000..5397d45c5 --- /dev/null +++ b/languages/oas/src/test/resources/fixtures/beta-annotation.yaml @@ -0,0 +1,33 @@ +openapi: "3.0.0" +info: + title: Beta Annotation Regression Test API + version: "v1" + +servers: + - url: https://example.com/{version} + +paths: + /test: + get: + operationId: TestGet + description: |- + a trait that marks any method using it as beta + parameters: + - name: priceRecurrencePolicy + x-beta: true + in: query + required: false + style: form + schema: + type: "string" + explode: true + x-beta: true + responses: + "200": + description: |- + 200 + content: {} + +components: + + schemas: