[haskell-http-client] fixes for fake-endpoints (#6597)

* fix compile errors / sanitization for petstore-with-fake-endpoints-models-for-testing.yaml
* correct mimetype logic
* add makefile
This commit is contained in:
Jon Schoning
2017-10-01 05:18:46 -05:00
committed by wing328
parent c32281cd02
commit 8bd7d3912b
59 changed files with 6972 additions and 2013 deletions

View File

@@ -5,7 +5,6 @@ import io.swagger.models.Model;
import io.swagger.models.ModelImpl;
import io.swagger.models.Operation;
import io.swagger.models.Swagger;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.Property;
@@ -26,12 +25,10 @@ import io.swagger.util.Json;
import java.io.IOException;
import java.io.File;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenConfig {
@@ -65,6 +62,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
static final String MEDIA_TYPE = "mediaType";
static final String MEDIA_DATA_TYPE = "x-mediaDataType";
static final String MEDIA_IS_JSON = "x-mediaIsJson";
protected Map<String, CodegenParameter> uniqueOptionalParamsByName = new HashMap<String, CodegenParameter>();
@@ -86,6 +84,8 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
}
final private static Pattern JSON_MIME_PATTERN = Pattern.compile("(?i)application/.*json(;.*)?");
public HaskellHttpClientCodegen() {
super();
@@ -120,7 +120,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
"instance", "let", "in",
"mdo", "module", "newtype",
"proc", "qualified", "rec",
"type", "where"
"type", "where", "pure", "return"
)
);
@@ -150,30 +150,33 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
"Char",
"Double",
"List",
"FilePath"
"FilePath",
"Text"
)
);
typeMapping.clear();
// typeMapping.put("array", "List");
typeMapping.put("set", "Set");
// prim
typeMapping.put("boolean", "Bool");
typeMapping.put("string", "Text");
typeMapping.put("int", "Int");
typeMapping.put("long", "Integer");
typeMapping.put("short", "Int");
typeMapping.put("char", "Char");
typeMapping.put("float", "Float");
typeMapping.put("double", "Double");
typeMapping.put("Date", "Day");
typeMapping.put("DateTime", "UTCTime");
typeMapping.put("file", "FilePath");
typeMapping.put("number", "Double");
typeMapping.put("integer", "Int");
typeMapping.put("any", "Value");
typeMapping.put("file", "FilePath");
// lib
typeMapping.put("string", "Text");
typeMapping.put("UUID", "Text");
typeMapping.put("binary", "ByteString");
typeMapping.put("ByteArray", "ByteString");
typeMapping.put("any", "A.Value");
typeMapping.put("set", "Set.Set");
// newtype
typeMapping.put("binary", "Binary");
typeMapping.put("ByteArray", "ByteArray");
typeMapping.put("date", "Date");
typeMapping.put("DateTime", "DateTime");
knownMimeDataTypes.put("application/json", "MimeJSON");
knownMimeDataTypes.put("application/xml", "MimeXML");
@@ -181,6 +184,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
knownMimeDataTypes.put("application/octet-stream", "MimeOctetStream");
knownMimeDataTypes.put("multipart/form-data", "MimeMultipartFormData");
knownMimeDataTypes.put("text/plain", "MimePlainText");
knownMimeDataTypes.put("*/*", "MimeAny");
importMapping.clear();
importMapping.put("Map", "qualified Data.Map as Map");
@@ -203,8 +207,6 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
cliOptions.add(CliOption.newBoolean(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "hides the timestamp when files were generated").defaultValue(Boolean.TRUE.toString()));
// cliOptions.add(new CliOption(MODEL_IMPORTS, "Additional imports in the Models file"));
// cliOptions.add(new CliOption(MODEL_EXTENSIONS, "Additional extensions in the Models file"));
}
public void setAllowFromJsonNulls(Boolean value) {
@@ -332,17 +334,6 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
}
// @Override
// public String apiFileFolder() {
// String apiName = (String)additionalProperties.get("title");
// return outputFolder + File.separator + "lib/" + apiName;
// }
// @Override
// public String modelFileFolder() {
// String apiName = (String)additionalProperties.get("title");
// return outputFolder + File.separator + "lib/" + apiName;
// }
@Override
public void preprocessSwagger(Swagger swagger) {
// From the title, compute a reasonable name for the package and the API
@@ -407,19 +398,6 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
additionalProperties.put("configType", apiName + "Config");
additionalProperties.put("swaggerVersion", swagger.getSwagger());
// prepend '
// List<Map<String, Object>> replacements = new ArrayList<>();
// Object[] replacementChars = specialCharReplacements.keySet().toArray();
// for (int i = 0; i < replacementChars.length; i++) {
// String c = (String) replacementChars[i];
// Map<String, Object> o = new HashMap<>();
// o.put("char", c);
// o.put("replacement", "'" + specialCharReplacements.get(c));
// o.put("hasMore", i != replacementChars.length - 1);
// replacements.add(o);
// }
// additionalProperties.put("specialCharReplacements", replacements);
//copy input swagger to output folder
try {
String swaggerJson = Json.pretty(swagger);
@@ -441,9 +419,9 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
} else if (p instanceof MapProperty) {
MapProperty mp = (MapProperty) p;
Property inner = mp.getAdditionalProperties();
return "Map.Map String " + getTypeDeclaration(inner);
return "(Map.Map String " + getTypeDeclaration(inner) + ")";
}
return fixModelChars(super.getTypeDeclaration(p));
return super.getTypeDeclaration(p);
}
@Override
@@ -451,17 +429,16 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
String swaggerType = super.getSwaggerType(p);
String type = null;
if (typeMapping.containsKey(swaggerType)) {
type = typeMapping.get(swaggerType);
if (languageSpecificPrimitives.contains(type))
return toModelName(type);
return typeMapping.get(swaggerType);
} else if (languageSpecificPrimitives.contains(type)) {
return type;
} else if (swaggerType == "object") {
type = "Value";
} else if (typeMapping.containsValue(swaggerType)) {
type = swaggerType + "_";
return "A.Value";
// } else if (typeMapping.containsValue(swaggerType)) {
// return toModelName(swaggerType) + "_";
} else {
type = swaggerType;
return toModelName(swaggerType);
}
return toModelName(type);
}
@Override
@@ -479,8 +456,6 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
} else if (p instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) p;
String inner = getSwaggerType(ap.getItems());
// Return only the inner type; the wrapping with QueryList is done
// somewhere else, where we have access to the collection format.
return inner;
} else {
return null;
@@ -493,12 +468,12 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
op.vendorExtensions.put("x-baseOperationId", op.operationId);
op.vendorExtensions.put("x-haddockPath", String.format("%s %s", op.httpMethod, op.path.replace("/", "\\/")));
op.operationId = toHsVarName(op.operationId);
op.vendorExtensions.put("x-operationType", toHsTypeName(op.operationId));
op.operationId = toVarName(op.operationId);
op.vendorExtensions.put("x-operationType", toTypeName("Op", op.operationId));
op.vendorExtensions.put("x-hasBodyOrFormParam", op.getHasBodyParam() || op.getHasFormParams());
for (CodegenParameter param : op.allParams) {
param.vendorExtensions.put("x-operationType", capitalize(op.operationId));
param.vendorExtensions.put("x-operationType", WordUtils.capitalize(op.operationId));
param.vendorExtensions.put("x-isBodyOrFormParam", param.isBodyParam || param.isFormParam);
if (!StringUtils.isBlank(param.collectionFormat)) {
param.vendorExtensions.put("x-collectionFormat", mapCollectionFormat(param.collectionFormat));
@@ -506,7 +481,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
if (!param.required) {
op.vendorExtensions.put("x-hasOptionalParams", true);
String paramNameType = capitalize(param.paramName);
String paramNameType = toTypeName("Param", param.paramName);
if (uniqueOptionalParamsByName.containsKey(paramNameType)) {
CodegenParameter lastParam = this.uniqueOptionalParamsByName.get(paramNameType);
@@ -532,7 +507,6 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
if (op.getHasPathParams()) {
String remainingPath = op.path;
for (CodegenParameter param : op.pathParams) {
param.paramName = toHsVarName(param.paramName);
String[] pieces = remainingPath.split("\\{" + param.baseName + "\\}");
if (pieces.length == 0)
throw new RuntimeException("paramName {" + param.baseName + "} not in path " + op.path);
@@ -571,7 +545,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
for (Map<String, String> m : op.consumes) {
processMediaType(op,m);
}
if (isMultipart(op.consumes)) {
if (isMultipartOperation(op.consumes)) {
op.isMultipart = Boolean.TRUE;
}
}
@@ -645,19 +619,14 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
public CodegenModel fromModel(String name, Model mod, Map<String, Model> allDefinitions) {
CodegenModel model = super.fromModel(name, mod, allDefinitions);
// Clean up the class name to remove invalid characters
model.classname = fixModelChars(model.classname);
if (typeMapping.containsValue(model.classname)) {
model.classname += "_";
}
while (uniqueOptionalParamsByName.containsKey(model.classname)) {
model.classname = generateNextName(model.classname);
}
// From the model name, compute the prefix for the fields.
String prefix = camelize(model.classname, true);
String prefix = WordUtils.uncapitalize(model.classname);
for (CodegenProperty prop : model.vars) {
prop.name = toVarName(prefix + camelize(fixOperatorChars(prop.name)));
prop.name = toVarName(prefix, prop.name);
}
//String dataOrNewtype = "data";
@@ -666,25 +635,10 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
return model;
}
// Create newtypes for things with non-object types
// String modelType = ((ModelImpl) mod).getType();
// if(modelType != "object" && typeMapping.containsKey(modelType)) {
// String newtype = typeMapping.get(modelType);
// model.vendorExtensions.put("x-customNewtype", newtype);
// }
modelNames.put(model.classname, model);
return model;
}
@Override
public CodegenParameter fromParameter(Parameter param, Set<String> imports) {
CodegenParameter p = super.fromParameter(param, imports);
p.paramName = toHsVarName(p.baseName);
p.dataType = fixModelChars(p.dataType);
return p;
}
@Override
public String escapeReservedWord(String name) {
if (this.reservedWordsMappings().containsKey(name)) {
@@ -693,13 +647,6 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
return "_" + name;
}
@Override
public String toModelFilename(String name) {
// should be the same as the model name
return toModelName(name);
}
@Override
public String escapeQuotationMark(String input) {
// remove " to avoid code injection
@@ -726,17 +673,11 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
if(StringUtils.isBlank(mediaType)) return;
String[] mediaTypeParts = mediaType.split("/",2);
if(mediaTypeParts.length > 1) {
m.put("x-mediaMainType", mediaTypeParts[0]);
m.put("x-mediaSubType", mediaTypeParts[1]);
} else {
m.put("x-mediaMainType", mediaTypeParts[0]);
m.put("x-mediaSubType", "");
}
String mimeType = getMimeDataType(mediaType);
m.put(MEDIA_DATA_TYPE, mimeType);
if (isJsonMimeType(mediaType)) {
m.put(MEDIA_IS_JSON, "true");
}
allMimeTypes.put(mediaType, m);
if(!knownMimeDataTypes.containsKey(mediaType) && !unknownMimeTypes.contains(m)) {
@@ -796,64 +737,9 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
return knownMimeDataTypes.get(mimeType);
}
String shortenedName = mimeType.replaceFirst("application/","");
return "Mime" + toHsTypeName(shortenedName);
return "Mime" + toTypeName("", shortenedName);
}
private String toHsVarName(String paramName) {
return toVarName(camelize(fixOperatorChars(fixModelChars(paramName)), true));
}
private String toHsTypeName(String paramName) {
return toHsTypeName(paramName, "");
}
private String toHsTypeName(String paramName, String modelCharReplacement) {
return camelize(fixOperatorChars(fixModelChars(paramName, modelCharReplacement)), false);
}
private String fixOperatorChars(String string) {
if(string == null) return null;
StringBuilder sb = new StringBuilder();
String name = string;
//Check if it is a reserved word, in which case the underscore is added when property name is generated.
if (string.startsWith("_")) {
if (reservedWords.contains(string.substring(1, string.length()))) {
name = string.substring(1, string.length());
} else if (reservedWordsMappings.containsValue(string)) {
name = LEADING_UNDERSCORE.matcher(string).replaceFirst("");
}
}
// prepend '
for (char c : name.toCharArray()) {
String cString = String.valueOf(c);
if (specialCharReplacements.containsKey(cString)) {
// sb.append("'");
sb.append(specialCharReplacements.get(cString));
} else {
sb.append(c);
}
}
return sb.toString();
}
// Remove characters from a string that do not belong in a model classname
private String fixModelChars(String string, String replacement) {
if(string == null) return null;
return string.replace(".", replacement).replace("-", replacement);
}
private String fixModelChars(String string) {
return fixModelChars(string, "");
}
private String capitalize(String word) {
if(word == null) return null;
if (word.length() > 0) {
word = word.substring(0, 1).toUpperCase() + word.substring(1);
}
return word;
}
private static String generateNextName(String name) {
Pattern pattern = Pattern.compile("\\d+\\z");
Matcher matcher = pattern.matcher(name);
@@ -865,7 +751,7 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
return name + "2";
}
}
private static boolean isMultipart(List<Map<String, String>> consumes) {
private static boolean isMultipartOperation(List<Map<String, String>> consumes) {
for(Map<String, String> consume : consumes) {
if (consume != null) {
if ("multipart/form-data".equals(consume.get(MEDIA_TYPE))) {
@@ -875,12 +761,58 @@ public class HaskellHttpClientCodegen extends DefaultCodegen implements CodegenC
}
return false;
}
@Override
public String toVarName(String name) {
return toVarName("", name);
}
public String toVarName(String prefix, String name) {
Boolean hasPrefix = !StringUtils.isBlank(prefix);
name = underscore(sanitizeName(name.replaceAll("-", "_")));
name = camelize(name, !hasPrefix);
if(hasPrefix) {
return prefix + name;
} else {
if (name.matches("^\\d.*"))
name = escapeReservedWord(name);
if (isReservedWord(name))
name = escapeReservedWord(name);
return name;
}
}
// private boolean isModelledType(CodegenParameter param) {
// return isModelledType(param.baseType == null ? param.dataType : param.baseType);
// }
//
// private boolean isModelledType(String typeName) {
// return !languageSpecificPrimitives.contains(typeName) && !typeMapping.values().contains(typeName);
// }
@Override
public String toParamName(String name) {
return toVarName(name);
}
@Override
public String toModelName(String name) {
return toTypeName("Model", name);
}
@Override
public String toModelFilename(String name) {
return toTypeName("Model", name);
}
public String toTypeName(String prefix, String name) {
name = camelize(underscore(sanitizeName(name)));
if(StringUtils.isBlank(prefix)) return name;
if (isReservedWord(name)) {
name = prefix + name;
}
if (name.matches("^\\d.*")) {
name = prefix + name; // e.g. 200Response => Model200Response (after camelize)
}
if (languageSpecificPrimitives.contains(name)) {
name = prefix + name;
}
if (typeMapping.containsValue(name)) {
name = prefix + name;
}
return name;
}
static boolean isJsonMimeType(String mime) {
return mime != null && JSON_MIME_PATTERN.matcher(mime).matches();
}
}