From 0de376847f39f84a0fb094c9049e4128e60e408c Mon Sep 17 00:00:00 2001 From: Anna Shipil Date: Mon, 3 Aug 2026 12:15:38 +0200 Subject: [PATCH 1/4] DEVX-846: adding annotations --- .../languages/oas/model/OasResourceRenderer.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 e6a347b6..566d0fb9 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" @@ -52,7 +53,8 @@ class OasResourceRenderer constructor(val api: Api, val vrapTypeProvider: VrapTy | parameters: | <<${method.queryParameters.joinToString("\n") { renderQueryParameter(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 (method.annotations.isNotEmpty()) """ + | <<${method.annotations.joinToString("\n") { it.renderAnnotation() }} >>""" else ""} | responses: | <<${method.responses.joinToString("\n") { renderResponse(it, method) }}>> """.trimMargin().keepAngleIndent() @@ -160,7 +162,8 @@ class OasResourceRenderer constructor(val api: Api, val vrapTypeProvider: VrapTy 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 (uriParameter.annotations.isNotEmpty()) """ + | <<${uriParameter.annotations.joinToString("\n") { it.renderAnnotation() }} >>""" else ""} | <<${uriParameter.type.renderType()}>> | required: ${uriParameter.required} """.trimMargin().keepAngleIndent() @@ -169,7 +172,8 @@ class OasResourceRenderer constructor(val api: Api, val vrapTypeProvider: VrapTy private fun renderQueryParameter(queryParameter: QueryParameter): String { 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 (queryParameter.annotations.isNotEmpty()) """ + | <<${ queryParameter.annotations.joinToString("\n") { it.renderAnnotation() } } >>""" else ""} | in: query | required: ${queryParameter.required} | style: form From 8faf6453ba779e2f453488b86516ecc63107bd65 Mon Sep 17 00:00:00 2001 From: Anna Shipil Date: Mon, 3 Aug 2026 13:16:06 +0200 Subject: [PATCH 2/4] DEVX-846: adding tests --- .../kotlin/languages/oas/TestCodeGenerator.kt | 26 +++++++++++++++++++ .../beta-annotation-test-direct.raml | 21 +++++++++++++++ .../beta-annotation-test-method.raml | 21 +++++++++++++++ .../test/resources/beta-annotation-test.raml | 26 +++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 languages/oas/src/test/resources/beta-annotation-test-direct.raml create mode 100644 languages/oas/src/test/resources/beta-annotation-test-method.raml create mode 100644 languages/oas/src/test/resources/beta-annotation-test.raml diff --git a/languages/oas/src/test/kotlin/languages/oas/TestCodeGenerator.kt b/languages/oas/src/test/kotlin/languages/oas/TestCodeGenerator.kt index 96733f55..4c459f64 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 00000000..4d1b40c9 --- /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 00000000..c83aae23 --- /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 00000000..dbff7636 --- /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: From 6af6173c991e8f65f236fb65cb33f51d06186906 Mon Sep 17 00:00:00 2001 From: Anna Shipil Date: Mon, 3 Aug 2026 13:16:21 +0200 Subject: [PATCH 3/4] DEVX-846: updating annotations --- .../oas/model/OasResourceRenderer.kt | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) 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 566d0fb9..8d6fdf46 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 @@ -43,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: @@ -51,10 +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 ""}${if (method.annotations.isNotEmpty()) """ - | <<${method.annotations.joinToString("\n") { it.renderAnnotation() }} >>""" 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() @@ -159,21 +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 ""}${if (uriParameter.annotations.isNotEmpty()) """ - | <<${uriParameter.annotations.joinToString("\n") { it.renderAnnotation() }} >>""" 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 ""}${if (queryParameter.annotations.isNotEmpty()) """ - | <<${ queryParameter.annotations.joinToString("\n") { it.renderAnnotation() } } >>""" 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 From 8cfaedc9ac11940fcecffa0edbd8160b377f98e0 Mon Sep 17 00:00:00 2001 From: Anna Shipil Date: Mon, 3 Aug 2026 13:17:02 +0200 Subject: [PATCH 4/4] DEVX-846: adding test resources --- .../src/test/resources/beta-annotation.raml | 28 ++++++++++++++++ .../resources/fixtures/beta-annotation.yaml | 33 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 languages/oas/src/test/resources/beta-annotation.raml create mode 100644 languages/oas/src/test/resources/fixtures/beta-annotation.yaml 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 00000000..2e14763f --- /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 00000000..5397d45c --- /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: