Added support for enums in Dart. (#6516)

* Added support for enums in Dart.

* Pick non-private names for enum values.

The _ prefix denotes a private member in Dart, so avoid generating enum values starting with this character.

* Properly encode enum values into query paramters.

* Various cleanups.

* Add support for x-enum-values extension.
Use class instead of enum for better ergonomy.
Better generated enum names.

* Fixed test.

* Support enum descriptions.
This commit is contained in:
P.Y. Laligand
2017-10-16 06:28:21 -07:00
committed by wing328
parent 8b70f24371
commit 1050aa9a06
20 changed files with 234 additions and 52 deletions

View File

@@ -3,27 +3,35 @@ package io.swagger.codegen.languages;
import io.swagger.codegen.CliOption;
import io.swagger.codegen.CodegenConfig;
import io.swagger.codegen.CodegenConstants;
import io.swagger.codegen.CodegenModel;
import io.swagger.codegen.CodegenProperty;
import io.swagger.codegen.CodegenType;
import io.swagger.codegen.DefaultCodegen;
import io.swagger.codegen.SupportingFile;
import io.swagger.models.Model;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.Property;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
public static final String BROWSER_CLIENT = "browserClient";
public static final String PUB_NAME = "pubName";
public static final String PUB_VERSION = "pubVersion";
public static final String PUB_DESCRIPTION = "pubDescription";
public static final String USE_ENUM_EXTENSION = "useEnumExtension";
protected boolean browserClient = true;
protected String pubName = "swagger";
protected String pubVersion = "1.0.0";
protected String pubDescription = "Swagger API client";
protected boolean useEnumExtension = false;
protected String sourceFolder = "";
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
@@ -95,6 +103,7 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
cliOptions.add(new CliOption(PUB_NAME, "Name in generated pubspec"));
cliOptions.add(new CliOption(PUB_VERSION, "Version in generated pubspec"));
cliOptions.add(new CliOption(PUB_DESCRIPTION, "Description in generated pubspec"));
cliOptions.add(new CliOption(USE_ENUM_EXTENSION, "Allow the 'x-enum-values' extension for enums"));
cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, "source folder for generated code"));
}
@@ -145,6 +154,13 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
additionalProperties.put(PUB_DESCRIPTION, pubDescription);
}
if (additionalProperties.containsKey(USE_ENUM_EXTENSION)) {
this.setUseEnumExtension(convertPropertyToBooleanAndWriteBack(USE_ENUM_EXTENSION));
} else {
// Not set, use to be passed to template.
additionalProperties.put(USE_ENUM_EXTENSION, useEnumExtension);
}
if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) {
this.setSourceFolder((String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER));
}
@@ -177,16 +193,11 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
}
@Override
public String escapeReservedWord(String name) {
if(this.reservedWordsMappings().containsKey(name)) {
return this.reservedWordsMappings().get(name);
}
return "_" + name;
public String escapeReservedWord(String name) {
return name + "_";
}
@Override
@@ -223,8 +234,11 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
// pet_id => petId
name = camelize(name, true);
// for reserved word or word starting with number, append _
if (isReservedWord(name) || name.matches("^\\d.*")) {
if (name.matches("^\\d.*")) {
name = "n" + name;
}
if (isReservedWord(name)) {
name = escapeReservedWord(name);
}
@@ -300,6 +314,117 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
return toModelName(type);
}
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
return postProcessModelsEnum(objs);
}
@Override
public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
List<Object> models = (List<Object>) objs.get("models");
for (Object _mo : models) {
Map<String, Object> mo = (Map<String, Object>) _mo;
CodegenModel cm = (CodegenModel) mo.get("model");
boolean succes = buildEnumFromVendorExtension(cm) ||
buildEnumFromValues(cm);
for (CodegenProperty var : cm.vars) {
updateCodegenPropertyEnum(var);
}
}
return objs;
}
/**
* Builds the set of enum members from their declared value.
*
* @return {@code true} if the enum was built
*/
private boolean buildEnumFromValues(CodegenModel cm) {
if (!cm.isEnum || cm.allowableValues == null) {
return false;
}
Map<String, Object> allowableValues = cm.allowableValues;
List<Object> values = (List<Object>) allowableValues.get("values");
List<Map<String, String>> enumVars =
new ArrayList<Map<String, String>>();
String commonPrefix = findCommonPrefixOfVars(values);
int truncateIdx = commonPrefix.length();
for (Object value : values) {
Map<String, String> enumVar = new HashMap<String, String>();
String enumName;
if (truncateIdx == 0) {
enumName = value.toString();
} else {
enumName = value.toString().substring(truncateIdx);
if ("".equals(enumName)) {
enumName = value.toString();
}
}
enumVar.put("name", toEnumVarName(enumName, cm.dataType));
enumVar.put("value", toEnumValue(value.toString(), cm.dataType));
enumVars.add(enumVar);
}
cm.allowableValues.put("enumVars", enumVars);
return true;
}
/**
* Builds the set of enum members from a vendor extension.
*
* @return {@code true} if the enum was built
*/
private boolean buildEnumFromVendorExtension(CodegenModel cm) {
if (!cm.isEnum || cm.allowableValues == null ||
!useEnumExtension ||
!cm.vendorExtensions.containsKey("x-enum-values")) {
return false;
}
Object extension = cm.vendorExtensions.get("x-enum-values");
List<Map<String, Object>> values =
(List<Map<String, Object>>) extension;
List<Map<String, String>> enumVars =
new ArrayList<Map<String, String>>();
for (Map<String, Object> value : values) {
Map<String, String> enumVar = new HashMap<String, String>();
String name = camelize((String) value.get("identifier"), true);
if (isReservedWord(name)) {
name = escapeReservedWord(name);
}
enumVar.put("name", name);
enumVar.put("value", toEnumValue(
value.get("numericValue").toString(), cm.dataType));
if (value.containsKey("description")) {
enumVar.put("description", value.get("description").toString());
}
enumVars.add(enumVar);
}
cm.allowableValues.put("enumVars", enumVars);
return true;
}
@Override
public String toEnumVarName(String value, String datatype) {
if (value.length() == 0) {
return "empty";
}
String var = value.replaceAll("\\W+", "_");
if ("number".equalsIgnoreCase(datatype) ||
"int".equalsIgnoreCase(datatype)) {
var = "Number" + var;
}
return escapeReservedWord(camelize(var, true));
}
@Override
public String toEnumValue(String value, String datatype) {
if ("number".equalsIgnoreCase(datatype) ||
"int".equalsIgnoreCase(datatype)) {
return value;
} else {
return "\"" + escapeText(value) + "\"";
}
}
@Override
public String toOperationId(String operationId) {
// method name cannot use reserved keyword, e.g. return
@@ -328,6 +453,10 @@ public class DartClientCodegen extends DefaultCodegen implements CodegenConfig {
this.pubDescription = pubDescription;
}
public void setUseEnumExtension(boolean useEnumExtension) {
this.useEnumExtension = useEnumExtension;
}
public void setSourceFolder(String sourceFolder) {
this.sourceFolder = sourceFolder;
}