From 2cd2dc3e79d49216752a4bd68d89a6060f77441d Mon Sep 17 00:00:00 2001 From: William Cheng Date: Mon, 16 Feb 2026 01:00:54 +0800 Subject: [PATCH] minor improvements to Terraform & C++ Httplib generators --- README.md | 2 + .../languages/CppHttplibServerCodegen.java | 126 +++++++++--------- .../terraform-provider/README.mustache | 2 +- .../terraform/allof-discriminator/README.md | 2 +- .../terraform/oneof-anyof-required/README.md | 2 +- .../oneof-discriminator-lookup/README.md | 2 +- .../petstore/terraform-addpet/README.md | 2 +- .../petstore/terraform-server/README.md | 2 +- samples/client/petstore/terraform/README.md | 2 +- 9 files changed, 71 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 26b4770677ff..ae65115a97ed 100644 --- a/README.md +++ b/README.md @@ -1109,6 +1109,7 @@ Here is a list of template creators: * Swift 5: @4brunu * Swift 6: @4brunu * Swift Combine: @dydus0x14 + * Terraform: @jasondamour * TypeScript (Angular1): @mhardorf * TypeScript (Angular2): @roni-frantchi * TypeScript (Angular6): @akehir @@ -1131,6 +1132,7 @@ Here is a list of template creators: * C# Azure functions: @Abrhm7786 * C# NancyFX: @mstefaniuk * C++ (Qt5 QHttpEngine): @etherealjoy + * C++ Httplib: @rajvesh * C++ Oat++: @Kraust * C++ Pistache: @sebymiano * C++ Restbed: @stkrwork diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java index c621a9c8329f..1056c8b30eb7 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java @@ -85,8 +85,8 @@ public void preprocessOpenAPI(OpenAPI openAPI) { // Check if any security is defined in the spec boolean hasAnySecurity = (openAPI.getComponents() != null - && openAPI.getComponents().getSecuritySchemes() != null - && !openAPI.getComponents().getSecuritySchemes().isEmpty()); + && openAPI.getComponents().getSecuritySchemes() != null + && !openAPI.getComponents().getSecuritySchemes().isEmpty()); additionalProperties.put("hasAuthMethods", hasAnySecurity); // Process all paths to enhance inline schemas with meaningful titles @@ -317,8 +317,7 @@ private String getStandardIncludeForType(String typeName) { } if (cstdintTypes.contains(typeName)) { return "#include "; - } - else if (cstdintTypes.contains(mappedType)) { + } else if (cstdintTypes.contains(mappedType)) { return "#include "; } return null; @@ -398,7 +397,7 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List 0 && - Character.isUpperCase(innerType.charAt(0))) { + !innerType.startsWith("std::") && + !innerType.contains("::") && + innerType.length() > 0 && + Character.isUpperCase(innerType.charAt(0))) { modelsUsed.add(innerType); // Add namespace prefix String prefixedType = namespaceFiltered + "::" + innerType; @@ -620,16 +619,16 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List finalSuccessConstName.equals(listitem.get("constName"))); + .anyMatch(listitem -> finalSuccessConstName.equals(listitem.get("constName"))); if (!successConstExists) { Map item = new HashMap<>(); item.put("constName", successConstName); @@ -660,14 +659,14 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List finalErrorConstName.equals(listitem.get("constName"))); + .anyMatch(listitem -> finalErrorConstName.equals(listitem.get("constName"))); if (!errorConstName.isEmpty() && !errorConstExists) { Map item = new HashMap<>(); item.put("constName", errorConstName); @@ -842,14 +841,14 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List sortedModels = new ArrayList<>(modelsUsed); Collections.sort(sortedModels); objs.put("modelsUsed", new ArrayList<>(sortedModels)); objs.put("includeVariantHeader", INCLUDE_VARIANT); } - if(includeOptionalHeader) { + if (includeOptionalHeader) { objs.put("includeOptionalHeader", INCLUDE_OPTIONAL); } - return objs; + return objs; } /** @@ -1070,8 +1069,7 @@ public Map postProcessAllModels(Map objs) String headerName = toPascalCase(imp); projectHeaders.add("#include \"" + headerName + ".h\""); - } - else { + } else { String standardInclude = getStandardIncludeForType(imp); if (standardInclude != null) { systemHeaders.add(standardInclude); @@ -1245,8 +1243,8 @@ private void processModelVariable(CodegenProperty var, CodegenModel model) { if (var.isArray && var.dataType.startsWith("std::vector<")) { // Use datatypeWithEnum for enums to preserve enum type names before they're stripped String itemType = var.items != null ? - (var.items.datatypeWithEnum != null ? var.items.datatypeWithEnum : var.items.dataType) : - "std::string"; + (var.items.datatypeWithEnum != null ? var.items.datatypeWithEnum : var.items.dataType) : + "std::string"; // For inline enums in arrays, qualify with the model class name if not already qualified if (var.items != null && var.items.isEnum && !itemType.contains("::")) { @@ -1265,7 +1263,7 @@ private void processModelVariable(CodegenProperty var, CodegenModel model) { var.dataType = "std::map"; } - if(var.items !=null && "string".equals(var.items.dataType)) { + if (var.items != null && "string".equals(var.items.dataType)) { var.items.dataType = "std::string"; var.items.isPrimitiveType = true; } @@ -1280,18 +1278,17 @@ private void processModelVariable(CodegenProperty var, CodegenModel model) { // Use datatypeWithEnum which has the correct type (including enum types) var.defaultValue = var.datatypeWithEnum + "()"; } - } - else { + } else { //Handle enums - if(var.isEnum) { + if (var.isEnum) { setEnumVendorExtensions(var, model); // Check for explicit default values in schema // Base generator may auto-generate defaults which should be ignored for enums boolean hasExplicitDefault = var.defaultValue != null - && !var.defaultValue.equals("\"\"") - && !var.defaultValue.equals("null") - && !var.defaultValue.equals("0"); // Base generator default for integer types + && !var.defaultValue.equals("\"\"") + && !var.defaultValue.equals("null") + && !var.defaultValue.equals("0"); // Base generator default for integer types // Handle enum default values based on required status and schema default if (!hasExplicitDefault) { @@ -1363,14 +1360,14 @@ private void processModelVariable(CodegenProperty var, CodegenModel model) { var.vendorExtensions.put("isString", true); var.vendorExtensions.put("isPrimitive", true); } - if(var.isModel) { + if (var.isModel) { var.vendorExtensions.put("isModel", true); - if(var.defaultValue != null && var.defaultValue.startsWith("std::make_shared<")) { - var.defaultValue = var.datatypeWithEnum + "()" ; + if (var.defaultValue != null && var.defaultValue.startsWith("std::make_shared<")) { + var.defaultValue = var.datatypeWithEnum + "()"; } } } - //Handle getters and setters + //Handle getters and setters if (var.getter != null) { var.vendorExtensions.put("getter", var.getter); var.vendorExtensions.put("getterType", var.datatypeWithEnum); @@ -1706,8 +1703,8 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert if (enumName != null && !enumName.contains("::")) { // Replace std::EnumName with ClassName::EnumName property.datatypeWithEnum = property.datatypeWithEnum.replace( - "std::" + enumName, - model.classname + "::" + enumName + "std::" + enumName, + model.classname + "::" + enumName ); property.dataType = property.datatypeWithEnum; } @@ -1968,7 +1965,7 @@ public String toPascalCase(String name) { } else { // Check if part is already in PascalCase or camelCase (mixed case) boolean hasMixedCase = !part.equals(part.toLowerCase(Locale.ROOT)) && - !part.equals(part.toUpperCase(Locale.ROOT)); + !part.equals(part.toUpperCase(Locale.ROOT)); if (hasMixedCase && Character.isUpperCase(part.charAt(0))) { // Already PascalCase, keep as-is @@ -2044,8 +2041,8 @@ public String camelize(String name, boolean lowercaseFirstLetter) { public String toHandlerFunctionName(String httpMethod, String path, Boolean prefix) { String method = toPascalCase(httpMethod); String className = stripPathFromClassName(path).get("className"); - className = className.replaceAll("[^A-Za-z0-9]",""); - if(prefix) { + className = className.replaceAll("[^A-Za-z0-9]", ""); + if (prefix) { return "handle" + method + "For" + toPascalCase(className); } else { return toPascalCase(className) + method; @@ -2060,7 +2057,7 @@ public String toHandlerFunctionName(String httpMethod, String path, Boolean pref */ public String toHandlerFunctionRequest(String path, String method) { String className = stripPathFromClassName(path).get("className"); - className = className.replaceAll("[^A-Za-z0-9]",""); + className = className.replaceAll("[^A-Za-z0-9]", ""); return toPascalCase(className + toPascalCase(method) + "Request"); } @@ -2073,7 +2070,7 @@ public String toHandlerFunctionRequest(String path, String method) { */ public String toHandlerFunctionResponse(String path, String method) { String className = stripPathFromClassName(path).get("className"); - className = className.replaceAll("[^A-Za-z0-9]",""); + className = className.replaceAll("[^A-Za-z0-9]", ""); return toPascalCase(className + toPascalCase(method) + "Response"); } @@ -2100,7 +2097,7 @@ public void processOpts() { additionalProperties.put("packageName", modelPackage); additionalProperties.put("projectName", projectName); String cmakeProjectName = (String) additionalProperties.get("cmakeProjectName"); - if(cmakeProjectName == null || cmakeProjectName.isEmpty()) { + if (cmakeProjectName == null || cmakeProjectName.isEmpty()) { cmakeProjectName = (String) projectName; } additionalProperties.put("cmakeProjectName", StringUtils.underscore(cmakeProjectName)); @@ -2268,7 +2265,7 @@ private void setArrayVendorExtensions(Object varObj, String varName, String mode vendorExtensions.put("isArrayOfPrimitive", true); vendorExtensions.put("vectorFromStringHelper", varName + "VectorFromString"); vendorExtensions.put("vectorToStringHelper", varName + "VectorToString"); - } else if(items.isContainer) { + } else if (items.isContainer) { vendorExtensions.put("isArrayOfContainer", true); vendorExtensions.put("vectorFromStringHelper", varName + "VectorFromString"); vendorExtensions.put("vectorToStringHelper", varName + "VectorToString"); @@ -2281,6 +2278,7 @@ private void setArrayVendorExtensions(Object varObj, String varName, String mode vendorExtensions.put("isArrayOfPrimitive", true); } } + private void setPrimitiveTypes(Object varObj) { if (varObj == null) return; @@ -2348,12 +2346,12 @@ private void setPrimitiveTypes(Object varObj) { * This method processes enum values in a CodegenProperty and prefixes any purely numeric * enum values with an underscore. This is necessary because in C++, enum identifiers cannot * start with a digit, so numeric enum values must be transformed to valid C++ identifiers. - * + *

