diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NimClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NimClientCodegen.java index 8e13aea833e3..35f3ff81c2d6 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NimClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/NimClientCodegen.java @@ -458,10 +458,13 @@ public class NimClientCodegen extends DefaultCodegen implements CodegenConfig { name = normalizeSchemaName(name); CodegenModel mdl = super.fromModel(name, schema); - // Detect integer enums - check both the schema type and the dataType + // Detect numeric enums - check both the schema type and the dataType + // Note: "number" type in OpenAPI can include integer values in enums if (mdl.isEnum) { String schemaType = schema != null ? schema.getType() : null; - if ("integer".equals(schemaType) || "int".equals(mdl.dataType) || "int64".equals(mdl.dataType)) { + if ("integer".equals(schemaType) || "number".equals(schemaType) || + "int".equals(mdl.dataType) || "int64".equals(mdl.dataType) || + "float".equals(mdl.dataType) || "float64".equals(mdl.dataType)) { mdl.vendorExtensions.put("x-is-integer-enum", true); } } @@ -606,22 +609,38 @@ public class NimClientCodegen extends DefaultCodegen implements CodegenConfig { return objs; } + /** + * Resolve a schema reference to its target schema. + * This is needed to properly detect nested maps/arrays when the schema is a $ref. + */ + private Schema resolveSchema(Schema schema) { + if (schema != null && schema.get$ref() != null) { + Schema resolved = ModelUtils.getReferencedSchema(this.openAPI, schema); + return resolved != null ? resolved : schema; + } + return schema; + } + @Override public String getTypeDeclaration(Schema p) { - if (ModelUtils.isArraySchema(p)) { - Schema inner = ModelUtils.getSchemaItems(p); + // Resolve the schema to check for nested maps/arrays - refs that point to map/array schemas + Schema resolved = resolveSchema(p); + + if (ModelUtils.isArraySchema(resolved)) { + Schema inner = ModelUtils.getSchemaItems(resolved); if (inner == null) { return null; } return "seq[" + getTypeDeclaration(inner) + "]"; - } else if (ModelUtils.isMapSchema(p)) { - Schema inner = ModelUtils.getAdditionalProperties(p); + } else if (ModelUtils.isMapSchema(resolved)) { + Schema inner = ModelUtils.getAdditionalProperties(resolved); if (inner == null) { inner = new StringSchema(); } return "Table[string, " + getTypeDeclaration(inner) + "]"; } + // For non-containers, use the original schema to preserve model names String schemaType = getSchemaType(p); if (typeMapping.containsKey(schemaType)) { return typeMapping.get(schemaType); @@ -719,10 +738,17 @@ public class NimClientCodegen extends DefaultCodegen implements CodegenConfig { @Override public String toEnumVarName(String name, String datatype) { + // Handle negative numbers by prefixing with "Neg" to avoid collisions + // e.g., -1 and 1 would both become `1` without this, causing invalid syntax + if (name.startsWith("-")) { + name = "Neg" + name.substring(1); + } + name = name.replace(" ", "_"); name = StringUtils.camelize(name); - // starts with number or contains any character not allowed,see + // starts with number or contains any character not allowed, see + // https://nim-lang.org/docs/manual.html#lexical-analysis-identifiers-amp-keywords if (isValidIdentifier(name)) { return name; } else { diff --git a/modules/openapi-generator/src/test/resources/3_0/nim/petstore.yaml b/modules/openapi-generator/src/test/resources/3_0/nim/petstore.yaml index 23c6f0fe4e8c..6df5edfcc430 100644 --- a/modules/openapi-generator/src/test/resources/3_0/nim/petstore.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/nim/petstore.yaml @@ -1020,3 +1020,29 @@ components: type: array items: $ref: '#/components/schemas/PetReview' + + # Test numeric enum with negative values + DigestEmailFrequency: + description: Email digest frequency with negative value for disabled + type: number + enum: [-1, 0, 1, 2] + + # Test nested maps (map of maps) + StringMap: + description: A simple string to string map + type: object + additionalProperties: + type: string + NestedStringMap: + description: A nested map (string to map of string to string) + type: object + additionalProperties: + $ref: '#/components/schemas/StringMap' + PetStatistics: + description: Statistics about a pet including nested map for health records + type: object + properties: + groomingHistory: + $ref: '#/components/schemas/StringMap' + healthRecords: + $ref: '#/components/schemas/NestedStringMap' diff --git a/samples/client/petstore/nim/.openapi-generator/FILES b/samples/client/petstore/nim/.openapi-generator/FILES index f8e488383817..83c3ca42d9c5 100644 --- a/samples/client/petstore/nim/.openapi-generator/FILES +++ b/samples/client/petstore/nim/.openapi-generator/FILES @@ -7,6 +7,7 @@ petstore/apis/api_user.nim petstore/models/model_any_type.nim petstore/models/model_api_response.nim petstore/models/model_category.nim +petstore/models/model_digest_email_frequency.nim petstore/models/model_get_pet_reviews200response.nim petstore/models/model_get_pet_reviews_response_with_presence.nim petstore/models/model_get_pet_stats200response.nim @@ -23,6 +24,7 @@ petstore/models/model_pet_positions.nim petstore/models/model_pet_priority.nim petstore/models/model_pet_review.nim petstore/models/model_pet_reviews_response.nim +petstore/models/model_pet_statistics.nim petstore/models/model_record_string_before_string_or_null_after_string_or_null_value.nim petstore/models/model_tag.nim petstore/models/model_unfavorite_pet_request.nim diff --git a/samples/client/petstore/nim/petstore.nim b/samples/client/petstore/nim/petstore.nim index 6a0b825c31d8..dee94daf948f 100644 --- a/samples/client/petstore/nim/petstore.nim +++ b/samples/client/petstore/nim/petstore.nim @@ -10,6 +10,7 @@ # Models import petstore/models/model_api_response import petstore/models/model_category +import petstore/models/model_digest_email_frequency import petstore/models/model_get_pet_reviews200response import petstore/models/model_get_pet_reviews_response_with_presence import petstore/models/model_get_pet_stats200response @@ -25,6 +26,7 @@ import petstore/models/model_pet_positions import petstore/models/model_pet_priority import petstore/models/model_pet_review import petstore/models/model_pet_reviews_response +import petstore/models/model_pet_statistics import petstore/models/model_record_string_before_string_or_null_after_string_or_null_value import petstore/models/model_tag import petstore/models/model_unfavorite_pet_request @@ -32,6 +34,7 @@ import petstore/models/model_user export model_api_response export model_category +export model_digest_email_frequency export model_get_pet_reviews200response export model_get_pet_reviews_response_with_presence export model_get_pet_stats200response @@ -47,6 +50,7 @@ export model_pet_positions export model_pet_priority export model_pet_review export model_pet_reviews_response +export model_pet_statistics export model_record_string_before_string_or_null_after_string_or_null_value export model_tag export model_unfavorite_pet_request diff --git a/samples/client/petstore/nim/petstore/models/model_digest_email_frequency.nim b/samples/client/petstore/nim/petstore/models/model_digest_email_frequency.nim new file mode 100644 index 000000000000..92eaba47ee9f --- /dev/null +++ b/samples/client/petstore/nim/petstore/models/model_digest_email_frequency.nim @@ -0,0 +1,50 @@ +# +# OpenAPI Petstore +# +# This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. +# The version of the OpenAPI document: 1.0.0 +# +# Generated by: https://openapi-generator.tech +# + +import json +import tables +import marshal +import options + + +type DigestEmailFrequency* {.pure.} = enum + Neg1 + `0` + `1` + `2` + +func `%`*(v: DigestEmailFrequency): JsonNode = + result = case v: + of DigestEmailFrequency.Neg1: %(-1) + of DigestEmailFrequency.`0`: %(0) + of DigestEmailFrequency.`1`: %(1) + of DigestEmailFrequency.`2`: %(2) + +func `$`*(v: DigestEmailFrequency): string = + result = case v: + of DigestEmailFrequency.Neg1: $(-1) + of DigestEmailFrequency.`0`: $(0) + of DigestEmailFrequency.`1`: $(1) + of DigestEmailFrequency.`2`: $(2) +proc to*(node: JsonNode, T: typedesc[DigestEmailFrequency]): DigestEmailFrequency = + if node.kind != JInt: + raise newException(ValueError, "Expected integer for enum DigestEmailFrequency, got " & $node.kind) + let intVal = node.getInt() + case intVal: + of -1: + return DigestEmailFrequency.Neg1 + of 0: + return DigestEmailFrequency.`0` + of 1: + return DigestEmailFrequency.`1` + of 2: + return DigestEmailFrequency.`2` + else: + raise newException(ValueError, "Invalid enum value for DigestEmailFrequency: " & $intVal) + diff --git a/samples/client/petstore/nim/petstore/models/model_pet_statistics.nim b/samples/client/petstore/nim/petstore/models/model_pet_statistics.nim new file mode 100644 index 000000000000..355b4c3a4fd7 --- /dev/null +++ b/samples/client/petstore/nim/petstore/models/model_pet_statistics.nim @@ -0,0 +1,20 @@ +# +# OpenAPI Petstore +# +# This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. +# The version of the OpenAPI document: 1.0.0 +# +# Generated by: https://openapi-generator.tech +# + +import json +import tables +import marshal +import options + + +type PetStatistics* = object + ## Statistics about a pet including nested map for health records + groomingHistory*: Option[Table[string, string]] ## A simple string to string map + healthRecords*: Option[Table[string, Table[string, string]]] ## A nested map (string to map of string to string) +