From 917354f45db724ab6eb64783a09ae9b8415bdc5d Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 1 Aug 2024 20:59:26 +0530 Subject: [PATCH 01/16] Enable ballerina type extension in CLI --- .../mapper/ServiceToOpenAPIMapper.java | 48 ++++++++++++++++++- .../mapper/diagnostic/DiagnosticMessages.java | 4 +- .../example/OpenAPIExampleMapperImpl.java | 2 +- .../mapper/model/OASGenerationMetaInfo.java | 13 +++++ .../extension/BallerinaExtensionLevel.java | 47 ++++++++++++++++++ .../type/extension/BallerinaPackage.java | 4 +- .../extension/BallerinaTypeExtensioner.java | 46 +++++++++++++++++- .../io/ballerina/openapi/cmd/BaseCmd.java | 3 +- .../openapi/cmd/OASContractGenerator.java | 7 ++- .../io/ballerina/openapi/cmd/OpenApiCmd.java | 20 +++++++- 10 files changed, 182 insertions(+), 12 deletions(-) create mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaExtensionLevel.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index be368b642..a53e81c79 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -17,7 +17,9 @@ */ package io.ballerina.openapi.service.mapper; +import io.ballerina.compiler.api.ModuleID; import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.compiler.api.symbols.ModuleSymbol; import io.ballerina.compiler.api.symbols.ServiceDeclarationSymbol; import io.ballerina.compiler.api.symbols.Symbol; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; @@ -38,6 +40,7 @@ import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OASGenerationMetaInfo; import io.ballerina.openapi.service.mapper.model.OASResult; +import io.ballerina.openapi.service.mapper.type.extension.BallerinaExtensionLevel; import io.ballerina.openapi.service.mapper.type.extension.BallerinaTypeExtensioner; import io.ballerina.projects.Module; import io.ballerina.projects.Project; @@ -80,6 +83,23 @@ public static List generateOAS3Definition(Project project, SyntaxTree SemanticModel semanticModel, String serviceName, Boolean needJson, Path inputPath) { + return generateOAS3Definition(project, syntaxTree, semanticModel, serviceName, needJson, inputPath, "0"); + } + + /** + * This method will generate openapi definition Map lists with ballerina code. + * + * @param syntaxTree - Syntax tree the related to ballerina service + * @param semanticModel - Semantic model related to ballerina module + * @param serviceName - Service name that need to generate the openAPI specification + * @param needJson - Flag for enabling the generated file format with json or YAML + * @param inputPath - Input file path for resolve the annotation details + * @return - {@link java.util.Map} with openAPI definitions for service nodes + */ + public static List generateOAS3Definition(Project project, SyntaxTree syntaxTree, + SemanticModel semanticModel, + String serviceName, Boolean needJson, + Path inputPath, String ballerinaExtensionLevel) { Map servicesToGenerate = new HashMap<>(); List availableService = new ArrayList<>(); List diagnostics = new ArrayList<>(); @@ -96,6 +116,15 @@ public static List generateOAS3Definition(Project project, SyntaxTree availableService.toString()); diagnostics.add(error); } + // Check ballerina extension level + BallerinaExtensionLevel extensionLevel = BallerinaExtensionLevel.DISABLED; + try { + extensionLevel = BallerinaExtensionLevel.fromValue(ballerinaExtensionLevel); + } catch (IllegalArgumentException e) { + ExceptionDiagnostic error = new ExceptionDiagnostic(DiagnosticMessages.OAS_CONVERTOR_136, + ballerinaExtensionLevel); + diagnostics.add(error); + } // Generating openapi specification for selected services for (Map.Entry serviceNode : servicesToGenerate.entrySet()) { String openApiName = getOpenApiFileName(syntaxTree.filePath(), serviceNode.getKey(), needJson); @@ -105,6 +134,7 @@ public static List generateOAS3Definition(Project project, SyntaxTree .setSemanticModel(semanticModel) .setOpenApiFileName(openApiName) .setBallerinaFilePath(inputPath) + .setBallerinaExtensionLevel(extensionLevel) .setProject(project); OASGenerationMetaInfo oasGenerationMetaInfo = builder.build(); OASResult oasDefinition = generateOAS(oasGenerationMetaInfo); @@ -220,7 +250,13 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) openapi.setComponents(null); } // Remove ballerina extensions - BallerinaTypeExtensioner.removeExtensions(openapi); + Optional serviceModuleId = getServiceModuleId(serviceDefinition, semanticModel); + if (serviceModuleId.isPresent()) { + BallerinaTypeExtensioner.removeExtensions(openapi, + oasGenerationMetaInfo.getBallerinaExtensionLevel(), serviceModuleId.get()); + } else { + BallerinaTypeExtensioner.removeExtensions(openapi); + } return new OASResult(openapi, diagnostics); } else { return new OASResult(openapi, oasResult.getDiagnostics()); @@ -230,6 +266,16 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) } } + private static Optional getServiceModuleId(ServiceDeclarationNode serviceDeclarationNode, + SemanticModel semanticModel) { + Optional symbol = semanticModel.symbol(serviceDeclarationNode); + if (symbol.isEmpty()) { + return Optional.empty(); + } + Optional module = symbol.get().getModule(); + return module.map(ModuleSymbol::id); + } + /** * Travers every syntax tree and collect all the listener nodes. * diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/diagnostic/DiagnosticMessages.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/diagnostic/DiagnosticMessages.java index c1e320a77..a18a51676 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/diagnostic/DiagnosticMessages.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/diagnostic/DiagnosticMessages.java @@ -103,7 +103,9 @@ public enum DiagnosticMessages { OAS_CONVERTOR_134("OAS_CONVERTOR_134", "Generated OpenAPI definition does not contain the `%s` for" + " `%s` parameter: `%s`, since the example value(s) has parser errors", DiagnosticSeverity.WARNING), OAS_CONVERTOR_135("OAS_CONVERTOR_135", "Example skipped for request parameter: `%s`, since the request payload " + - "type implies more than one content-type", DiagnosticSeverity.WARNING); + "type implies more than one content-type", DiagnosticSeverity.WARNING), + OAS_CONVERTOR_136("OAS_CONVERTOR_136", "Given ballerina extension level: %s is not supported. Set the " + + "ballerina extension level to DISABLED", DiagnosticSeverity.WARNING); private final String code; private final String description; private final DiagnosticSeverity severity; diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/example/OpenAPIExampleMapperImpl.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/example/OpenAPIExampleMapperImpl.java index 852b98493..a7ba1a228 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/example/OpenAPIExampleMapperImpl.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/example/OpenAPIExampleMapperImpl.java @@ -149,7 +149,7 @@ private Optional getTypeDefinitionNode(String name, Schema Optional ballerinaType; if (ballerinaExt.isPresent()) { BallerinaPackage ballerinaPkg = ballerinaExt.get(); - String typeName = ballerinaPkg.name().orElse(name); + String typeName = Objects.isNull(ballerinaPkg.name()) ? name : ballerinaPkg.name(); ballerinaType = semanticModel.types().getTypeByName(ballerinaPkg.orgName(), ballerinaPkg.moduleName(), ballerinaPkg.version(), typeName); } else { diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/OASGenerationMetaInfo.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/OASGenerationMetaInfo.java index 93e3d7629..58cc1e4ed 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/OASGenerationMetaInfo.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/OASGenerationMetaInfo.java @@ -19,6 +19,7 @@ import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; +import io.ballerina.openapi.service.mapper.type.extension.BallerinaExtensionLevel; import io.ballerina.projects.Project; import java.nio.file.Path; @@ -35,6 +36,7 @@ public class OASGenerationMetaInfo { private final SemanticModel semanticModel; private final ServiceDeclarationNode serviceDeclarationNode; private final Project project; + private final BallerinaExtensionLevel ballerinaExtensionLevel; public OASGenerationMetaInfo(OASGenerationMetaInfoBuilder builder) { this.openApiFileName = builder.openApiFileName; @@ -42,6 +44,7 @@ public OASGenerationMetaInfo(OASGenerationMetaInfoBuilder builder) { this.semanticModel = builder.semanticModel; this.serviceDeclarationNode = builder.serviceDeclarationNode; this.project = builder.project; + this.ballerinaExtensionLevel = builder.ballerinaExtensionLevel; } public String getOpenApiFileName() { @@ -64,6 +67,10 @@ public Project getProject() { return project; } + public BallerinaExtensionLevel getBallerinaExtensionLevel() { + return ballerinaExtensionLevel; + } + /** * This method is used to create a new {@link OASGenerationMetaInfoBuilder} instance. */ @@ -74,6 +81,7 @@ public static class OASGenerationMetaInfoBuilder { private SemanticModel semanticModel; private ServiceDeclarationNode serviceDeclarationNode; private Project project; + private BallerinaExtensionLevel ballerinaExtensionLevel = BallerinaExtensionLevel.DISABLED; public OASGenerationMetaInfoBuilder setBallerinaFilePath(Path ballerinaFilePath) { this.ballerinaFilePath = ballerinaFilePath; @@ -95,6 +103,11 @@ public OASGenerationMetaInfoBuilder setOpenApiFileName(String openApiFileName) { return this; } + public OASGenerationMetaInfoBuilder setBallerinaExtensionLevel(BallerinaExtensionLevel balExtLevel) { + this.ballerinaExtensionLevel = balExtLevel; + return this; + } + public void setProject(Project project) { this.project = project; } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaExtensionLevel.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaExtensionLevel.java new file mode 100644 index 000000000..462a6138a --- /dev/null +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaExtensionLevel.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package io.ballerina.openapi.service.mapper.type.extension; + +/** + * This {@link BallerinaExtensionLevel} represents the Ballerina extension levels. + */ +public enum BallerinaExtensionLevel { + DISABLED("0"), + EXTERNAL_PACKAGE_TYPES("1"), + SAME_PACKAGE_DIFFERENT_MODULE_TYPES("2"), + ALL_REFERENCED_TYPES("3"); + + private final String value; + + BallerinaExtensionLevel(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static BallerinaExtensionLevel fromValue(String value) { + for (BallerinaExtensionLevel level : BallerinaExtensionLevel.values()) { + if (level.getValue().equals(value)) { + return level; + } + } + throw new IllegalArgumentException("Unknown value: " + value); + } +} diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaPackage.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaPackage.java index 6edbfffce..484bcb9e3 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaPackage.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaPackage.java @@ -17,8 +17,6 @@ */ package io.ballerina.openapi.service.mapper.type.extension; -import java.util.Optional; - /** * This {@link BallerinaPackage} record represents the Ballerina package details. * @param orgName organization name @@ -30,5 +28,5 @@ * @since 2.1.0 */ public record BallerinaPackage(String orgName, String pkgName, String moduleName, String version, - String modulePrefix, Optional name) { + String modulePrefix, String name) { } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java index 07ad658d5..bc0ba72af 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java @@ -46,6 +46,17 @@ public static void addExtension(Schema schema, TypeSymbol typeSymbol) { } public static void removeExtensions(OpenAPI openAPI) { + removeExtensions(openAPI, BallerinaExtensionLevel.DISABLED, "", ""); + } + + public static void removeExtensions(OpenAPI openAPI, BallerinaExtensionLevel extensionLevel, ModuleID moduleID) { + String orgName = moduleID.orgName(); + String moduleName = moduleID.moduleName(); + removeExtensions(openAPI, extensionLevel, orgName, moduleName); + } + + private static void removeExtensions(OpenAPI openAPI, BallerinaExtensionLevel extensionLevel, + String orgName, String moduleName) { Components components = openAPI.getComponents(); if (Objects.isNull(components)) { return; @@ -59,11 +70,42 @@ public static void removeExtensions(OpenAPI openAPI) { schemas.forEach((key, schema) -> { Map extensions = schema.getExtensions(); if (Objects.nonNull(extensions)) { - extensions.remove(X_BALLERINA_TYPE); + removeBallerinaExtension(extensionLevel, extensions, orgName, moduleName); } }); } + private static void removeBallerinaExtension(BallerinaExtensionLevel extensionLevel, + Map extensions, String orgName, String moduleName) { + switch (extensionLevel) { + case DISABLED: + extensions.remove(X_BALLERINA_TYPE); + break; + case EXTERNAL_PACKAGE_TYPES: + if (fromSamePackage(extensions, orgName)) { + extensions.remove(X_BALLERINA_TYPE); + } + break; + case SAME_PACKAGE_DIFFERENT_MODULE_TYPES: + if (fromSameModule(extensions, orgName, moduleName)) { + extensions.remove(X_BALLERINA_TYPE); + } + break; + case ALL_REFERENCED_TYPES: + break; + } + } + + private static boolean fromSameModule(Map extensions, String orgName, String moduleName) { + return extensions.get(X_BALLERINA_TYPE) instanceof BallerinaPackage ballerinaPkg && + orgName.equals(ballerinaPkg.orgName()) && moduleName.equals(ballerinaPkg.moduleName()); + } + + private static boolean fromSamePackage(Map extensions, String orgName) { + return extensions.get(X_BALLERINA_TYPE) instanceof BallerinaPackage ballerinaPkg && + orgName.equals(ballerinaPkg.orgName()); + } + public static Optional getExtension(Schema schema) { Map extensions = schema.getExtensions(); if (Objects.isNull(extensions)) { @@ -84,6 +126,6 @@ static Optional getBallerinaPackage(TypeSymbol typeSymbol) { } ModuleID moduleID = module.get().id(); return Optional.of(new BallerinaPackage(moduleID.orgName(), moduleID.packageName(), moduleID.moduleName(), - moduleID.version(), moduleID.modulePrefix(), typeSymbol.getName())); + moduleID.version(), moduleID.modulePrefix(), typeSymbol.getName().orElse(null))); } } diff --git a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BaseCmd.java b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BaseCmd.java index 7385b68bd..825ca3bc9 100644 --- a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BaseCmd.java +++ b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BaseCmd.java @@ -54,8 +54,7 @@ public class BaseCmd { @CommandLine.Option(names = {"--status-code-binding"}, description = "Generate the client methods with " + "status code response binding") public boolean statusCodeBinding; - - + @CommandLine.Option(names = {"--mock"}, hidden = true, description = "Generate mock client with given response example") public boolean mock; diff --git a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java index ffd43ef52..f7fa3beb7 100644 --- a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java +++ b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java @@ -59,6 +59,7 @@ public class OASContractGenerator { private Project project; private List diagnostics = new ArrayList<>(); private PrintStream outStream = System.out; + private String ballerinaExtensionLevel = "0"; /** * Initialize constructor. @@ -67,6 +68,10 @@ public OASContractGenerator() { } + public void setBallerinaExtensionLevel(String ballerinaExtensionLevel) { + this.ballerinaExtensionLevel = ballerinaExtensionLevel; + } + public List getDiagnostics() { return diagnostics; } @@ -118,7 +123,7 @@ public void generateOAS3DefinitionsAllService(Path servicePath, Path outPath, St } semanticModel = compilation.getSemanticModel(docId.moduleId()); List openAPIDefinitions = ServiceToOpenAPIMapper.generateOAS3Definition(project, syntaxTree, - semanticModel, serviceName, needJson, inputPath); + semanticModel, serviceName, needJson, inputPath, ballerinaExtensionLevel); if (!openAPIDefinitions.isEmpty()) { List fileNames = new ArrayList<>(); diff --git a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java index 56422a31f..084cc4571 100644 --- a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java +++ b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java @@ -121,6 +121,9 @@ public class OpenApiCmd implements BLauncherCmd { description = "Generate service without data binding") private boolean generateWithoutDataBinding; + @CommandLine.Option(names = {"--bal-ext-level"}, hidden = true, description = "Generate ballerina type extensions") + private String ballerinaExtensionLevel; + @CommandLine.Parameters private List argList; @@ -211,7 +214,7 @@ public void execute() { if (baseCmd.statusCodeBinding) { if (baseCmd.mode != null && baseCmd.mode.equals(SERVICE)) { - outStream.println("ERROR: the '--status-code-binding' option is only available in client " + + outStream.println("the '--status-code-binding' option is only available in client " + "generation mode."); exitError(this.exitWhenFinish); } @@ -226,6 +229,12 @@ public void execute() { } } + if (ballerinaExtensionLevel != null) { + outStream.println("'--bal-ext-level' option is only available in OpenAPI specification " + + "generation mode."); + exitError(this.exitWhenFinish); + } + try { openApiToBallerina(fileName, filter); } catch (IOException e) { @@ -239,6 +248,14 @@ public void execute() { outStream.println("'--client-methods' option is only available in client generation mode."); exitError(this.exitWhenFinish); } + if (ballerinaExtensionLevel != null && !(ballerinaExtensionLevel.equals("0") || + ballerinaExtensionLevel.equals("1") || ballerinaExtensionLevel.equals("2") || + ballerinaExtensionLevel.equals("3"))) { + outStream.println("unsupported '--bal-ext-level' option value. Please use 0 - DISABLED, 1 - " + + "EXTERNAL_PACKAGE_TYPES, 2 - SAME_PACKAGE_DIFFERENT_MODULE_TYPES, 3 - ALL_REFERENCED_TYPES"); + exitError(this.exitWhenFinish); + + } ballerinaToOpenApi(fileName); } else { outStream.println(ErrorMessages.MISSING_CONTRACT_PATH); @@ -277,6 +294,7 @@ private void ballerinaToOpenApi(String fileName) { getTargetOutputPath(); // Check service name it is mandatory OASContractGenerator openApiConverter = new OASContractGenerator(); + openApiConverter.setBallerinaExtensionLevel(ballerinaExtensionLevel); openApiConverter.generateOAS3DefinitionsAllService(balFilePath, targetOutputPath, service, generatedFileType); mapperDiagnostics.addAll(openApiConverter.getDiagnostics()); From 839733a114c6e7c3d7c2c4381cdeea53efc40b1c Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 1 Aug 2024 20:59:36 +0530 Subject: [PATCH 02/16] Add test cases --- .../openapi/cmd/BallerinaToOpenAPITests.java | 44 +++++ .../project_openapi_bal_ext/Ballerina.toml | 4 + .../project_openapi_bal_ext/main.bal | 32 +++ .../modules/module/module.bal | 4 + .../project_openapi_bal_ext/result_0.yaml | 128 ++++++++++++ .../project_openapi_bal_ext/result_1.yaml | 163 ++++++++++++++++ .../project_openapi_bal_ext/result_2.yaml | 170 ++++++++++++++++ .../project_openapi_bal_ext/result_3.yaml | 184 ++++++++++++++++++ 8 files changed, 729 insertions(+) create mode 100644 openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/Ballerina.toml create mode 100644 openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/main.bal create mode 100644 openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/modules/module/module.bal create mode 100644 openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_0.yaml create mode 100644 openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml create mode 100644 openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml create mode 100644 openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml diff --git a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java index 4c0cde27a..cbe7c6309 100644 --- a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java +++ b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java @@ -166,6 +166,36 @@ public void openAPIExampleAnnotations() throws IOException, InterruptedException "project_openapi_examples/result.yaml"); } + @Test(description = "Generate without ballerina extension option") + public void openAPIGenWithoutBalExt() throws IOException, InterruptedException { + executeCommand("project_openapi_bal_ext/main.bal", "api_openapi_ext_default.yaml", + "project_openapi_bal_ext/result_0.yaml"); + } + + @Test(description = "Generate with ballerina extension option - 0 - DISABLED") + public void openAPIGenWithExtOpt0() throws IOException, InterruptedException { + executeCommand("project_openapi_bal_ext/main.bal", "api_openapi_ext_0.yaml", + "project_openapi_bal_ext/result_0.yaml", "0"); + } + + @Test(description = "Generate with ballerina extension option - 1 - EXTERNAL_PACKAGE_TYPES") + public void openAPIGenWithExtOpt1() throws IOException, InterruptedException { + executeCommand("project_openapi_bal_ext/main.bal", "api_openapi_ext_1.yaml", + "project_openapi_bal_ext/result_1.yaml", "1"); + } + + @Test(description = "Generate with ballerina extension option - 2 - SAME_PACKAGE_DIFFERENT_MODULE_TYPES") + public void openAPIGenWithExtOpt2() throws IOException, InterruptedException { + executeCommand("project_openapi_bal_ext/main.bal", "api_openapi_ext_2.yaml", + "project_openapi_bal_ext/result_2.yaml", "2"); + } + + @Test(description = "Generate with ballerina extension option - 3 - ALL_REFERENCED_TYPES") + public void openAPIGenWithExtOpt3() throws IOException, InterruptedException { + executeCommand("project_openapi_bal_ext/main.bal", "api_openapi_ext_3.yaml", + "project_openapi_bal_ext/result_3.yaml", "3"); + } + @AfterClass public void cleanUp() throws IOException { TestUtil.cleanDistribution(); @@ -190,6 +220,20 @@ private void executeCommand(String resourcePath, String generatedFile, String ex Assert.assertEquals(expectedYaml, generatedOpenAPI); } + private void executeCommand(String resourcePath, String generatedFile, String expectedPath, String extensionLevel) + throws IOException, InterruptedException { + List buildArgs = new LinkedList<>(); + buildArgs.add("-i"); + buildArgs.add(resourcePath); + buildArgs.add("--bal-ext-level"); + buildArgs.add(extensionLevel); + boolean successful = TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs); + Assert.assertTrue(Files.exists(TEST_RESOURCE.resolve(generatedFile))); + String generatedOpenAPI = getStringFromGivenBalFile(TEST_RESOURCE.resolve(generatedFile)); + String expectedYaml = getStringFromGivenBalFile(TEST_RESOURCE.resolve(expectedPath)); + Assert.assertEquals(expectedYaml, generatedOpenAPI); + } + public Process getProcessForOpenAPISpecGeneration(String ballerinaFilePath) throws IOException { List buildArgs = new LinkedList<>(); buildArgs.add(0, "openapi"); diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/Ballerina.toml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/Ballerina.toml new file mode 100644 index 000000000..8d198de49 --- /dev/null +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/Ballerina.toml @@ -0,0 +1,4 @@ +[package] +org = "ballerina" +name = "openapi_bal_ext" +version = "0.1.0" diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/main.bal b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/main.bal new file mode 100644 index 000000000..fcb99a12a --- /dev/null +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/main.bal @@ -0,0 +1,32 @@ +import bal_ext.module as mod; + +import ballerina/http; +import ballerina/time; + +type Subject record {| + string name; + int credits; + time:Date examDate; +|}; + +public type Student record {| + *mod:BasicStudent; + Subject[] subjects; +|}; + +service /api/v1 on new http:Listener(9090) { + + resource function get students() returns Student[] { + return [ + { + name: "John", + age: 25, + subjects: [ + {name: "Math", credits: 4, examDate: {day: 10, month: 10, year: 2023}}, + {name: "Science", credits: 3, examDate: {day: 15, month: 10, year: 2023}} + ] + } + ]; + } +} + diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/modules/module/module.bal b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/modules/module/module.bal new file mode 100644 index 000000000..a3aa66ead --- /dev/null +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/modules/module/module.bal @@ -0,0 +1,4 @@ +public type BasicStudent record {| + string name; + int age; +|}; diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_0.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_0.yaml new file mode 100644 index 000000000..b9c068560 --- /dev/null +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_0.yaml @@ -0,0 +1,128 @@ +openapi: 3.0.1 +info: + title: Api V1 + version: 0.1.0 +servers: +- url: "{server}:{port}/api/v1" + variables: + server: + default: http://localhost + port: + default: "9090" +paths: + /students: + get: + operationId: getStudents + responses: + "200": + description: Ok + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Student' +components: + schemas: + BasicStudent: + required: + - age + - name + type: object + properties: + name: + type: string + age: + type: integer + format: int64 + additionalProperties: false + Date: + type: object + description: Date in proleptic Gregorian calendar. + allOf: + - $ref: '#/components/schemas/DateFields' + - $ref: '#/components/schemas/OptionalTimeOfDayFields' + - type: object + properties: + utcOffset: + $ref: '#/components/schemas/ZoneOffset' + DateFields: + required: + - day + - month + - year + type: object + properties: + year: + type: integer + format: int64 + month: + type: integer + format: int64 + day: + type: integer + format: int64 + description: Fields of the Date record. + OptionalTimeOfDayFields: + type: object + properties: + hour: + type: integer + format: int64 + minute: + type: integer + format: int64 + second: + $ref: '#/components/schemas/Seconds' + description: TimeOfDay with all the fields beign optional. + Seconds: + type: number + description: Holds the seconds as a decimal value. + format: double + Student: + type: object + allOf: + - $ref: '#/components/schemas/BasicStudent' + - required: + - subjects + type: object + properties: + subjects: + type: array + items: + $ref: '#/components/schemas/Subject' + additionalProperties: false + Subject: + required: + - credits + - examDate + - name + type: object + properties: + name: + type: string + credits: + type: integer + format: int64 + examDate: + $ref: '#/components/schemas/Date' + additionalProperties: false + ZoneOffset: + required: + - hours + type: object + properties: + hours: + type: integer + format: int64 + minutes: + type: integer + format: int64 + seconds: + type: number + description: |- + IETF zone files have historical zones that are offset by + integer seconds; we use Seconds type so that this is a subtype + of Delta + format: double + additionalProperties: false diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml new file mode 100644 index 000000000..6805d4926 --- /dev/null +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml @@ -0,0 +1,163 @@ +openapi: 3.0.1 +info: + title: Api V1 + version: 0.1.0 +servers: +- url: "{server}:{port}/api/v1" + variables: + server: + default: http://localhost + port: + default: "9090" +paths: + /students: + get: + operationId: getStudents + responses: + "200": + description: Ok + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Student' +components: + schemas: + BasicStudent: + required: + - age + - name + type: object + properties: + name: + type: string + age: + type: integer + format: int64 + additionalProperties: false + Date: + type: object + description: Date in proleptic Gregorian calendar. + allOf: + - $ref: '#/components/schemas/DateFields' + - $ref: '#/components/schemas/OptionalTimeOfDayFields' + - type: object + properties: + utcOffset: + $ref: '#/components/schemas/ZoneOffset' + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: Date + DateFields: + required: + - day + - month + - year + type: object + properties: + year: + type: integer + format: int64 + month: + type: integer + format: int64 + day: + type: integer + format: int64 + description: Fields of the Date record. + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: DateFields + OptionalTimeOfDayFields: + type: object + properties: + hour: + type: integer + format: int64 + minute: + type: integer + format: int64 + second: + $ref: '#/components/schemas/Seconds' + description: TimeOfDay with all the fields beign optional. + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: OptionalTimeOfDayFields + Seconds: + type: number + description: Holds the seconds as a decimal value. + format: double + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: Seconds + Student: + type: object + allOf: + - $ref: '#/components/schemas/BasicStudent' + - required: + - subjects + type: object + properties: + subjects: + type: array + items: + $ref: '#/components/schemas/Subject' + additionalProperties: false + Subject: + required: + - credits + - examDate + - name + type: object + properties: + name: + type: string + credits: + type: integer + format: int64 + examDate: + $ref: '#/components/schemas/Date' + additionalProperties: false + ZoneOffset: + required: + - hours + type: object + properties: + hours: + type: integer + format: int64 + minutes: + type: integer + format: int64 + seconds: + type: number + description: |- + IETF zone files have historical zones that are offset by + integer seconds; we use Seconds type so that this is a subtype + of Delta + format: double + additionalProperties: false + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: ZoneOffset diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml new file mode 100644 index 000000000..bc0ec0d96 --- /dev/null +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml @@ -0,0 +1,170 @@ +openapi: 3.0.1 +info: + title: Api V1 + version: 0.1.0 +servers: +- url: "{server}:{port}/api/v1" + variables: + server: + default: http://localhost + port: + default: "9090" +paths: + /students: + get: + operationId: getStudents + responses: + "200": + description: Ok + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Student' +components: + schemas: + BasicStudent: + required: + - age + - name + type: object + properties: + name: + type: string + age: + type: integer + format: int64 + additionalProperties: false + x-ballerina-type: + orgName: tharmigan + pkgName: bal_ext + moduleName: bal_ext.module + version: 0.1.0 + modulePrefix: module + name: BasicStudent + Date: + type: object + description: Date in proleptic Gregorian calendar. + allOf: + - $ref: '#/components/schemas/DateFields' + - $ref: '#/components/schemas/OptionalTimeOfDayFields' + - type: object + properties: + utcOffset: + $ref: '#/components/schemas/ZoneOffset' + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: Date + DateFields: + required: + - day + - month + - year + type: object + properties: + year: + type: integer + format: int64 + month: + type: integer + format: int64 + day: + type: integer + format: int64 + description: Fields of the Date record. + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: DateFields + OptionalTimeOfDayFields: + type: object + properties: + hour: + type: integer + format: int64 + minute: + type: integer + format: int64 + second: + $ref: '#/components/schemas/Seconds' + description: TimeOfDay with all the fields beign optional. + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: OptionalTimeOfDayFields + Seconds: + type: number + description: Holds the seconds as a decimal value. + format: double + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: Seconds + Student: + type: object + allOf: + - $ref: '#/components/schemas/BasicStudent' + - required: + - subjects + type: object + properties: + subjects: + type: array + items: + $ref: '#/components/schemas/Subject' + additionalProperties: false + Subject: + required: + - credits + - examDate + - name + type: object + properties: + name: + type: string + credits: + type: integer + format: int64 + examDate: + $ref: '#/components/schemas/Date' + additionalProperties: false + ZoneOffset: + required: + - hours + type: object + properties: + hours: + type: integer + format: int64 + minutes: + type: integer + format: int64 + seconds: + type: number + description: |- + IETF zone files have historical zones that are offset by + integer seconds; we use Seconds type so that this is a subtype + of Delta + format: double + additionalProperties: false + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: ZoneOffset diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml new file mode 100644 index 000000000..8c6714baf --- /dev/null +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml @@ -0,0 +1,184 @@ +openapi: 3.0.1 +info: + title: Api V1 + version: 0.1.0 +servers: +- url: "{server}:{port}/api/v1" + variables: + server: + default: http://localhost + port: + default: "9090" +paths: + /students: + get: + operationId: getStudents + responses: + "200": + description: Ok + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Student' +components: + schemas: + BasicStudent: + required: + - age + - name + type: object + properties: + name: + type: string + age: + type: integer + format: int64 + additionalProperties: false + x-ballerina-type: + orgName: tharmigan + pkgName: bal_ext + moduleName: bal_ext.module + version: 0.1.0 + modulePrefix: module + name: BasicStudent + Date: + type: object + description: Date in proleptic Gregorian calendar. + allOf: + - $ref: '#/components/schemas/DateFields' + - $ref: '#/components/schemas/OptionalTimeOfDayFields' + - type: object + properties: + utcOffset: + $ref: '#/components/schemas/ZoneOffset' + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: Date + DateFields: + required: + - day + - month + - year + type: object + properties: + year: + type: integer + format: int64 + month: + type: integer + format: int64 + day: + type: integer + format: int64 + description: Fields of the Date record. + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: DateFields + OptionalTimeOfDayFields: + type: object + properties: + hour: + type: integer + format: int64 + minute: + type: integer + format: int64 + second: + $ref: '#/components/schemas/Seconds' + description: TimeOfDay with all the fields beign optional. + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: OptionalTimeOfDayFields + Seconds: + type: number + description: Holds the seconds as a decimal value. + format: double + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: Seconds + Student: + type: object + allOf: + - $ref: '#/components/schemas/BasicStudent' + - required: + - subjects + type: object + properties: + subjects: + type: array + items: + $ref: '#/components/schemas/Subject' + additionalProperties: false + x-ballerina-type: + orgName: tharmigan + pkgName: bal_ext + moduleName: bal_ext + version: 0.1.0 + modulePrefix: bal_ext + name: Student + Subject: + required: + - credits + - examDate + - name + type: object + properties: + name: + type: string + credits: + type: integer + format: int64 + examDate: + $ref: '#/components/schemas/Date' + additionalProperties: false + x-ballerina-type: + orgName: tharmigan + pkgName: bal_ext + moduleName: bal_ext + version: 0.1.0 + modulePrefix: bal_ext + name: Subject + ZoneOffset: + required: + - hours + type: object + properties: + hours: + type: integer + format: int64 + minutes: + type: integer + format: int64 + seconds: + type: number + description: |- + IETF zone files have historical zones that are offset by + integer seconds; we use Seconds type so that this is a subtype + of Delta + format: double + additionalProperties: false + x-ballerina-type: + orgName: ballerina + pkgName: time + moduleName: time + version: 2.4.0 + modulePrefix: time + name: ZoneOffset From 9b72c2971eaeafbc47f06d2aae9a50e86d256bea Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 1 Aug 2024 21:07:55 +0530 Subject: [PATCH 03/16] Add assertion for successful execution --- .../openapi/cmd/BallerinaToOpenAPITests.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java index cbe7c6309..f946f16df 100644 --- a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java +++ b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java @@ -44,7 +44,7 @@ */ public class BallerinaToOpenAPITests extends OpenAPITest { public static final String DISTRIBUTION_FILE_NAME = DISTRIBUTIONS_DIR.toString(); - public static final Path TEST_RESOURCE = Paths.get(RESOURCES_PATH.toString() + "/ballerina_sources"); + public static final Path TEST_RESOURCE = Paths.get(RESOURCES_PATH + "/ballerina_sources"); @BeforeClass public void setupDistributions() throws IOException { @@ -92,7 +92,7 @@ public void multipleService() throws IOException, InterruptedException { List buildArgs = new LinkedList<>(); buildArgs.add("-i"); buildArgs.add("project_7/service.bal"); - boolean successful = TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs); + Assert.assertTrue(TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs)); Assert.assertTrue(Files.exists(TEST_RESOURCE.resolve("mTitle_openapi.yaml"))); } @@ -101,7 +101,7 @@ public void multipleServiceWithAnnotation() throws IOException, InterruptedExcep List buildArgs = new LinkedList<>(); buildArgs.add("-i"); buildArgs.add("project_8/service.bal"); - boolean successful = TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs); + Assert.assertTrue(TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs)); Assert.assertTrue(Files.exists(TEST_RESOURCE.resolve("mTitle01_openapi.yaml"))); Assert.assertTrue(Files.exists(TEST_RESOURCE.resolve("mVersion_openapi.yaml"))); } @@ -123,7 +123,7 @@ public void nonHttpService() throws IOException, InterruptedException { List buildArgs = new LinkedList<>(); buildArgs.add("-i"); buildArgs.add("project_11/service.bal"); - boolean successful = TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs); + Assert.assertTrue(TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs)); Assert.assertFalse(Files.exists(TEST_RESOURCE.resolve("query_openapi.yaml"))); } @@ -154,7 +154,7 @@ public void exampleMapping() throws IOException, InterruptedException { } //TODO enable after resolving dependency issue - @Test(description = "Service is with openapi annotation include all oas infor section details", enabled = false) + @Test(description = "Service is with openapi annotation include all oas info section details", enabled = false) public void openAPInForSectionTest() throws IOException, InterruptedException { executeCommand("project_openapi_info/service_file.bal", "info_openapi.yaml", "project_openapi_info/result.yaml"); @@ -213,7 +213,7 @@ private void executeCommand(String resourcePath, String generatedFile, String ex List buildArgs = new LinkedList<>(); buildArgs.add("-i"); buildArgs.add(resourcePath); - boolean successful = TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs); + Assert.assertTrue(TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs)); Assert.assertTrue(Files.exists(TEST_RESOURCE.resolve(generatedFile))); String generatedOpenAPI = getStringFromGivenBalFile(TEST_RESOURCE.resolve(generatedFile)); String expectedYaml = getStringFromGivenBalFile(TEST_RESOURCE.resolve(expectedPath)); @@ -227,7 +227,7 @@ private void executeCommand(String resourcePath, String generatedFile, String ex buildArgs.add(resourcePath); buildArgs.add("--bal-ext-level"); buildArgs.add(extensionLevel); - boolean successful = TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs); + Assert.assertTrue(TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs)); Assert.assertTrue(Files.exists(TEST_RESOURCE.resolve(generatedFile))); String generatedOpenAPI = getStringFromGivenBalFile(TEST_RESOURCE.resolve(generatedFile)); String expectedYaml = getStringFromGivenBalFile(TEST_RESOURCE.resolve(expectedPath)); From 904c8836b2b9c7d6c850c9e604a9863a384c1f24 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 1 Aug 2024 21:22:24 +0530 Subject: [PATCH 04/16] [Automated] Update the toml files for client native tests --- openapi-client-native/ballerina-tests/Dependencies.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openapi-client-native/ballerina-tests/Dependencies.toml b/openapi-client-native/ballerina-tests/Dependencies.toml index e9cd5368b..11f5ac352 100644 --- a/openapi-client-native/ballerina-tests/Dependencies.toml +++ b/openapi-client-native/ballerina-tests/Dependencies.toml @@ -5,12 +5,12 @@ [ballerina] dependencies-toml-version = "2" -distribution-version = "2201.9.0" +distribution-version = "2201.10.0-20240624-004800-68612b63" [[package]] org = "ballerina" name = "auth" -version = "2.11.0" +version = "2.11.1" dependencies = [ {org = "ballerina", name = "crypto"}, {org = "ballerina", name = "jballerina.java"}, @@ -75,7 +75,7 @@ dependencies = [ [[package]] org = "ballerina" name = "http" -version = "2.11.1" +version = "2.11.3" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -124,7 +124,7 @@ modules = [ [[package]] org = "ballerina" name = "jwt" -version = "2.11.0" +version = "2.12.1" dependencies = [ {org = "ballerina", name = "cache"}, {org = "ballerina", name = "crypto"}, From 63e2638d7279acc0883ede4cae2f5356900256ed Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 1 Aug 2024 21:25:53 +0530 Subject: [PATCH 05/16] Add a null check before assigning the level --- .../java/io/ballerina/openapi/cmd/OASContractGenerator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java index f7fa3beb7..33d14d1dc 100644 --- a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java +++ b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java @@ -43,6 +43,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Optional; import static io.ballerina.openapi.service.mapper.utils.CodegenUtils.resolveContractFileName; @@ -69,7 +70,9 @@ public OASContractGenerator() { } public void setBallerinaExtensionLevel(String ballerinaExtensionLevel) { - this.ballerinaExtensionLevel = ballerinaExtensionLevel; + if (Objects.nonNull(ballerinaExtensionLevel)) { + this.ballerinaExtensionLevel = ballerinaExtensionLevel; + } } public List getDiagnostics() { From cdd666650c9a292b415c230871dd2b1853fd2ff1 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 1 Aug 2024 21:28:38 +0530 Subject: [PATCH 06/16] Fix module import --- .../ballerina_sources/project_openapi_bal_ext/main.bal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/main.bal b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/main.bal index fcb99a12a..d8e584c4f 100644 --- a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/main.bal +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/main.bal @@ -1,4 +1,4 @@ -import bal_ext.module as mod; +import openapi_bal_ext.module as mod; import ballerina/http; import ballerina/time; From 322679ad375d1c740b00ba65cb552c5da0e09fc5 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 1 Aug 2024 21:36:40 +0530 Subject: [PATCH 07/16] Fix generated file name --- .../ballerina/openapi/cmd/BallerinaToOpenAPITests.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java index f946f16df..ec80330ea 100644 --- a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java +++ b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java @@ -168,31 +168,31 @@ public void openAPIExampleAnnotations() throws IOException, InterruptedException @Test(description = "Generate without ballerina extension option") public void openAPIGenWithoutBalExt() throws IOException, InterruptedException { - executeCommand("project_openapi_bal_ext/main.bal", "api_openapi_ext_default.yaml", + executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", "project_openapi_bal_ext/result_0.yaml"); } @Test(description = "Generate with ballerina extension option - 0 - DISABLED") public void openAPIGenWithExtOpt0() throws IOException, InterruptedException { - executeCommand("project_openapi_bal_ext/main.bal", "api_openapi_ext_0.yaml", + executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", "project_openapi_bal_ext/result_0.yaml", "0"); } @Test(description = "Generate with ballerina extension option - 1 - EXTERNAL_PACKAGE_TYPES") public void openAPIGenWithExtOpt1() throws IOException, InterruptedException { - executeCommand("project_openapi_bal_ext/main.bal", "api_openapi_ext_1.yaml", + executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", "project_openapi_bal_ext/result_1.yaml", "1"); } @Test(description = "Generate with ballerina extension option - 2 - SAME_PACKAGE_DIFFERENT_MODULE_TYPES") public void openAPIGenWithExtOpt2() throws IOException, InterruptedException { - executeCommand("project_openapi_bal_ext/main.bal", "api_openapi_ext_2.yaml", + executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", "project_openapi_bal_ext/result_2.yaml", "2"); } @Test(description = "Generate with ballerina extension option - 3 - ALL_REFERENCED_TYPES") public void openAPIGenWithExtOpt3() throws IOException, InterruptedException { - executeCommand("project_openapi_bal_ext/main.bal", "api_openapi_ext_3.yaml", + executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", "project_openapi_bal_ext/result_3.yaml", "3"); } From 09a16b80e9a37158d6de86a512f95e6422be4ed3 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 1 Aug 2024 21:46:45 +0530 Subject: [PATCH 08/16] Fix assertion --- .../java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java index ec80330ea..b84a67f00 100644 --- a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java +++ b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java @@ -123,7 +123,7 @@ public void nonHttpService() throws IOException, InterruptedException { List buildArgs = new LinkedList<>(); buildArgs.add("-i"); buildArgs.add("project_11/service.bal"); - Assert.assertTrue(TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs)); + Assert.assertFalse(TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs)); Assert.assertFalse(Files.exists(TEST_RESOURCE.resolve("query_openapi.yaml"))); } From 71f5a08a763c803b8df67ef14c468ee6d0f65751 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 1 Aug 2024 22:27:51 +0530 Subject: [PATCH 09/16] Fix package name resolution --- .../extension/BallerinaTypeExtensioner.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java index bc0ba72af..f002fa91f 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java @@ -46,17 +46,18 @@ public static void addExtension(Schema schema, TypeSymbol typeSymbol) { } public static void removeExtensions(OpenAPI openAPI) { - removeExtensions(openAPI, BallerinaExtensionLevel.DISABLED, "", ""); + removeExtensions(openAPI, BallerinaExtensionLevel.DISABLED, "", "", ""); } public static void removeExtensions(OpenAPI openAPI, BallerinaExtensionLevel extensionLevel, ModuleID moduleID) { String orgName = moduleID.orgName(); + String packageName = moduleID.packageName(); String moduleName = moduleID.moduleName(); - removeExtensions(openAPI, extensionLevel, orgName, moduleName); + removeExtensions(openAPI, extensionLevel, orgName, packageName, moduleName); } private static void removeExtensions(OpenAPI openAPI, BallerinaExtensionLevel extensionLevel, - String orgName, String moduleName) { + String orgName, String packageName, String moduleName) { Components components = openAPI.getComponents(); if (Objects.isNull(components)) { return; @@ -70,19 +71,19 @@ private static void removeExtensions(OpenAPI openAPI, BallerinaExtensionLevel ex schemas.forEach((key, schema) -> { Map extensions = schema.getExtensions(); if (Objects.nonNull(extensions)) { - removeBallerinaExtension(extensionLevel, extensions, orgName, moduleName); + removeBallerinaExtension(extensionLevel, extensions, orgName, packageName, moduleName); } }); } - private static void removeBallerinaExtension(BallerinaExtensionLevel extensionLevel, - Map extensions, String orgName, String moduleName) { + private static void removeBallerinaExtension(BallerinaExtensionLevel extensionLevel, Map extensions, + String orgName, String packageName, String moduleName) { switch (extensionLevel) { case DISABLED: extensions.remove(X_BALLERINA_TYPE); break; case EXTERNAL_PACKAGE_TYPES: - if (fromSamePackage(extensions, orgName)) { + if (fromSamePackage(extensions, orgName, packageName)) { extensions.remove(X_BALLERINA_TYPE); } break; @@ -101,9 +102,9 @@ private static boolean fromSameModule(Map extensions, String orgName, Stri orgName.equals(ballerinaPkg.orgName()) && moduleName.equals(ballerinaPkg.moduleName()); } - private static boolean fromSamePackage(Map extensions, String orgName) { + private static boolean fromSamePackage(Map extensions, String orgName, String packageName) { return extensions.get(X_BALLERINA_TYPE) instanceof BallerinaPackage ballerinaPkg && - orgName.equals(ballerinaPkg.orgName()); + orgName.equals(ballerinaPkg.orgName()) && packageName.equals(ballerinaPkg.pkgName()); } public static Optional getExtension(Schema schema) { From 92cf77e0603d241b0c7d3bc3aec18879fdb23656 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Thu, 1 Aug 2024 22:34:19 +0530 Subject: [PATCH 10/16] Update results --- .../project_openapi_bal_ext/result_0.yaml | 62 +++++++------- .../project_openapi_bal_ext/result_1.yaml | 62 +++++++------- .../project_openapi_bal_ext/result_2.yaml | 68 +++++++-------- .../project_openapi_bal_ext/result_3.yaml | 84 +++++++++---------- 4 files changed, 138 insertions(+), 138 deletions(-) diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_0.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_0.yaml index b9c068560..888e567c3 100644 --- a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_0.yaml +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_0.yaml @@ -3,12 +3,12 @@ info: title: Api V1 version: 0.1.0 servers: -- url: "{server}:{port}/api/v1" - variables: - server: - default: http://localhost - port: - default: "9090" + - url: "{server}:{port}/api/v1" + variables: + server: + default: http://localhost + port: + default: "9090" paths: /students: get: @@ -26,8 +26,8 @@ components: schemas: BasicStudent: required: - - age - - name + - age + - name type: object properties: name: @@ -40,17 +40,17 @@ components: type: object description: Date in proleptic Gregorian calendar. allOf: - - $ref: '#/components/schemas/DateFields' - - $ref: '#/components/schemas/OptionalTimeOfDayFields' - - type: object - properties: - utcOffset: - $ref: '#/components/schemas/ZoneOffset' + - $ref: '#/components/schemas/DateFields' + - $ref: '#/components/schemas/OptionalTimeOfDayFields' + - type: object + properties: + utcOffset: + $ref: '#/components/schemas/ZoneOffset' DateFields: required: - - day - - month - - year + - day + - month + - year type: object properties: year: @@ -82,21 +82,21 @@ components: Student: type: object allOf: - - $ref: '#/components/schemas/BasicStudent' - - required: - - subjects - type: object - properties: - subjects: - type: array - items: - $ref: '#/components/schemas/Subject' - additionalProperties: false + - $ref: '#/components/schemas/BasicStudent' + - required: + - subjects + type: object + properties: + subjects: + type: array + items: + $ref: '#/components/schemas/Subject' + additionalProperties: false Subject: required: - - credits - - examDate - - name + - credits + - examDate + - name type: object properties: name: @@ -109,7 +109,7 @@ components: additionalProperties: false ZoneOffset: required: - - hours + - hours type: object properties: hours: diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml index 6805d4926..c21a4a8f7 100644 --- a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml @@ -3,12 +3,12 @@ info: title: Api V1 version: 0.1.0 servers: -- url: "{server}:{port}/api/v1" - variables: - server: - default: http://localhost - port: - default: "9090" + - url: "{server}:{port}/api/v1" + variables: + server: + default: http://localhost + port: + default: "9090" paths: /students: get: @@ -26,8 +26,8 @@ components: schemas: BasicStudent: required: - - age - - name + - age + - name type: object properties: name: @@ -40,12 +40,12 @@ components: type: object description: Date in proleptic Gregorian calendar. allOf: - - $ref: '#/components/schemas/DateFields' - - $ref: '#/components/schemas/OptionalTimeOfDayFields' - - type: object - properties: - utcOffset: - $ref: '#/components/schemas/ZoneOffset' + - $ref: '#/components/schemas/DateFields' + - $ref: '#/components/schemas/OptionalTimeOfDayFields' + - type: object + properties: + utcOffset: + $ref: '#/components/schemas/ZoneOffset' x-ballerina-type: orgName: ballerina pkgName: time @@ -55,9 +55,9 @@ components: name: Date DateFields: required: - - day - - month - - year + - day + - month + - year type: object properties: year: @@ -110,21 +110,21 @@ components: Student: type: object allOf: - - $ref: '#/components/schemas/BasicStudent' - - required: - - subjects - type: object - properties: - subjects: - type: array - items: - $ref: '#/components/schemas/Subject' - additionalProperties: false + - $ref: '#/components/schemas/BasicStudent' + - required: + - subjects + type: object + properties: + subjects: + type: array + items: + $ref: '#/components/schemas/Subject' + additionalProperties: false Subject: required: - - credits - - examDate - - name + - credits + - examDate + - name type: object properties: name: @@ -137,7 +137,7 @@ components: additionalProperties: false ZoneOffset: required: - - hours + - hours type: object properties: hours: diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml index bc0ec0d96..0dafce369 100644 --- a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml @@ -3,12 +3,12 @@ info: title: Api V1 version: 0.1.0 servers: -- url: "{server}:{port}/api/v1" - variables: - server: - default: http://localhost - port: - default: "9090" + - url: "{server}:{port}/api/v1" + variables: + server: + default: http://localhost + port: + default: "9090" paths: /students: get: @@ -26,8 +26,8 @@ components: schemas: BasicStudent: required: - - age - - name + - age + - name type: object properties: name: @@ -37,9 +37,9 @@ components: format: int64 additionalProperties: false x-ballerina-type: - orgName: tharmigan - pkgName: bal_ext - moduleName: bal_ext.module + orgName: ballerina + pkgName: openapi_bal_ext + moduleName: openapi_bal_ext.module version: 0.1.0 modulePrefix: module name: BasicStudent @@ -47,12 +47,12 @@ components: type: object description: Date in proleptic Gregorian calendar. allOf: - - $ref: '#/components/schemas/DateFields' - - $ref: '#/components/schemas/OptionalTimeOfDayFields' - - type: object - properties: - utcOffset: - $ref: '#/components/schemas/ZoneOffset' + - $ref: '#/components/schemas/DateFields' + - $ref: '#/components/schemas/OptionalTimeOfDayFields' + - type: object + properties: + utcOffset: + $ref: '#/components/schemas/ZoneOffset' x-ballerina-type: orgName: ballerina pkgName: time @@ -62,9 +62,9 @@ components: name: Date DateFields: required: - - day - - month - - year + - day + - month + - year type: object properties: year: @@ -117,21 +117,21 @@ components: Student: type: object allOf: - - $ref: '#/components/schemas/BasicStudent' - - required: - - subjects - type: object - properties: - subjects: - type: array - items: - $ref: '#/components/schemas/Subject' - additionalProperties: false + - $ref: '#/components/schemas/BasicStudent' + - required: + - subjects + type: object + properties: + subjects: + type: array + items: + $ref: '#/components/schemas/Subject' + additionalProperties: false Subject: required: - - credits - - examDate - - name + - credits + - examDate + - name type: object properties: name: @@ -144,7 +144,7 @@ components: additionalProperties: false ZoneOffset: required: - - hours + - hours type: object properties: hours: diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml index 8c6714baf..a75bcb9ad 100644 --- a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml @@ -3,12 +3,12 @@ info: title: Api V1 version: 0.1.0 servers: -- url: "{server}:{port}/api/v1" - variables: - server: - default: http://localhost - port: - default: "9090" + - url: "{server}:{port}/api/v1" + variables: + server: + default: http://localhost + port: + default: "9090" paths: /students: get: @@ -26,8 +26,8 @@ components: schemas: BasicStudent: required: - - age - - name + - age + - name type: object properties: name: @@ -37,9 +37,9 @@ components: format: int64 additionalProperties: false x-ballerina-type: - orgName: tharmigan - pkgName: bal_ext - moduleName: bal_ext.module + orgName: ballerina + pkgName: openapi_bal_ext + moduleName: openapi_bal_ext.module version: 0.1.0 modulePrefix: module name: BasicStudent @@ -47,12 +47,12 @@ components: type: object description: Date in proleptic Gregorian calendar. allOf: - - $ref: '#/components/schemas/DateFields' - - $ref: '#/components/schemas/OptionalTimeOfDayFields' - - type: object - properties: - utcOffset: - $ref: '#/components/schemas/ZoneOffset' + - $ref: '#/components/schemas/DateFields' + - $ref: '#/components/schemas/OptionalTimeOfDayFields' + - type: object + properties: + utcOffset: + $ref: '#/components/schemas/ZoneOffset' x-ballerina-type: orgName: ballerina pkgName: time @@ -62,9 +62,9 @@ components: name: Date DateFields: required: - - day - - month - - year + - day + - month + - year type: object properties: year: @@ -117,28 +117,28 @@ components: Student: type: object allOf: - - $ref: '#/components/schemas/BasicStudent' - - required: - - subjects - type: object - properties: - subjects: - type: array - items: - $ref: '#/components/schemas/Subject' - additionalProperties: false + - $ref: '#/components/schemas/BasicStudent' + - required: + - subjects + type: object + properties: + subjects: + type: array + items: + $ref: '#/components/schemas/Subject' + additionalProperties: false x-ballerina-type: - orgName: tharmigan - pkgName: bal_ext - moduleName: bal_ext + orgName: ballerina + pkgName: openapi_bal_ext + moduleName: openapi_bal_ext version: 0.1.0 - modulePrefix: bal_ext + modulePrefix: openapi_bal_ext name: Student Subject: required: - - credits - - examDate - - name + - credits + - examDate + - name type: object properties: name: @@ -150,15 +150,15 @@ components: $ref: '#/components/schemas/Date' additionalProperties: false x-ballerina-type: - orgName: tharmigan - pkgName: bal_ext - moduleName: bal_ext + orgName: ballerina + pkgName: openapi_bal_ext + moduleName: openapi_bal_ext version: 0.1.0 - modulePrefix: bal_ext + modulePrefix: openapi_bal_ext name: Subject ZoneOffset: required: - - hours + - hours type: object properties: hours: From 4baa532a05d953cb5b576a75116f8c08ec829fbc Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 2 Aug 2024 08:48:02 +0530 Subject: [PATCH 11/16] Fix assertion on windows --- .../java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java index b84a67f00..a737795d2 100644 --- a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java +++ b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java @@ -123,7 +123,7 @@ public void nonHttpService() throws IOException, InterruptedException { List buildArgs = new LinkedList<>(); buildArgs.add("-i"); buildArgs.add("project_11/service.bal"); - Assert.assertFalse(TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs)); + TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs); Assert.assertFalse(Files.exists(TEST_RESOURCE.resolve("query_openapi.yaml"))); } From 5e382c9d1336b5cfed22a3ebfb0618b14f328a15 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 2 Aug 2024 10:21:27 +0530 Subject: [PATCH 12/16] Address review comments --- .../service/mapper/ServiceToOpenAPIMapper.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index a53e81c79..8026329dc 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -55,6 +55,7 @@ import java.util.Set; import static io.ballerina.openapi.service.mapper.Constants.HYPHEN; +import static io.ballerina.openapi.service.mapper.type.extension.BallerinaExtensionLevel.DISABLED; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.containErrors; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getOpenApiFileName; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.isHttpService; @@ -83,7 +84,8 @@ public static List generateOAS3Definition(Project project, SyntaxTree SemanticModel semanticModel, String serviceName, Boolean needJson, Path inputPath) { - return generateOAS3Definition(project, syntaxTree, semanticModel, serviceName, needJson, inputPath, "0"); + return generateOAS3Definition(project, syntaxTree, semanticModel, serviceName, needJson, inputPath, + DISABLED.getValue()); } /** @@ -117,7 +119,7 @@ public static List generateOAS3Definition(Project project, SyntaxTree diagnostics.add(error); } // Check ballerina extension level - BallerinaExtensionLevel extensionLevel = BallerinaExtensionLevel.DISABLED; + BallerinaExtensionLevel extensionLevel = DISABLED; try { extensionLevel = BallerinaExtensionLevel.fromValue(ballerinaExtensionLevel); } catch (IllegalArgumentException e) { @@ -268,12 +270,8 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) private static Optional getServiceModuleId(ServiceDeclarationNode serviceDeclarationNode, SemanticModel semanticModel) { - Optional symbol = semanticModel.symbol(serviceDeclarationNode); - if (symbol.isEmpty()) { - return Optional.empty(); - } - Optional module = symbol.get().getModule(); - return module.map(ModuleSymbol::id); + return semanticModel.symbol(serviceDeclarationNode) + .flatMap(symbol -> symbol.getModule().map(ModuleSymbol::id)); } /** From 022d179304b781c1dab509a03b3fc080bf4d76c1 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 2 Aug 2024 11:04:57 +0530 Subject: [PATCH 13/16] Refactor implementation to allow only one level --- .../mapper/ServiceToOpenAPIMapper.java | 23 +-- .../mapper/model/OASGenerationMetaInfo.java | 13 +- .../extension/BallerinaTypeExtensioner.java | 43 ++-- .../openapi/cmd/OASContractGenerator.java | 10 +- .../io/ballerina/openapi/cmd/OpenApiCmd.java | 18 +- .../openapi/cmd/BallerinaToOpenAPITests.java | 26 +-- .../project_openapi_bal_ext/result_1.yaml | 7 + .../project_openapi_bal_ext/result_2.yaml | 170 ---------------- .../project_openapi_bal_ext/result_3.yaml | 184 ------------------ 9 files changed, 46 insertions(+), 448 deletions(-) delete mode 100644 openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml delete mode 100644 openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 8026329dc..b9d12234e 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -40,7 +40,6 @@ import io.ballerina.openapi.service.mapper.model.ModuleMemberVisitor; import io.ballerina.openapi.service.mapper.model.OASGenerationMetaInfo; import io.ballerina.openapi.service.mapper.model.OASResult; -import io.ballerina.openapi.service.mapper.type.extension.BallerinaExtensionLevel; import io.ballerina.openapi.service.mapper.type.extension.BallerinaTypeExtensioner; import io.ballerina.projects.Module; import io.ballerina.projects.Project; @@ -55,7 +54,6 @@ import java.util.Set; import static io.ballerina.openapi.service.mapper.Constants.HYPHEN; -import static io.ballerina.openapi.service.mapper.type.extension.BallerinaExtensionLevel.DISABLED; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.containErrors; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.getOpenApiFileName; import static io.ballerina.openapi.service.mapper.utils.MapperCommonUtils.isHttpService; @@ -84,8 +82,7 @@ public static List generateOAS3Definition(Project project, SyntaxTree SemanticModel semanticModel, String serviceName, Boolean needJson, Path inputPath) { - return generateOAS3Definition(project, syntaxTree, semanticModel, serviceName, needJson, inputPath, - DISABLED.getValue()); + return generateOAS3Definition(project, syntaxTree, semanticModel, serviceName, needJson, inputPath, false); } /** @@ -101,7 +98,7 @@ public static List generateOAS3Definition(Project project, SyntaxTree public static List generateOAS3Definition(Project project, SyntaxTree syntaxTree, SemanticModel semanticModel, String serviceName, Boolean needJson, - Path inputPath, String ballerinaExtensionLevel) { + Path inputPath, Boolean ballerinaExtension) { Map servicesToGenerate = new HashMap<>(); List availableService = new ArrayList<>(); List diagnostics = new ArrayList<>(); @@ -118,15 +115,6 @@ public static List generateOAS3Definition(Project project, SyntaxTree availableService.toString()); diagnostics.add(error); } - // Check ballerina extension level - BallerinaExtensionLevel extensionLevel = DISABLED; - try { - extensionLevel = BallerinaExtensionLevel.fromValue(ballerinaExtensionLevel); - } catch (IllegalArgumentException e) { - ExceptionDiagnostic error = new ExceptionDiagnostic(DiagnosticMessages.OAS_CONVERTOR_136, - ballerinaExtensionLevel); - diagnostics.add(error); - } // Generating openapi specification for selected services for (Map.Entry serviceNode : servicesToGenerate.entrySet()) { String openApiName = getOpenApiFileName(syntaxTree.filePath(), serviceNode.getKey(), needJson); @@ -136,7 +124,7 @@ public static List generateOAS3Definition(Project project, SyntaxTree .setSemanticModel(semanticModel) .setOpenApiFileName(openApiName) .setBallerinaFilePath(inputPath) - .setBallerinaExtensionLevel(extensionLevel) + .setBallerinaExtension(ballerinaExtension) .setProject(project); OASGenerationMetaInfo oasGenerationMetaInfo = builder.build(); OASResult oasDefinition = generateOAS(oasGenerationMetaInfo); @@ -253,9 +241,8 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) } // Remove ballerina extensions Optional serviceModuleId = getServiceModuleId(serviceDefinition, semanticModel); - if (serviceModuleId.isPresent()) { - BallerinaTypeExtensioner.removeExtensions(openapi, - oasGenerationMetaInfo.getBallerinaExtensionLevel(), serviceModuleId.get()); + if (oasGenerationMetaInfo.getBallerinaExtension() && serviceModuleId.isPresent()) { + BallerinaTypeExtensioner.removeCurrentModuleTypeExtensions(openapi, serviceModuleId.get()); } else { BallerinaTypeExtensioner.removeExtensions(openapi); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/OASGenerationMetaInfo.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/OASGenerationMetaInfo.java index 58cc1e4ed..2cd65fa09 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/OASGenerationMetaInfo.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/OASGenerationMetaInfo.java @@ -19,7 +19,6 @@ import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.syntax.tree.ServiceDeclarationNode; -import io.ballerina.openapi.service.mapper.type.extension.BallerinaExtensionLevel; import io.ballerina.projects.Project; import java.nio.file.Path; @@ -36,7 +35,7 @@ public class OASGenerationMetaInfo { private final SemanticModel semanticModel; private final ServiceDeclarationNode serviceDeclarationNode; private final Project project; - private final BallerinaExtensionLevel ballerinaExtensionLevel; + private final Boolean ballerinaExtensionLevel; public OASGenerationMetaInfo(OASGenerationMetaInfoBuilder builder) { this.openApiFileName = builder.openApiFileName; @@ -44,7 +43,7 @@ public OASGenerationMetaInfo(OASGenerationMetaInfoBuilder builder) { this.semanticModel = builder.semanticModel; this.serviceDeclarationNode = builder.serviceDeclarationNode; this.project = builder.project; - this.ballerinaExtensionLevel = builder.ballerinaExtensionLevel; + this.ballerinaExtensionLevel = builder.ballerinaExtension; } public String getOpenApiFileName() { @@ -67,7 +66,7 @@ public Project getProject() { return project; } - public BallerinaExtensionLevel getBallerinaExtensionLevel() { + public Boolean getBallerinaExtension() { return ballerinaExtensionLevel; } @@ -81,7 +80,7 @@ public static class OASGenerationMetaInfoBuilder { private SemanticModel semanticModel; private ServiceDeclarationNode serviceDeclarationNode; private Project project; - private BallerinaExtensionLevel ballerinaExtensionLevel = BallerinaExtensionLevel.DISABLED; + private Boolean ballerinaExtension = false; public OASGenerationMetaInfoBuilder setBallerinaFilePath(Path ballerinaFilePath) { this.ballerinaFilePath = ballerinaFilePath; @@ -103,8 +102,8 @@ public OASGenerationMetaInfoBuilder setOpenApiFileName(String openApiFileName) { return this; } - public OASGenerationMetaInfoBuilder setBallerinaExtensionLevel(BallerinaExtensionLevel balExtLevel) { - this.ballerinaExtensionLevel = balExtLevel; + public OASGenerationMetaInfoBuilder setBallerinaExtension(Boolean balExt) { + this.ballerinaExtension = balExt; return this; } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java index f002fa91f..a4f94a2cf 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaTypeExtensioner.java @@ -46,18 +46,18 @@ public static void addExtension(Schema schema, TypeSymbol typeSymbol) { } public static void removeExtensions(OpenAPI openAPI) { - removeExtensions(openAPI, BallerinaExtensionLevel.DISABLED, "", "", ""); + removeExtensionsFromSchemas(openAPI, (extensions, orgName, moduleName) -> true); } - public static void removeExtensions(OpenAPI openAPI, BallerinaExtensionLevel extensionLevel, ModuleID moduleID) { + public static void removeCurrentModuleTypeExtensions(OpenAPI openAPI, ModuleID moduleID) { String orgName = moduleID.orgName(); - String packageName = moduleID.packageName(); String moduleName = moduleID.moduleName(); - removeExtensions(openAPI, extensionLevel, orgName, packageName, moduleName); + + removeExtensionsFromSchemas(openAPI, (extensions, org, mod) -> fromSameModule(extensions, orgName, + moduleName)); } - private static void removeExtensions(OpenAPI openAPI, BallerinaExtensionLevel extensionLevel, - String orgName, String packageName, String moduleName) { + private static void removeExtensionsFromSchemas(OpenAPI openAPI, ExtensionRemovalCondition condition) { Components components = openAPI.getComponents(); if (Objects.isNull(components)) { return; @@ -70,31 +70,15 @@ private static void removeExtensions(OpenAPI openAPI, BallerinaExtensionLevel ex schemas.forEach((key, schema) -> { Map extensions = schema.getExtensions(); - if (Objects.nonNull(extensions)) { - removeBallerinaExtension(extensionLevel, extensions, orgName, packageName, moduleName); + if (Objects.nonNull(extensions) && condition.shouldRemove(extensions, null, null)) { + extensions.remove(X_BALLERINA_TYPE); } }); } - private static void removeBallerinaExtension(BallerinaExtensionLevel extensionLevel, Map extensions, - String orgName, String packageName, String moduleName) { - switch (extensionLevel) { - case DISABLED: - extensions.remove(X_BALLERINA_TYPE); - break; - case EXTERNAL_PACKAGE_TYPES: - if (fromSamePackage(extensions, orgName, packageName)) { - extensions.remove(X_BALLERINA_TYPE); - } - break; - case SAME_PACKAGE_DIFFERENT_MODULE_TYPES: - if (fromSameModule(extensions, orgName, moduleName)) { - extensions.remove(X_BALLERINA_TYPE); - } - break; - case ALL_REFERENCED_TYPES: - break; - } + @FunctionalInterface + private interface ExtensionRemovalCondition { + boolean shouldRemove(Map extensions, String orgName, String moduleName); } private static boolean fromSameModule(Map extensions, String orgName, String moduleName) { @@ -102,11 +86,6 @@ private static boolean fromSameModule(Map extensions, String orgName, Stri orgName.equals(ballerinaPkg.orgName()) && moduleName.equals(ballerinaPkg.moduleName()); } - private static boolean fromSamePackage(Map extensions, String orgName, String packageName) { - return extensions.get(X_BALLERINA_TYPE) instanceof BallerinaPackage ballerinaPkg && - orgName.equals(ballerinaPkg.orgName()) && packageName.equals(ballerinaPkg.pkgName()); - } - public static Optional getExtension(Schema schema) { Map extensions = schema.getExtensions(); if (Objects.isNull(extensions)) { diff --git a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java index 33d14d1dc..8381ac80a 100644 --- a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java +++ b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OASContractGenerator.java @@ -60,7 +60,7 @@ public class OASContractGenerator { private Project project; private List diagnostics = new ArrayList<>(); private PrintStream outStream = System.out; - private String ballerinaExtensionLevel = "0"; + private Boolean ballerinaExtension = false; /** * Initialize constructor. @@ -69,9 +69,9 @@ public OASContractGenerator() { } - public void setBallerinaExtensionLevel(String ballerinaExtensionLevel) { - if (Objects.nonNull(ballerinaExtensionLevel)) { - this.ballerinaExtensionLevel = ballerinaExtensionLevel; + public void setBallerinaExtension(Boolean ballerinaExtension) { + if (Objects.nonNull(ballerinaExtension)) { + this.ballerinaExtension = ballerinaExtension; } } @@ -126,7 +126,7 @@ public void generateOAS3DefinitionsAllService(Path servicePath, Path outPath, St } semanticModel = compilation.getSemanticModel(docId.moduleId()); List openAPIDefinitions = ServiceToOpenAPIMapper.generateOAS3Definition(project, syntaxTree, - semanticModel, serviceName, needJson, inputPath, ballerinaExtensionLevel); + semanticModel, serviceName, needJson, inputPath, ballerinaExtension); if (!openAPIDefinitions.isEmpty()) { List fileNames = new ArrayList<>(); diff --git a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java index 06eea8999..3ddb66be3 100644 --- a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java +++ b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java @@ -121,8 +121,8 @@ public class OpenApiCmd implements BLauncherCmd { description = "Generate service without data binding") private boolean generateWithoutDataBinding; - @CommandLine.Option(names = {"--bal-ext-level"}, hidden = true, description = "Generate ballerina type extensions") - private String ballerinaExtensionLevel; + @CommandLine.Option(names = {"--with-bal-ext"}, hidden = true, description = "Generate ballerina type extensions") + private Boolean addBallerinaExtension; @CommandLine.Parameters @@ -229,8 +229,8 @@ public void execute() { } } - if (ballerinaExtensionLevel != null) { - outStream.println("'--bal-ext-level' option is only available in OpenAPI specification " + + if (addBallerinaExtension != null) { + outStream.println("'--bal-ext' option is only available in OpenAPI specification " + "generation mode."); exitError(this.exitWhenFinish); } @@ -248,14 +248,6 @@ public void execute() { outStream.println("'--client-methods' option is only available in client generation mode."); exitError(this.exitWhenFinish); } - if (ballerinaExtensionLevel != null && !(ballerinaExtensionLevel.equals("0") || - ballerinaExtensionLevel.equals("1") || ballerinaExtensionLevel.equals("2") || - ballerinaExtensionLevel.equals("3"))) { - outStream.println("unsupported '--bal-ext-level' option value. Please use 0 - DISABLED, 1 - " + - "EXTERNAL_PACKAGE_TYPES, 2 - SAME_PACKAGE_DIFFERENT_MODULE_TYPES, 3 - ALL_REFERENCED_TYPES"); - exitError(this.exitWhenFinish); - - } ballerinaToOpenApi(fileName); } else { outStream.println(ErrorMessages.MISSING_CONTRACT_PATH); @@ -294,7 +286,7 @@ private void ballerinaToOpenApi(String fileName) { getTargetOutputPath(); // Check service name it is mandatory OASContractGenerator openApiConverter = new OASContractGenerator(); - openApiConverter.setBallerinaExtensionLevel(ballerinaExtensionLevel); + openApiConverter.setBallerinaExtension(addBallerinaExtension); openApiConverter.generateOAS3DefinitionsAllService(balFilePath, targetOutputPath, service, generatedFileType); mapperDiagnostics.addAll(openApiConverter.getDiagnostics()); diff --git a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java index a737795d2..801b6ff2f 100644 --- a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java +++ b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java @@ -172,28 +172,16 @@ public void openAPIGenWithoutBalExt() throws IOException, InterruptedException { "project_openapi_bal_ext/result_0.yaml"); } - @Test(description = "Generate with ballerina extension option - 0 - DISABLED") + @Test(description = "Generate with ballerina extension option - false") public void openAPIGenWithExtOpt0() throws IOException, InterruptedException { executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", - "project_openapi_bal_ext/result_0.yaml", "0"); + "project_openapi_bal_ext/result_0.yaml", false); } - @Test(description = "Generate with ballerina extension option - 1 - EXTERNAL_PACKAGE_TYPES") - public void openAPIGenWithExtOpt1() throws IOException, InterruptedException { - executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", - "project_openapi_bal_ext/result_1.yaml", "1"); - } - - @Test(description = "Generate with ballerina extension option - 2 - SAME_PACKAGE_DIFFERENT_MODULE_TYPES") + @Test(description = "Generate with ballerina extension option - true") public void openAPIGenWithExtOpt2() throws IOException, InterruptedException { executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", - "project_openapi_bal_ext/result_2.yaml", "2"); - } - - @Test(description = "Generate with ballerina extension option - 3 - ALL_REFERENCED_TYPES") - public void openAPIGenWithExtOpt3() throws IOException, InterruptedException { - executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", - "project_openapi_bal_ext/result_3.yaml", "3"); + "project_openapi_bal_ext/result_1.yaml", true); } @AfterClass @@ -220,13 +208,13 @@ private void executeCommand(String resourcePath, String generatedFile, String ex Assert.assertEquals(expectedYaml, generatedOpenAPI); } - private void executeCommand(String resourcePath, String generatedFile, String expectedPath, String extensionLevel) + private void executeCommand(String resourcePath, String generatedFile, String expectedPath, boolean balExt) throws IOException, InterruptedException { List buildArgs = new LinkedList<>(); buildArgs.add("-i"); buildArgs.add(resourcePath); - buildArgs.add("--bal-ext-level"); - buildArgs.add(extensionLevel); + buildArgs.add("--bal-ext"); + buildArgs.add(String.valueOf(balExt)); Assert.assertTrue(TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs)); Assert.assertTrue(Files.exists(TEST_RESOURCE.resolve(generatedFile))); String generatedOpenAPI = getStringFromGivenBalFile(TEST_RESOURCE.resolve(generatedFile)); diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml index c21a4a8f7..0dafce369 100644 --- a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml +++ b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_1.yaml @@ -36,6 +36,13 @@ components: type: integer format: int64 additionalProperties: false + x-ballerina-type: + orgName: ballerina + pkgName: openapi_bal_ext + moduleName: openapi_bal_ext.module + version: 0.1.0 + modulePrefix: module + name: BasicStudent Date: type: object description: Date in proleptic Gregorian calendar. diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml deleted file mode 100644 index 0dafce369..000000000 --- a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_2.yaml +++ /dev/null @@ -1,170 +0,0 @@ -openapi: 3.0.1 -info: - title: Api V1 - version: 0.1.0 -servers: - - url: "{server}:{port}/api/v1" - variables: - server: - default: http://localhost - port: - default: "9090" -paths: - /students: - get: - operationId: getStudents - responses: - "200": - description: Ok - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Student' -components: - schemas: - BasicStudent: - required: - - age - - name - type: object - properties: - name: - type: string - age: - type: integer - format: int64 - additionalProperties: false - x-ballerina-type: - orgName: ballerina - pkgName: openapi_bal_ext - moduleName: openapi_bal_ext.module - version: 0.1.0 - modulePrefix: module - name: BasicStudent - Date: - type: object - description: Date in proleptic Gregorian calendar. - allOf: - - $ref: '#/components/schemas/DateFields' - - $ref: '#/components/schemas/OptionalTimeOfDayFields' - - type: object - properties: - utcOffset: - $ref: '#/components/schemas/ZoneOffset' - x-ballerina-type: - orgName: ballerina - pkgName: time - moduleName: time - version: 2.4.0 - modulePrefix: time - name: Date - DateFields: - required: - - day - - month - - year - type: object - properties: - year: - type: integer - format: int64 - month: - type: integer - format: int64 - day: - type: integer - format: int64 - description: Fields of the Date record. - x-ballerina-type: - orgName: ballerina - pkgName: time - moduleName: time - version: 2.4.0 - modulePrefix: time - name: DateFields - OptionalTimeOfDayFields: - type: object - properties: - hour: - type: integer - format: int64 - minute: - type: integer - format: int64 - second: - $ref: '#/components/schemas/Seconds' - description: TimeOfDay with all the fields beign optional. - x-ballerina-type: - orgName: ballerina - pkgName: time - moduleName: time - version: 2.4.0 - modulePrefix: time - name: OptionalTimeOfDayFields - Seconds: - type: number - description: Holds the seconds as a decimal value. - format: double - x-ballerina-type: - orgName: ballerina - pkgName: time - moduleName: time - version: 2.4.0 - modulePrefix: time - name: Seconds - Student: - type: object - allOf: - - $ref: '#/components/schemas/BasicStudent' - - required: - - subjects - type: object - properties: - subjects: - type: array - items: - $ref: '#/components/schemas/Subject' - additionalProperties: false - Subject: - required: - - credits - - examDate - - name - type: object - properties: - name: - type: string - credits: - type: integer - format: int64 - examDate: - $ref: '#/components/schemas/Date' - additionalProperties: false - ZoneOffset: - required: - - hours - type: object - properties: - hours: - type: integer - format: int64 - minutes: - type: integer - format: int64 - seconds: - type: number - description: |- - IETF zone files have historical zones that are offset by - integer seconds; we use Seconds type so that this is a subtype - of Delta - format: double - additionalProperties: false - x-ballerina-type: - orgName: ballerina - pkgName: time - moduleName: time - version: 2.4.0 - modulePrefix: time - name: ZoneOffset diff --git a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml b/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml deleted file mode 100644 index a75bcb9ad..000000000 --- a/openapi-integration-tests/src/test/resources/ballerina_sources/project_openapi_bal_ext/result_3.yaml +++ /dev/null @@ -1,184 +0,0 @@ -openapi: 3.0.1 -info: - title: Api V1 - version: 0.1.0 -servers: - - url: "{server}:{port}/api/v1" - variables: - server: - default: http://localhost - port: - default: "9090" -paths: - /students: - get: - operationId: getStudents - responses: - "200": - description: Ok - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Student' -components: - schemas: - BasicStudent: - required: - - age - - name - type: object - properties: - name: - type: string - age: - type: integer - format: int64 - additionalProperties: false - x-ballerina-type: - orgName: ballerina - pkgName: openapi_bal_ext - moduleName: openapi_bal_ext.module - version: 0.1.0 - modulePrefix: module - name: BasicStudent - Date: - type: object - description: Date in proleptic Gregorian calendar. - allOf: - - $ref: '#/components/schemas/DateFields' - - $ref: '#/components/schemas/OptionalTimeOfDayFields' - - type: object - properties: - utcOffset: - $ref: '#/components/schemas/ZoneOffset' - x-ballerina-type: - orgName: ballerina - pkgName: time - moduleName: time - version: 2.4.0 - modulePrefix: time - name: Date - DateFields: - required: - - day - - month - - year - type: object - properties: - year: - type: integer - format: int64 - month: - type: integer - format: int64 - day: - type: integer - format: int64 - description: Fields of the Date record. - x-ballerina-type: - orgName: ballerina - pkgName: time - moduleName: time - version: 2.4.0 - modulePrefix: time - name: DateFields - OptionalTimeOfDayFields: - type: object - properties: - hour: - type: integer - format: int64 - minute: - type: integer - format: int64 - second: - $ref: '#/components/schemas/Seconds' - description: TimeOfDay with all the fields beign optional. - x-ballerina-type: - orgName: ballerina - pkgName: time - moduleName: time - version: 2.4.0 - modulePrefix: time - name: OptionalTimeOfDayFields - Seconds: - type: number - description: Holds the seconds as a decimal value. - format: double - x-ballerina-type: - orgName: ballerina - pkgName: time - moduleName: time - version: 2.4.0 - modulePrefix: time - name: Seconds - Student: - type: object - allOf: - - $ref: '#/components/schemas/BasicStudent' - - required: - - subjects - type: object - properties: - subjects: - type: array - items: - $ref: '#/components/schemas/Subject' - additionalProperties: false - x-ballerina-type: - orgName: ballerina - pkgName: openapi_bal_ext - moduleName: openapi_bal_ext - version: 0.1.0 - modulePrefix: openapi_bal_ext - name: Student - Subject: - required: - - credits - - examDate - - name - type: object - properties: - name: - type: string - credits: - type: integer - format: int64 - examDate: - $ref: '#/components/schemas/Date' - additionalProperties: false - x-ballerina-type: - orgName: ballerina - pkgName: openapi_bal_ext - moduleName: openapi_bal_ext - version: 0.1.0 - modulePrefix: openapi_bal_ext - name: Subject - ZoneOffset: - required: - - hours - type: object - properties: - hours: - type: integer - format: int64 - minutes: - type: integer - format: int64 - seconds: - type: number - description: |- - IETF zone files have historical zones that are offset by - integer seconds; we use Seconds type so that this is a subtype - of Delta - format: double - additionalProperties: false - x-ballerina-type: - orgName: ballerina - pkgName: time - moduleName: time - version: 2.4.0 - modulePrefix: time - name: ZoneOffset From 4b9b112ba851a169e3d6881011bc183589ee536e Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 2 Aug 2024 11:12:29 +0530 Subject: [PATCH 14/16] Remove extension level class --- .../extension/BallerinaExtensionLevel.java | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaExtensionLevel.java diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaExtensionLevel.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaExtensionLevel.java deleted file mode 100644 index 462a6138a..000000000 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/type/extension/BallerinaExtensionLevel.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package io.ballerina.openapi.service.mapper.type.extension; - -/** - * This {@link BallerinaExtensionLevel} represents the Ballerina extension levels. - */ -public enum BallerinaExtensionLevel { - DISABLED("0"), - EXTERNAL_PACKAGE_TYPES("1"), - SAME_PACKAGE_DIFFERENT_MODULE_TYPES("2"), - ALL_REFERENCED_TYPES("3"); - - private final String value; - - BallerinaExtensionLevel(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - public static BallerinaExtensionLevel fromValue(String value) { - for (BallerinaExtensionLevel level : BallerinaExtensionLevel.values()) { - if (level.getValue().equals(value)) { - return level; - } - } - throw new IllegalArgumentException("Unknown value: " + value); - } -} From 4d16bd5502e8090de1865bcd27dcb8b5f541edd3 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 2 Aug 2024 11:42:09 +0530 Subject: [PATCH 15/16] Fix test cases --- .../java/io/ballerina/openapi/cmd/OpenApiCmd.java | 6 +++--- .../openapi/cmd/BallerinaToOpenAPITests.java | 12 +++--------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java index 3ddb66be3..dd367f0e0 100644 --- a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java +++ b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/OpenApiCmd.java @@ -122,7 +122,7 @@ public class OpenApiCmd implements BLauncherCmd { private boolean generateWithoutDataBinding; @CommandLine.Option(names = {"--with-bal-ext"}, hidden = true, description = "Generate ballerina type extensions") - private Boolean addBallerinaExtension; + private boolean addBallerinaExtension; @CommandLine.Parameters @@ -229,8 +229,8 @@ public void execute() { } } - if (addBallerinaExtension != null) { - outStream.println("'--bal-ext' option is only available in OpenAPI specification " + + if (addBallerinaExtension) { + outStream.println("'--with-bal-ext' option is only available in OpenAPI specification " + "generation mode."); exitError(this.exitWhenFinish); } diff --git a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java index 801b6ff2f..83082d548 100644 --- a/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java +++ b/openapi-integration-tests/src/test/java/io/ballerina/openapi/cmd/BallerinaToOpenAPITests.java @@ -172,14 +172,8 @@ public void openAPIGenWithoutBalExt() throws IOException, InterruptedException { "project_openapi_bal_ext/result_0.yaml"); } - @Test(description = "Generate with ballerina extension option - false") - public void openAPIGenWithExtOpt0() throws IOException, InterruptedException { - executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", - "project_openapi_bal_ext/result_0.yaml", false); - } - - @Test(description = "Generate with ballerina extension option - true") - public void openAPIGenWithExtOpt2() throws IOException, InterruptedException { + @Test(description = "Generate with ballerina extension option") + public void openAPIGenWithBalExt() throws IOException, InterruptedException { executeCommand("project_openapi_bal_ext/main.bal", "api_v1_openapi.yaml", "project_openapi_bal_ext/result_1.yaml", true); } @@ -213,7 +207,7 @@ private void executeCommand(String resourcePath, String generatedFile, String ex List buildArgs = new LinkedList<>(); buildArgs.add("-i"); buildArgs.add(resourcePath); - buildArgs.add("--bal-ext"); + buildArgs.add("--with-bal-ext"); buildArgs.add(String.valueOf(balExt)); Assert.assertTrue(TestUtil.executeOpenAPI(DISTRIBUTION_FILE_NAME, TEST_RESOURCE, buildArgs)); Assert.assertTrue(Files.exists(TEST_RESOURCE.resolve(generatedFile))); From 1f099717bbd9e44d83225b551d83b9297d5c2d16 Mon Sep 17 00:00:00 2001 From: TharmiganK Date: Fri, 2 Aug 2024 11:59:25 +0530 Subject: [PATCH 16/16] Merge with master --- .../openapi/service/mapper/ServiceToOpenAPIMapper.java | 5 ++--- .../openapi/service/mapper/model/ServiceDeclaration.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java index 97439ebb6..4b0e7aaa7 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/ServiceToOpenAPIMapper.java @@ -358,9 +358,8 @@ private static String extractBasePath(OpenAPI openApiFromServiceContract) { return servers.get(0).getUrl().split("\\{server}:\\{port}").length == 2 ? parts[1] : ""; } - private static Optional getServiceModuleId(ServiceDeclarationNode serviceDeclarationNode, - SemanticModel semanticModel) { - return semanticModel.symbol(serviceDeclarationNode) + private static Optional getServiceModuleId(ServiceNode serviceNode, SemanticModel semanticModel) { + return semanticModel.symbol(serviceNode.getInternalNode()) .flatMap(symbol -> symbol.getModule().map(ModuleSymbol::id)); } diff --git a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceDeclaration.java b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceDeclaration.java index 9d6606f9c..632f01167 100644 --- a/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceDeclaration.java +++ b/ballerina-to-openapi/src/main/java/io/ballerina/openapi/service/mapper/model/ServiceDeclaration.java @@ -236,7 +236,7 @@ private Optional getOpenAPISpecFromResources(Package pkg, SemanticModel return Optional.empty(); } OASResult oasResult = generateOasFroServiceNode(pkg.project(), serviceName.get(), semanticModel, null, - serviceContract.get()); + serviceContract.get(), false); if (oasResult.getDiagnostics().stream() .anyMatch(diagnostic -> diagnostic.getDiagnosticSeverity().equals(DiagnosticSeverity.ERROR))) { diagnostics.add(new ExceptionDiagnostic(DiagnosticMessages.OAS_CONVERTOR_136, serviceName.get()));