* For example: * - "200" becomes "_200" * - "404" becomes "_404" * - "OK" remains "OK" - * + *

* The method retrieves enum values from either the property's {@code _enum} field or from * the {@code allowableValues} map, then updates all three locations with the converted values * to maintain consistency across the property's internal state. @@ -2432,7 +2430,7 @@ private void setEnumVendorExtensions(Object varObj, CodegenModel model) { } LOGGER.debug("Processing enum for variable {}: isEnum={}, _enum={}, allowableValues={}", - var.name, var.isEnum, var._enum, var.allowableValues); + var.name, var.isEnum, var._enum, var.allowableValues); // Check if enum has UNKNOWN/UNSPECIFIED value, if not add it at the beginning boolean hasUnknownValue = false; @@ -2440,7 +2438,7 @@ private void setEnumVendorExtensions(Object varObj, CodegenModel model) { for (String enumVal : enumValues) { String upperVal = enumVal.toUpperCase(Locale.ROOT); if (upperVal.equals("UNKNOWN") || upperVal.equals("UNSPECIFIED") || - upperVal.equals("NONE") || upperVal.equals("UNDEFINED")) { + upperVal.equals("NONE") || upperVal.equals("UNDEFINED")) { hasUnknownValue = true; break; } @@ -2477,15 +2475,15 @@ private void setEnumVendorExtensions(Object varObj, CodegenModel model) { List> enumCases = new ArrayList<>(); // Iterate through original enum values to maintain mapping between C++ identifiers and original JSON values if (enumValues != null) { - for (int i = 0; i < enumValues.size(); i++) { - String originalVal = enumValues.get(i); // Original value (e.g., "200") - String convertedVal = convertedValues.get(i); // Converted C++ identifier (e.g., "_200") - Map caseMap = new HashMap<>(); - caseMap.put("name", convertedVal); // C++ enum identifier - caseMap.put("value", originalVal); // Original JSON value - caseMap.put("enumName", shortEnumName); // Use short name - enumCases.add(caseMap); - } + for (int i = 0; i < enumValues.size(); i++) { + String originalVal = enumValues.get(i); // Original value (e.g., "200") + String convertedVal = convertedValues.get(i); // Converted C++ identifier (e.g., "_200") + Map caseMap = new HashMap<>(); + caseMap.put("name", convertedVal); // C++ enum identifier + caseMap.put("value", originalVal); // Original JSON value + caseMap.put("enumName", shortEnumName); // Use short name + enumCases.add(caseMap); + } } var.vendorExtensions.put("enumCases", enumCases); @@ -2567,7 +2565,7 @@ private void processSecurityRequirements(CodegenOperation op) { public Map postProcessSupportingFileData(Map objs) { // Conditionally add AuthenticationManager file if security is defined if (additionalProperties.containsKey("hasAuthMethods") - && Boolean.TRUE.equals(additionalProperties.get("hasAuthMethods"))) { + && Boolean.TRUE.equals(additionalProperties.get("hasAuthMethods"))) { supportingFiles.add(new SupportingFile("AuthenticationManager.mustache", "api", "AuthenticationManager.h")); } return super.postProcessSupportingFileData(objs); diff --git a/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache b/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache index d154d5f9ffb4..62811bdbc974 100644 --- a/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache +++ b/modules/openapi-generator/src/main/resources/terraform-provider/README.mustache @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.22 +- [Go](https://golang.org/doc/install) >= 1.24 ## Building The Provider diff --git a/samples/client/others/terraform/allof-discriminator/README.md b/samples/client/others/terraform/allof-discriminator/README.md index cd7dee82af68..a78202656fb9 100644 --- a/samples/client/others/terraform/allof-discriminator/README.md +++ b/samples/client/others/terraform/allof-discriminator/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.22 +- [Go](https://golang.org/doc/install) >= 1.24 ## Building The Provider diff --git a/samples/client/others/terraform/oneof-anyof-required/README.md b/samples/client/others/terraform/oneof-anyof-required/README.md index fffc99f3ef06..8c151fc9bb19 100644 --- a/samples/client/others/terraform/oneof-anyof-required/README.md +++ b/samples/client/others/terraform/oneof-anyof-required/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.22 +- [Go](https://golang.org/doc/install) >= 1.24 ## Building The Provider diff --git a/samples/client/others/terraform/oneof-discriminator-lookup/README.md b/samples/client/others/terraform/oneof-discriminator-lookup/README.md index e1fd479793b6..bdfb0f51b129 100644 --- a/samples/client/others/terraform/oneof-discriminator-lookup/README.md +++ b/samples/client/others/terraform/oneof-discriminator-lookup/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.22 +- [Go](https://golang.org/doc/install) >= 1.24 ## Building The Provider diff --git a/samples/client/petstore/terraform-addpet/README.md b/samples/client/petstore/terraform-addpet/README.md index cd476b444d3d..1afe822b4725 100644 --- a/samples/client/petstore/terraform-addpet/README.md +++ b/samples/client/petstore/terraform-addpet/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.22 +- [Go](https://golang.org/doc/install) >= 1.24 ## Building The Provider diff --git a/samples/client/petstore/terraform-server/README.md b/samples/client/petstore/terraform-server/README.md index eab0fd629c1e..ab1b3ad8aa59 100644 --- a/samples/client/petstore/terraform-server/README.md +++ b/samples/client/petstore/terraform-server/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.22 +- [Go](https://golang.org/doc/install) >= 1.24 ## Building The Provider diff --git a/samples/client/petstore/terraform/README.md b/samples/client/petstore/terraform/README.md index 27ed9be64720..1f4ce90c080c 100644 --- a/samples/client/petstore/terraform/README.md +++ b/samples/client/petstore/terraform/README.md @@ -5,7 +5,7 @@ This Terraform provider was generated using [OpenAPI Generator](https://openapi- ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 1.0 -- [Go](https://golang.org/doc/install) >= 1.22 +- [Go](https://golang.org/doc/install) >= 1.24 ## Building The Provider