forked from loafle/openapi-generator-original
[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:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user