io.swagger.codegen.languages.SwiftCodegen Maven / Gradle / Ivy
package io.swagger.codegen.languages;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import io.swagger.codegen.*;
import io.swagger.models.Swagger;
import io.swagger.models.Model;
import io.swagger.models.Operation;
import io.swagger.models.parameters.HeaderParameter;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.Property;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import javax.annotation.Nullable;
import java.util.*;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Swift (2.x) generator is no longer actively maintained. Please use
* 'swift3' or 'swift4' generator instead.
*/
public class SwiftCodegen extends DefaultCodegen implements CodegenConfig {
public static final String PROJECT_NAME = "projectName";
public static final String RESPONSE_AS = "responseAs";
public static final String UNWRAP_REQUIRED = "unwrapRequired";
public static final String POD_SOURCE = "podSource";
public static final String POD_AUTHORS = "podAuthors";
public static final String POD_SOCIAL_MEDIA_URL = "podSocialMediaURL";
public static final String POD_DOCSET_URL = "podDocsetURL";
public static final String POD_LICENSE = "podLicense";
public static final String POD_HOMEPAGE = "podHomepage";
public static final String POD_SUMMARY = "podSummary";
public static final String POD_DESCRIPTION = "podDescription";
public static final String POD_SCREENSHOTS = "podScreenshots";
public static final String POD_DOCUMENTATION_URL = "podDocumentationURL";
public static final String SWIFT_USE_API_NAMESPACE = "swiftUseApiNamespace";
public static final String DEFAULT_POD_AUTHORS = "Swagger Codegen";
protected static final String LIBRARY_PROMISE_KIT = "PromiseKit";
protected static final String LIBRARY_RX_SWIFT = "RxSwift";
protected static final String[] RESPONSE_LIBRARIES = { LIBRARY_PROMISE_KIT, LIBRARY_RX_SWIFT };
protected String projectName = "SwaggerClient";
protected boolean unwrapRequired;
protected boolean swiftUseApiNamespace;
protected String[] responseAs = new String[0];
protected String sourceFolder = "Classes" + File.separator + "Swaggers";
private static final Pattern PATH_PARAM_PATTERN = Pattern.compile("\\{[a-zA-Z_]+\\}");
@Override
public CodegenType getTag() {
return CodegenType.CLIENT;
}
@Override
public String getName() {
return "swift";
}
@Override
public String getHelp() {
return "Generates a Swift (2.x) client library. IMPORTANT NOTE: this generator (swfit 2.x) is no longer actively maintained so please use 'swift3' or 'swift4' generator instead.";
}
public SwiftCodegen() {
super();
outputFolder = "generated-code" + File.separator + "swift";
modelTemplateFiles.put("model.mustache", ".swift");
apiTemplateFiles.put("api.mustache", ".swift");
embeddedTemplateDir = templateDir = "swift";
apiPackage = File.separator + "APIs";
modelPackage = File.separator + "Models";
// default HIDE_GENERATION_TIMESTAMP to true
hideGenerationTimestamp = Boolean.TRUE;
languageSpecificPrimitives = new HashSet(
Arrays.asList(
"Int",
"Int32",
"Int64",
"Float",
"Double",
"Bool",
"Void",
"String",
"Character",
"AnyObject")
);
defaultIncludes = new HashSet(
Arrays.asList(
"NSData",
"NSDate",
"NSURL", // for file
"NSUUID",
"Array",
"Dictionary",
"Set",
"Any",
"Empty",
"AnyObject")
);
reservedWords = new HashSet(
Arrays.asList(
// name used by swift client
"ErrorResponse",
// swift keywords
"Int", "Int32", "Int64", "Int64", "Float", "Double", "Bool", "Void", "String", "Character", "AnyObject",
"class", "Class", "break", "as", "associativity", "deinit", "case", "dynamicType", "convenience", "enum", "continue",
"false", "dynamic", "extension", "default", "is", "didSet", "func", "do", "nil", "final", "import", "else",
"self", "get", "init", "fallthrough", "Self", "infix", "internal", "for", "super", "inout", "let", "if",
"true", "lazy", "operator", "in", "COLUMN", "left", "private", "return", "FILE", "mutating", "protocol",
"switch", "FUNCTION", "none", "public", "where", "LINE", "nonmutating", "static", "while", "optional",
"struct", "override", "subscript", "postfix", "typealias", "precedence", "var", "prefix", "Protocol",
"required", "right", "set", "Type", "unowned", "weak", "Data")
);
typeMapping = new HashMap();
typeMapping.put("array", "Array");
typeMapping.put("List", "Array");
typeMapping.put("map", "Dictionary");
typeMapping.put("date", "ISOFullDate");
typeMapping.put("Date", "ISOFullDate");
typeMapping.put("DateTime", "NSDate");
typeMapping.put("boolean", "Bool");
typeMapping.put("string", "String");
typeMapping.put("char", "Character");
typeMapping.put("short", "Int");
typeMapping.put("int", "Int32");
typeMapping.put("long", "Int64");
typeMapping.put("integer", "Int32");
typeMapping.put("Integer", "Int32");
typeMapping.put("float", "Float");
typeMapping.put("number", "Double");
typeMapping.put("double", "Double");
typeMapping.put("object", "AnyObject");
typeMapping.put("file", "NSURL");
typeMapping.put("binary", "NSData");
typeMapping.put("ByteArray", "NSData");
typeMapping.put("UUID", "NSUUID");
importMapping = new HashMap();
cliOptions.add(new CliOption(PROJECT_NAME, "Project name in Xcode"));
cliOptions.add(new CliOption(RESPONSE_AS, "Optionally use libraries to manage response. Currently " +
StringUtils.join(RESPONSE_LIBRARIES, ", ") + " are available."));
cliOptions.add(new CliOption(UNWRAP_REQUIRED, "Treat 'required' properties in response as non-optional " +
"(which would crash the app if api returns null as opposed to required option specified in json schema"));
cliOptions.add(new CliOption(POD_SOURCE, "Source information used for Podspec"));
cliOptions.add(new CliOption(CodegenConstants.POD_VERSION, "Version used for Podspec"));
cliOptions.add(new CliOption(POD_AUTHORS, "Authors used for Podspec"));
cliOptions.add(new CliOption(POD_SOCIAL_MEDIA_URL, "Social Media URL used for Podspec"));
cliOptions.add(new CliOption(POD_DOCSET_URL, "Docset URL used for Podspec"));
cliOptions.add(new CliOption(POD_LICENSE, "License used for Podspec"));
cliOptions.add(new CliOption(POD_HOMEPAGE, "Homepage used for Podspec"));
cliOptions.add(new CliOption(POD_SUMMARY, "Summary used for Podspec"));
cliOptions.add(new CliOption(POD_DESCRIPTION, "Description used for Podspec"));
cliOptions.add(new CliOption(POD_SCREENSHOTS, "Screenshots used for Podspec"));
cliOptions.add(new CliOption(POD_DOCUMENTATION_URL, "Documentation URL used for Podspec"));
cliOptions.add(new CliOption(SWIFT_USE_API_NAMESPACE, "Flag to make all the API classes inner-class of {{projectName}}API"));
cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC)
.defaultValue(Boolean.TRUE.toString()));
}
@Override
public void processOpts() {
super.processOpts();
// Setup project name
if (additionalProperties.containsKey(PROJECT_NAME)) {
setProjectName((String) additionalProperties.get(PROJECT_NAME));
} else {
additionalProperties.put(PROJECT_NAME, projectName);
}
sourceFolder = projectName + File.separator + sourceFolder;
// Setup unwrapRequired option, which makes all the properties with "required" non-optional
if (additionalProperties.containsKey(UNWRAP_REQUIRED)) {
setUnwrapRequired(convertPropertyToBooleanAndWriteBack(UNWRAP_REQUIRED));
}
// Setup unwrapRequired option, which makes all the properties with "required" non-optional
if (additionalProperties.containsKey(RESPONSE_AS)) {
Object responseAsObject = additionalProperties.get(RESPONSE_AS);
if (responseAsObject instanceof String) {
setResponseAs(((String)responseAsObject).split(","));
} else {
setResponseAs((String[]) responseAsObject);
}
}
additionalProperties.put(RESPONSE_AS, responseAs);
if (ArrayUtils.contains(responseAs, LIBRARY_PROMISE_KIT)) {
additionalProperties.put("usePromiseKit", true);
}
if (ArrayUtils.contains(responseAs, LIBRARY_RX_SWIFT)) {
additionalProperties.put("useRxSwift", true);
}
// Setup swiftUseApiNamespace option, which makes all the API classes inner-class of {{projectName}}API
if (additionalProperties.containsKey(SWIFT_USE_API_NAMESPACE)) {
setSwiftUseApiNamespace(convertPropertyToBooleanAndWriteBack(SWIFT_USE_API_NAMESPACE));
}
if (!additionalProperties.containsKey(POD_AUTHORS)) {
additionalProperties.put(POD_AUTHORS, DEFAULT_POD_AUTHORS);
}
supportingFiles.add(new SupportingFile("Podspec.mustache", "", projectName + ".podspec"));
supportingFiles.add(new SupportingFile("Cartfile.mustache", "", "Cartfile"));
supportingFiles.add(new SupportingFile("APIHelper.mustache", sourceFolder, "APIHelper.swift"));
supportingFiles.add(new SupportingFile("AlamofireImplementations.mustache", sourceFolder,
"AlamofireImplementations.swift"));
supportingFiles.add(new SupportingFile("Extensions.mustache", sourceFolder, "Extensions.swift"));
supportingFiles.add(new SupportingFile("Models.mustache", sourceFolder, "Models.swift"));
supportingFiles.add(new SupportingFile("APIs.mustache", sourceFolder, "APIs.swift"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
}
@Override
protected boolean isReservedWord(String word) {
return word != null && reservedWords.contains(word); //don't lowercase as super does
}
@Override
public String escapeReservedWord(String name) {
if(this.reservedWordsMappings().containsKey(name)) {
return this.reservedWordsMappings().get(name);
}
return "_" + name; // add an underscore to the name
}
@Override
public String modelFileFolder() {
return outputFolder + File.separator + sourceFolder + modelPackage().replace('.', File.separatorChar);
}
@Override
public String apiFileFolder() {
return outputFolder + File.separator + sourceFolder + apiPackage().replace('.', File.separatorChar);
}
@Override
public String getTypeDeclaration(Property p) {
if (p instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) p;
Property inner = ap.getItems();
return "[" + getTypeDeclaration(inner) + "]";
} else if (p instanceof MapProperty) {
MapProperty mp = (MapProperty) p;
Property inner = mp.getAdditionalProperties();
return "[String:" + getTypeDeclaration(inner) + "]";
}
return super.getTypeDeclaration(p);
}
@Override
public String getSwaggerType(Property p) {
String swaggerType = super.getSwaggerType(p);
String type = null;
if (typeMapping.containsKey(swaggerType)) {
type = typeMapping.get(swaggerType);
if (languageSpecificPrimitives.contains(type) || defaultIncludes.contains(type))
return type;
} else
type = swaggerType;
return toModelName(type);
}
@Override
public boolean isDataTypeFile(String dataType) {
return dataType != null && dataType.equals("NSURL");
}
@Override
public boolean isDataTypeBinary(final String dataType) {
return dataType != null && dataType.equals("NSData");
}
/**
* Output the proper model name (capitalized)
*
* @param name the name of the model
* @return capitalized model name
*/
@Override
public String toModelName(String name) {
name = sanitizeName(name); // FIXME parameter should not be assigned. Also declare it as "final"
if (!StringUtils.isEmpty(modelNameSuffix)) { // set model suffix
name = name + "_" + modelNameSuffix;
}
if (!StringUtils.isEmpty(modelNamePrefix)) { // set model prefix
name = modelNamePrefix + "_" + name;
}
// camelize the model name
// phone_number => PhoneNumber
name = camelize(name);
// model name cannot use reserved keyword, e.g. return
if (isReservedWord(name)) {
String modelName = "Model" + name;
LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName);
return modelName;
}
// model name starts with number
if (name.matches("^\\d.*")) {
String modelName = "Model" + name; // e.g. 200Response => Model200Response (after camelize)
LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + modelName);
return modelName;
}
return name;
}
/**
* Return the capitalized file name of the model
*
* @param name the model name
* @return the file name of the model
*/
@Override
public String toModelFilename(String name) {
// should be the same as the model name
return toModelName(name);
}
@Override
public String toDefaultValue(Property p) {
// nil
return null;
}
@Override
public String toInstantiationType(Property p) {
if (p instanceof MapProperty) {
MapProperty ap = (MapProperty) p;
String inner = getSwaggerType(ap.getAdditionalProperties());
return "[String:" + inner + "]";
} else if (p instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) p;
String inner = getSwaggerType(ap.getItems());
return "[" + inner + "]";
}
return null;
}
@Override
public CodegenProperty fromProperty(String name, Property p) {
CodegenProperty codegenProperty = super.fromProperty(name, p);
// TODO skip array/map of enum for the time being,
// we need to add logic here to handle array/map of enum for any
// dimensions
if (Boolean.TRUE.equals(codegenProperty.isContainer)) {
return codegenProperty;
}
if (codegenProperty.isEnum) {
List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy