diff --git a/docs/generators/elixir.md b/docs/generators/elixir.md
index b13adcbad45..bc1a7a9beb8 100644
--- a/docs/generators/elixir.md
+++ b/docs/generators/elixir.md
@@ -68,9 +68,22 @@ These options may be applied as additional-properties (cli) or configOptions (pl
__ENV__
__FILE__
__MODULE__
+__struct__
+after
+and
+catch
+do
+else
+end
false
+fn
+in
nil
+not
+or
+rescue
true
+when
## FEATURE SET
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java
index 690cdb7f7ec..670029e692f 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ElixirClientCodegen.java
@@ -63,8 +63,7 @@ public class ElixirClientCodegen extends DefaultCodegen {
"{:tesla, \"~> 1.7\"}",
"{:jason, \"~> 1.4\"}",
"{:ex_doc, \"~> 0.30\", only: :dev, runtime: false}",
- "{:dialyxir, \"~> 1.3\", only: [:dev, :test], runtime: false}"
- );
+ "{:dialyxir, \"~> 1.3\", only: [:dev, :test], runtime: false}");
public ElixirClientCodegen() {
super();
@@ -73,114 +72,117 @@ public class ElixirClientCodegen extends DefaultCodegen {
.includeDocumentationFeatures(DocumentationFeature.Readme)
.securityFeatures(EnumSet.of(
SecurityFeature.OAuth2_Implicit,
- SecurityFeature.BasicAuth
- ))
+ SecurityFeature.BasicAuth))
.excludeGlobalFeatures(
GlobalFeature.XMLStructureDefinitions,
GlobalFeature.Callbacks,
GlobalFeature.LinkObjects,
- GlobalFeature.ParameterStyling
- )
+ GlobalFeature.ParameterStyling)
.excludeSchemaSupportFeatures(
- SchemaSupportFeature.Polymorphism
- )
+ SchemaSupportFeature.Polymorphism)
.excludeParameterFeatures(
- ParameterFeature.Cookie
- )
+ ParameterFeature.Cookie)
.includeClientModificationFeatures(
- ClientModificationFeature.BasePath
- )
+ ClientModificationFeature.BasePath)
.includeDataTypeFeatures(
- DataTypeFeature.AnyType
- )
- );
+ DataTypeFeature.AnyType));
// set the output folder here
outputFolder = "generated-code/elixir";
/*
- * Models. You can write model files using the modelTemplateFiles map.
+ * Models. You can write model files using the modelTemplateFiles map.
* if you want to create one template for file, you can do so here.
- * for multiple files for model, just put another entry in the `modelTemplateFiles` with
+ * for multiple files for model, just put another entry in the
+ * `modelTemplateFiles` with
* a different extension
*/
modelTemplateFiles.put(
"model.mustache", // the template to use
- ".ex"); // the extension for each file to write
+ ".ex"); // the extension for each file to write
/**
- * Api classes. You can write classes for each Api file with the apiTemplateFiles map.
- * as with models, add multiple entries with different extensions for multiple files per
+ * Api classes. You can write classes for each Api file with the
+ * apiTemplateFiles map.
+ * as with models, add multiple entries with different extensions for multiple
+ * files per
* class
*/
apiTemplateFiles.put(
- "api.mustache", // the template to use
- ".ex"); // the extension for each file to write
+ "api.mustache", // the template to use
+ ".ex"); // the extension for each file to write
/**
- * Template Location. This is the location which templates will be read from. The generator
+ * Template Location. This is the location which templates will be read from.
+ * The generator
* will use the resource stream to attempt to read the templates.
*/
templateDir = "elixir";
/**
- * Reserved words. Override this with reserved words specific to your language
- * Ref: https://github.com/itsgreggreg/elixir_quick_reference#reserved-words
+ * Reserved words. Override this with reserved words specific to your language
+ * Ref: https://hexdocs.pm/elixir/1.16.3/syntax-reference.html#reserved-words
*/
reservedWords = new HashSet<>(
Arrays.asList(
- "nil",
"true",
"false",
+ "nil",
+ "when",
+ "and",
+ "or",
+ "not",
+ "in",
+ "fn",
+ "do",
+ "end",
+ "catch",
+ "rescue",
+ "after",
+ "else",
+ "__struct__",
"__MODULE__",
"__FILE__",
"__DIR__",
"__ENV__",
- "__CALLER__")
- );
+ "__CALLER__"));
/**
- * Additional Properties. These values can be passed to the templates and
+ * Additional Properties. These values can be passed to the templates and
* are available in models, apis, and supporting files
*/
additionalProperties.put("apiVersion", apiVersion);
/**
- * Supporting Files. You can write single files for the generator with the
- * entire object tree available. If the input file has a suffix of `.mustache
- * it will be processed by the template engine. Otherwise, it will be copied
+ * Supporting Files. You can write single files for the generator with the
+ * entire object tree available. If the input file has a suffix of `.mustache
+ * it will be processed by the template engine. Otherwise, it will be copied
*/
- supportingFiles.add(new SupportingFile("README.md.mustache", // the input template or file
- "", // the destination folder, relative `outputFolder`
- "README.md") // the output file
+ supportingFiles.add(new SupportingFile("README.md.mustache", // the input template or file
+ "", // the destination folder, relative `outputFolder`
+ "README.md") // the output file
);
supportingFiles.add(new SupportingFile("config.exs.mustache",
"config",
- "config.exs")
- );
+ "config.exs"));
supportingFiles.add(new SupportingFile("runtime.exs.mustache",
"config",
- "runtime.exs")
- );
+ "runtime.exs"));
supportingFiles.add(new SupportingFile("mix.exs.mustache",
"",
- "mix.exs")
- );
+ "mix.exs"));
supportingFiles.add(new SupportingFile("formatter.exs",
"",
- ".formatter.exs")
- );
+ ".formatter.exs"));
supportingFiles.add(new SupportingFile("test_helper.exs.mustache",
"test",
- "test_helper.exs")
- );
+ "test_helper.exs"));
supportingFiles.add(new SupportingFile("gitignore.mustache",
"",
- ".gitignore")
- );
+ ".gitignore"));
/**
- * Language Specific Primitives. These types will not trigger imports by
+ * Language Specific Primitives. These types will not trigger imports by
* the client generator
*/
languageSpecificPrimitives = new HashSet<>(
@@ -196,12 +198,13 @@ public class ElixirClientCodegen extends DefaultCodegen {
"AnyType",
"Tuple",
"PID",
- "map()", // This is a workaround, since the DefaultCodeGen uses our elixir TypeSpec datetype to evaluate the primitive
- "any()"
- )
- );
+ // This is a workaround, since the DefaultCodeGen uses our elixir TypeSpec
+ // datetype to evaluate the primitive
+ "map()",
+ "any()"));
- // ref: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types
+ // ref:
+ // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types
typeMapping = new HashMap<>();
typeMapping.put("integer", "Integer");
typeMapping.put("long", "Integer");
@@ -223,7 +226,8 @@ public class ElixirClientCodegen extends DefaultCodegen {
typeMapping.put("UUID", "String");
typeMapping.put("URI", "String");
- cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE, "The main namespace to use for all classes. e.g. Yay.Pets"));
+ cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE,
+ "The main namespace to use for all classes. e.g. Yay.Pets"));
cliOptions.add(new CliOption("licenseHeader", "The license header to prepend to the top of all source files."));
cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "Elixir package name (convention: lowercase)."));
}
@@ -240,7 +244,8 @@ public class ElixirClientCodegen extends DefaultCodegen {
}
/**
- * Configures a friendly name for the generator. This will be used by the generator
+ * Configures a friendly name for the generator. This will be used by the
+ * generator
* to select the library with the -g flag.
*
* @return the friendly name for the generator
@@ -251,7 +256,7 @@ public class ElixirClientCodegen extends DefaultCodegen {
}
/**
- * Returns human-friendly help for the generator. Provide the consumer with help
+ * Returns human-friendly help for the generator. Provide the consumer with help
* tips, parameters here
*
* @return A string value for the help message
@@ -323,7 +328,6 @@ public class ElixirClientCodegen extends DefaultCodegen {
sourceFolder(),
"request_builder.ex"));
-
supportingFiles.add(new SupportingFile("deserializer.ex.mustache",
sourceFolder(),
"deserializer.ex"));
@@ -408,34 +412,39 @@ public class ElixirClientCodegen extends DefaultCodegen {
}
private String atomized(String text) {
- StringBuilder atom = new StringBuilder();
- Matcher m = simpleAtomPattern.matcher(text);
+ StringBuilder atom = new StringBuilder();
+ Matcher m = simpleAtomPattern.matcher(text);
- atom.append(":");
+ atom.append(":");
- if (!m.matches()) {
- atom.append("\"");
- }
+ if (!m.matches()) {
+ atom.append("\"");
+ }
- atom.append(text);
+ atom.append(text);
- if (!m.matches()) {
- atom.append("\"");
- }
+ if (!m.matches()) {
+ atom.append("\"");
+ }
- return atom.toString();
+ return atom.toString();
}
-
/**
- * Escapes a reserved word as defined in the `reservedWords` array. Handle escaping
- * those terms here. This logic is only called if a variable matches the reserved words
+ * Escapes a reserved word as defined in the `reservedWords` array. Handle
+ * escaping
+ * those terms here. This logic is only called if a variable matches the
+ * reserved words
*
* @return the escaped term
*/
@Override
public String escapeReservedWord(String name) {
- return "_" + name; // add an underscore to the name
+ String escapedName = name + "_var";
+
+ // Trim leading underscores in the event the name is already underscored
+ escapedName = escapedName.replaceAll("^_+", "");
+ return escapedName;
}
private String sourceFolder() {
@@ -447,7 +456,8 @@ public class ElixirClientCodegen extends DefaultCodegen {
}
/**
- * Location to write model files. You can use the modelPackage() as defined when the class is
+ * Location to write model files. You can use the modelPackage() as defined when
+ * the class is
* instantiated
*/
@Override
@@ -456,7 +466,8 @@ public class ElixirClientCodegen extends DefaultCodegen {
}
/**
- * Location to write api files. You can use the apiPackage() as defined when the class is
+ * Location to write api files. You can use the apiPackage() as defined when the
+ * class is
* instantiated
*/
@Override
@@ -529,20 +540,23 @@ public class ElixirClientCodegen extends DefaultCodegen {
@Override
public String toOperationId(String operationId) {
- // throw exception if method name is empty (should not occur as an auto-generated method name will be used)
+ // throw exception if method name is empty (should not occur as an
+ // auto-generated method name will be used)
if (StringUtils.isEmpty(operationId)) {
throw new RuntimeException("Empty method name (operationId) not allowed");
}
// method name cannot use reserved keyword, e.g. return
if (isReservedWord(operationId)) {
- LOGGER.warn("{} (reserved word) cannot be used as method name. Renamed to {}", operationId, underscore(sanitizeName("call_" + operationId)));
+ LOGGER.warn("{} (reserved word) cannot be used as method name. Renamed to {}", operationId,
+ underscore(sanitizeName("call_" + operationId)));
return underscore(sanitizeName("call_" + operationId));
}
// operationId starts with a number
if (operationId.matches("^\\d.*")) {
- LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId, underscore(sanitizeName("call_" + operationId)));
+ LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId,
+ underscore(sanitizeName("call_" + operationId)));
operationId = "call_" + operationId;
}
@@ -550,10 +564,12 @@ public class ElixirClientCodegen extends DefaultCodegen {
}
/**
- * Optional - type declaration. This is a String which is used by the templates to instantiate your
- * types. There is typically special handling for different property types
+ * Optional - type declaration. This is a String which is used by the templates
+ * to instantiate your
+ * types. There is typically special handling for different property types
*
- * @return a string value used as the `dataType` field for model templates, `returnType` for api templates
+ * @return a string value used as the `dataType` field for model templates,
+ * `returnType` for api templates
*/
@Override
public String getTypeDeclaration(Schema p) {
@@ -603,8 +619,10 @@ public class ElixirClientCodegen extends DefaultCodegen {
}
/**
- * Optional - OpenAPI type conversion. This is used to map OpenAPI types in a `Schema` into
- * either language specific types via `typeMapping` or into complex models if there is not a mapping.
+ * Optional - OpenAPI type conversion. This is used to map OpenAPI types in a
+ * `Schema` into
+ * either language specific types via `typeMapping` or into complex models if
+ * there is not a mapping.
*
* @return a string value of the type or complex model for this property
*/
@@ -801,23 +819,10 @@ public class ElixirClientCodegen extends DefaultCodegen {
if (exResponse.baseType == null) {
returnEntry.append("nil");
} else if (exResponse.containerType == null) { // not container (array, map, set)
- if (!exResponse.primitiveType) {
- returnEntry.append(moduleName);
- returnEntry.append(".Model.");
- }
-
- translateBaseType(returnEntry, exResponse.baseType);
+ returnEntry.append(normalizeTypeName(exResponse.dataType, exResponse.primitiveType));
} else {
- if (exResponse.containerType.equals("array") ||
- exResponse.containerType.equals("set")) {
- returnEntry.append("list(");
- if (!exResponse.primitiveType) {
- returnEntry.append(moduleName);
- returnEntry.append(".Model.");
- }
-
- translateBaseType(returnEntry, exResponse.baseType);
- returnEntry.append(")");
+ if (exResponse.containerType.equals("array") || exResponse.containerType.equals("set")) {
+ returnEntry.append(exResponse.dataType);
} else if (exResponse.containerType.equals("map")) {
returnEntry.append("map()");
}
@@ -833,6 +838,22 @@ public class ElixirClientCodegen extends DefaultCodegen {
return sb.toString();
}
+ private String normalizeTypeName(String baseType, boolean isPrimitive) {
+ if (baseType == null) {
+ return "nil";
+ }
+ if (isPrimitive || "String.t".equals(baseType)) {
+ return baseType;
+ }
+ if (!baseType.startsWith(moduleName + ".Model.")) {
+ baseType = moduleName + ".Model." + baseType;
+ }
+ if (!baseType.endsWith(".t")) {
+ baseType += ".t";
+ }
+ return baseType;
+ }
+
private void buildTypespec(CodegenParameter param, StringBuilder sb) {
if (param.dataType == null) {
sb.append("nil");
@@ -846,26 +867,15 @@ public class ElixirClientCodegen extends DefaultCodegen {
sb.append("%{optional(String.t) => ");
buildTypespec(param.items, sb);
sb.append("}");
- } else if (param.isPrimitiveType) {
- // like `integer()`, `String.t`
- sb.append(param.dataType);
- } else if (param.isFile || param.isBinary) {
- sb.append("String.t");
- } else if ("String.t".equals(param.dataType)) {
- // uuid, password, etc
- sb.append(param.dataType);
} else {
- // .Model..t
- sb.append(moduleName);
- sb.append(".Model.");
- sb.append(param.dataType);
- sb.append(".t");
+ sb.append(normalizeTypeName(param.dataType, param.isPrimitiveType || param.isFile || param.isBinary));
}
}
private void buildTypespec(CodegenProperty property, StringBuilder sb) {
if (property == null) {
- LOGGER.error("CodegenProperty cannot be null. Please report the issue to https://github.com/openapitools/openapi-generator with the spec");
+ LOGGER.error(
+ "CodegenProperty cannot be null. Please report the issue to https://github.com/openapitools/openapi-generator with the spec");
} else if (property.isArray) {
sb.append("list(");
buildTypespec(property.items, sb);
@@ -874,14 +884,8 @@ public class ElixirClientCodegen extends DefaultCodegen {
sb.append("%{optional(String.t) => ");
buildTypespec(property.items, sb);
sb.append("}");
- } else if (property.isPrimitiveType) {
- sb.append(property.baseType);
- sb.append(".t");
} else {
- sb.append(moduleName);
- sb.append(".Model.");
- sb.append(property.baseType);
- sb.append(".t");
+ sb.append(normalizeTypeName(property.dataType, property.isPrimitiveType));
}
}
@@ -982,6 +986,8 @@ public class ElixirClientCodegen extends DefaultCodegen {
}
@Override
- public GeneratorLanguage generatorLanguage() { return GeneratorLanguage.ELIXIR; }
+ public GeneratorLanguage generatorLanguage() {
+ return GeneratorLanguage.ELIXIR;
+ }
}
diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/api/fake.ex b/samples/client/petstore/elixir/lib/openapi_petstore/api/fake.ex
index b47e3ee8b50..a86a4160725 100644
--- a/samples/client/petstore/elixir/lib/openapi_petstore/api/fake.ex
+++ b/samples/client/petstore/elixir/lib/openapi_petstore/api/fake.ex
@@ -288,7 +288,7 @@ defmodule OpenapiPetstore.Api.Fake do
- `{:ok, nil}` on success
- `{:error, Tesla.Env.t}` on failure
"""
- @spec test_additional_properties_reference(Tesla.Env.client, %{optional(String.t) => AnyType.t}, keyword()) :: {:ok, nil} | {:error, Tesla.Env.t}
+ @spec test_additional_properties_reference(Tesla.Env.client, %{optional(String.t) => any()}, keyword()) :: {:ok, nil} | {:error, Tesla.Env.t}
def test_additional_properties_reference(connection, request_body, _opts \\ []) do
request =
%{}
diff --git a/samples/client/petstore/elixir/lib/openapi_petstore/api/pet.ex b/samples/client/petstore/elixir/lib/openapi_petstore/api/pet.ex
index edbab8e9fb5..b1360cfe35e 100644
--- a/samples/client/petstore/elixir/lib/openapi_petstore/api/pet.ex
+++ b/samples/client/petstore/elixir/lib/openapi_petstore/api/pet.ex
@@ -93,7 +93,7 @@ defmodule OpenapiPetstore.Api.Pet do
- `{:ok, [%Pet{}, ...]}` on success
- `{:error, Tesla.Env.t}` on failure
"""
- @spec find_pets_by_status(Tesla.Env.client, list(String.t), keyword()) :: {:ok, nil} | {:ok, list(OpenapiPetstore.Model.Pet.t)} | {:error, Tesla.Env.t}
+ @spec find_pets_by_status(Tesla.Env.client, list(String.t), keyword()) :: {:ok, nil} | {:ok, [OpenapiPetstore.Model.Pet.t]} | {:error, Tesla.Env.t}
def find_pets_by_status(connection, status, _opts \\ []) do
request =
%{}
@@ -125,7 +125,7 @@ defmodule OpenapiPetstore.Api.Pet do
- `{:ok, [%Pet{}, ...]}` on success
- `{:error, Tesla.Env.t}` on failure
"""
- @spec find_pets_by_tags(Tesla.Env.client, list(String.t), keyword()) :: {:ok, nil} | {:ok, list(OpenapiPetstore.Model.Pet.t)} | {:error, Tesla.Env.t}
+ @spec find_pets_by_tags(Tesla.Env.client, list(String.t), keyword()) :: {:ok, nil} | {:ok, [OpenapiPetstore.Model.Pet.t]} | {:error, Tesla.Env.t}
def find_pets_by_tags(connection, tags, _opts \\ []) do
request =
%{}