diff --git a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java index 5b83fe25a..b5f260777 100644 --- a/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java +++ b/openapi-cli/src/main/java/io/ballerina/openapi/cmd/BallerinaCodeGenerator.java @@ -167,11 +167,10 @@ public void generateClientAndService(String definitionPath, String serviceName, SyntaxTree schemaSyntaxTree = ballerinaSchemaGenerator.generateSyntaxTree(); String schemaContent = Formatter.format(schemaSyntaxTree).toSourceCode(); - if (filter.getTags().size() > 0) { - // Remove unused records and enums when generating the client by the tags given. - schemaContent = GeneratorUtils.removeUnusedEntities(schemaSyntaxTree, clientContent, schemaContent, - serviceContent); - } + // Remove unused records and enums when generating the client and service. + schemaContent = GeneratorUtils.removeUnusedEntities(schemaSyntaxTree, clientContent, schemaContent, + serviceContent); + if (!schemaContent.isBlank()) { sourceFiles.add(new GenSrcFile(GenSrcFile.GenFileType.MODEL_SRC, srcPackage, TYPE_FILE_NAME, (licenseHeader.isBlank() ? DEFAULT_FILE_HEADER : licenseHeader) + schemaContent)); @@ -439,8 +438,10 @@ public List generateBallerinaService(Path openAPI, String serviceNam ballerinaServiceGenerator.getTypeInclusionRecords()); BallerinaTypesGenerator ballerinaSchemaGenerator = new BallerinaTypesGenerator( openAPIDef, nullable, preGeneratedTypeDefNodes); - String schemaContent = Formatter.format( - ballerinaSchemaGenerator.generateSyntaxTree()).toSourceCode(); + SyntaxTree schemaSyntaxTree = ballerinaSchemaGenerator.generateSyntaxTree(); + String schemaContent = Formatter.format(schemaSyntaxTree).toString(); + schemaContent = GeneratorUtils.removeUnusedEntities(schemaSyntaxTree, mainContent, schemaContent, + null); if (!schemaContent.isBlank() && !generateWithoutDataBinding) { sourceFiles.add(new GenSrcFile(GenSrcFile.GenFileType.GEN_SRC, srcPackage, TYPE_FILE_NAME, (licenseHeader.isBlank() ? DEFAULT_FILE_HEADER : licenseHeader) + schemaContent)); diff --git a/openapi-cli/src/test/resources/expected_gen/licenses/schema_for_both_service_client.bal b/openapi-cli/src/test/resources/expected_gen/licenses/schema_for_both_service_client.bal index d835819c6..6be0c694e 100644 --- a/openapi-cli/src/test/resources/expected_gen/licenses/schema_for_both_service_client.bal +++ b/openapi-cli/src/test/resources/expected_gen/licenses/schema_for_both_service_client.bal @@ -61,16 +61,6 @@ public type ProxyConfig record {| public type Pets Pet[]; -public type Error record { - int code; - string message; -}; - -public type Dog record { - *Pet; - boolean bark?; -}; - public type Pet record { int id; string name; diff --git a/openapi-cli/src/test/resources/expected_gen/licenses/schema_for_service.bal b/openapi-cli/src/test/resources/expected_gen/licenses/schema_for_service.bal index ac33e05a5..297819e7a 100644 --- a/openapi-cli/src/test/resources/expected_gen/licenses/schema_for_service.bal +++ b/openapi-cli/src/test/resources/expected_gen/licenses/schema_for_service.bal @@ -3,16 +3,6 @@ public type Pets Pet[]; -public type Error record { - int code; - string message; -}; - -public type Dog record { - *Pet; - boolean bark?; -}; - public type Pet record { int id; string name; diff --git a/openapi-cli/src/test/resources/expected_gen/licenses/schema_with_user_given_license.bal b/openapi-cli/src/test/resources/expected_gen/licenses/schema_with_user_given_license.bal index caa35e690..78195e3a5 100644 --- a/openapi-cli/src/test/resources/expected_gen/licenses/schema_with_user_given_license.bal +++ b/openapi-cli/src/test/resources/expected_gen/licenses/schema_with_user_given_license.bal @@ -60,16 +60,6 @@ public type ProxyConfig record {| public type Pets Pet[]; -public type Error record { - int code; - string message; -}; - -public type Dog record { - *Pet; - boolean bark?; -}; - public type Pet record { int id; string name; diff --git a/openapi-cli/src/test/resources/expected_gen/licenses/types_for_both_service_client_generations.bal b/openapi-cli/src/test/resources/expected_gen/licenses/types_for_both_service_client_generations.bal index d835819c6..6be0c694e 100644 --- a/openapi-cli/src/test/resources/expected_gen/licenses/types_for_both_service_client_generations.bal +++ b/openapi-cli/src/test/resources/expected_gen/licenses/types_for_both_service_client_generations.bal @@ -61,16 +61,6 @@ public type ProxyConfig record {| public type Pets Pet[]; -public type Error record { - int code; - string message; -}; - -public type Dog record { - *Pet; - boolean bark?; -}; - public type Pet record { int id; string name; diff --git a/openapi-cli/src/test/resources/expected_gen/petstore_schema.bal b/openapi-cli/src/test/resources/expected_gen/petstore_schema.bal index d835819c6..6be0c694e 100644 --- a/openapi-cli/src/test/resources/expected_gen/petstore_schema.bal +++ b/openapi-cli/src/test/resources/expected_gen/petstore_schema.bal @@ -61,16 +61,6 @@ public type ProxyConfig record {| public type Pets Pet[]; -public type Error record { - int code; - string message; -}; - -public type Dog record { - *Pet; - boolean bark?; -}; - public type Pet record { int id; string name; diff --git a/openapi-cli/src/test/resources/expected_gen/petstore_schema_type.bal b/openapi-cli/src/test/resources/expected_gen/petstore_schema_type.bal index d5c0d107b..aeb47b88a 100644 --- a/openapi-cli/src/test/resources/expected_gen/petstore_schema_type.bal +++ b/openapi-cli/src/test/resources/expected_gen/petstore_schema_type.bal @@ -59,8 +59,6 @@ public type ProxyConfig record {| string password = ""; |}; -public type PetArr Pet[]; - public type Pet record { int petId; string name; diff --git a/openapi-cli/src/test/resources/expected_gen/petstore_schema_with_license.bal b/openapi-cli/src/test/resources/expected_gen/petstore_schema_with_license.bal index 9a4a6e293..a5f17a6fb 100644 --- a/openapi-cli/src/test/resources/expected_gen/petstore_schema_with_license.bal +++ b/openapi-cli/src/test/resources/expected_gen/petstore_schema_with_license.bal @@ -60,16 +60,6 @@ public type ProxyConfig record {| public type Pets Pet[]; -public type Error record { - int code; - string message; -}; - -public type Dog record { - *Pet; - boolean bark?; -}; - public type Pet record { int id; string name; diff --git a/openapi-cli/src/test/resources/expected_gen/petstore_wildcard_types.bal b/openapi-cli/src/test/resources/expected_gen/petstore_wildcard_types.bal index 4a0883c4a..03b5efbe3 100644 --- a/openapi-cli/src/test/resources/expected_gen/petstore_wildcard_types.bal +++ b/openapi-cli/src/test/resources/expected_gen/petstore_wildcard_types.bal @@ -4,22 +4,3 @@ public type OkAnydata record {| *http:Ok; anydata body; |}; - -public type Pets Pet[]; - -public type Error record { - int code; - string message; -}; - -public type Dog record { - *Pet; - boolean bark?; -}; - -public type Pet record { - int id; - string name; - string tag?; - string 'type?; -}; diff --git a/openapi-cli/src/test/resources/expected_gen/without-data-binding-type.bal b/openapi-cli/src/test/resources/expected_gen/without-data-binding-type.bal new file mode 100644 index 000000000..5cb64701e --- /dev/null +++ b/openapi-cli/src/test/resources/expected_gen/without-data-binding-type.bal @@ -0,0 +1 @@ +public type Coupon string; diff --git a/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java b/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java index 923a5676e..c811b96fe 100644 --- a/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java +++ b/openapi-core/src/main/java/io/ballerina/openapi/core/GeneratorUtils.java @@ -19,8 +19,12 @@ package io.ballerina.openapi.core; import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.compiler.api.symbols.RecordFieldSymbol; +import io.ballerina.compiler.api.symbols.RecordTypeSymbol; import io.ballerina.compiler.api.symbols.Symbol; import io.ballerina.compiler.api.symbols.SymbolKind; +import io.ballerina.compiler.api.symbols.TypeDefinitionSymbol; +import io.ballerina.compiler.api.symbols.TypeDescKind; import io.ballerina.compiler.syntax.tree.AbstractNodeFactory; import io.ballerina.compiler.syntax.tree.AnnotationNode; import io.ballerina.compiler.syntax.tree.BuiltinSimpleNameReferenceNode; @@ -95,6 +99,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -890,7 +895,7 @@ public static String removeUnusedEntities(SyntaxTree schemaSyntaxTree, String cl tempSourceFiles.put(CLIENT_FILE_NAME, clientContent); tempSourceFiles.put(TYPE_FILE_NAME, schemaContent); if (serviceContent != null) { - tempSourceFiles.put(SERVICE_FILE_NAME, schemaContent); + tempSourceFiles.put(SERVICE_FILE_NAME, serviceContent); } List unusedTypeDefinitionNameList = getUnusedTypeDefinitionNameList(tempSourceFiles); while (unusedTypeDefinitionNameList.size() > 0) { @@ -998,15 +1003,23 @@ private static List getUnusedTypeDefinitionNameList(Map List unusedTypeDefinitionNameList = new ArrayList<>(); Path tmpDir = Files.createTempDirectory(".openapi-tmp" + System.nanoTime()); writeFilesTemp(srcFiles, tmpDir); - if (Files.exists(tmpDir.resolve(CLIENT_FILE_NAME)) && Files.exists(tmpDir.resolve(TYPE_FILE_NAME)) && + if ((Files.exists(tmpDir.resolve(CLIENT_FILE_NAME)) || Files.exists(tmpDir.resolve(SERVICE_FILE_NAME))) + && Files.exists(tmpDir.resolve(TYPE_FILE_NAME)) && Files.exists(tmpDir.resolve(BALLERINA_TOML))) { - SemanticModel semanticModel = getSemanticModel(tmpDir.resolve(CLIENT_FILE_NAME)); + SemanticModel semanticModel = Files.exists(tmpDir.resolve(CLIENT_FILE_NAME)) ? + getSemanticModel(tmpDir.resolve(CLIENT_FILE_NAME)) : + getSemanticModel(tmpDir.resolve(SERVICE_FILE_NAME)); List symbols = semanticModel.moduleSymbols(); for (Symbol symbol : symbols) { if (symbol.kind().equals(SymbolKind.TYPE_DEFINITION) || symbol.kind().equals(SymbolKind.ENUM)) { List references = semanticModel.references(symbol); if (references.size() == 1) { unusedTypeDefinitionNameList.add(symbol.getName().get()); + } else if (references.size() == 2) { + if (symbol.kind().equals(SymbolKind.TYPE_DEFINITION)) { + TypeDefinitionSymbol typeDef = (TypeDefinitionSymbol) symbol; + handleCyclicType(unusedTypeDefinitionNameList, typeDef); + } } } } @@ -1021,6 +1034,29 @@ private static List getUnusedTypeDefinitionNameList(Map return unusedTypeDefinitionNameList; } + private static void handleCyclicType(List unusedTypeDefinitionNameList, TypeDefinitionSymbol symbol) { + TypeDescKind typeDescKind = symbol.typeDescriptor().typeKind(); + if (typeDescKind.equals(TypeDescKind.RECORD)) { + RecordTypeSymbol recordTypeSymbol = (RecordTypeSymbol) symbol.typeDescriptor(); + Map fields = recordTypeSymbol.fieldDescriptors(); + Collection values = fields.values(); + boolean isCyclic = false; + for (RecordFieldSymbol field: values) { + if (field.typeDescriptor().getName().isPresent()) { + if (field.typeDescriptor().getName().get().trim().equals(symbol.getName().get().trim())) { + isCyclic = true; + break; + } + } + } + if (isCyclic) { + unusedTypeDefinitionNameList.add(symbol.getName().get()); + } + } + //TODO: Handle cyclic type for other ex: array after this fix + //https://github.com/ballerina-platform/ballerina-lang/issues/36442 + } + private static void writeFilesTemp(Map srcFiles, Path tmpDir) throws IOException { srcFiles.put(BALLERINA_TOML, BALLERINA_TOML_CONTENT); PrintWriter writer = null; diff --git a/openapi-integration-tests/src/test/resources/service/return/ballerina/multiple_mediatype_for_one_response_code.bal b/openapi-integration-tests/src/test/resources/service/return/ballerina/multiple_mediatype_for_one_response_code.bal index 3c3b97fdb..49b51af90 100644 --- a/openapi-integration-tests/src/test/resources/service/return/ballerina/multiple_mediatype_for_one_response_code.bal +++ b/openapi-integration-tests/src/test/resources/service/return/ballerina/multiple_mediatype_for_one_response_code.bal @@ -10,15 +10,3 @@ public type User record { string firstName?; string lastName?; }; - -public type PetForm record { - string userName; - string firstName?; - string lastName?; -}; - -public type Pet record { - string userName; - string firstName?; - string lastName?; -}; diff --git a/openapi-integration-tests/src/test/resources/service/return/ballerina/response_has_inline_record.bal b/openapi-integration-tests/src/test/resources/service/return/ballerina/response_has_inline_record.bal index d1d0e1093..a70074c01 100644 --- a/openapi-integration-tests/src/test/resources/service/return/ballerina/response_has_inline_record.bal +++ b/openapi-integration-tests/src/test/resources/service/return/ballerina/response_has_inline_record.bal @@ -5,27 +5,9 @@ public type BadRequestInline_response_400 record {| Inline_response_400 body; |}; -public type User record { - string userName; - string firstName?; - string lastName?; -}; - -public type PetForm record { - string userName; - string firstName?; - string lastName?; -}; - public type Inline_response_400 record { # The error ID. int id?; # The error name. string errorType?; }; - -public type Pet record { - string userName; - string firstName?; - string lastName?; -};