Fix, tests for Issue #2258 "[JavaScript] Generator options and template improvements"

This commit is contained in:
demonfiddler
2016-03-17 11:02:15 +00:00
parent ca093e5aaa
commit 9511425019
13 changed files with 1648 additions and 302 deletions

View File

@@ -6,20 +6,35 @@ import java.util.*;
public class CodegenModel {
public String parent, parentSchema;
public List<String> interfaces;
// References to parent and interface CodegenModels. Only set when code generator supports inheritance.
public CodegenModel parentModel;
public List<CodegenModel> interfaceModels;
public String name, classname, description, classVarName, modelJson, dataType;
public String classFilename; // store the class file name, mainly used for import
public String unescapedDescription;
public String discriminator;
public String defaultValue;
public List<CodegenProperty> vars = new ArrayList<CodegenProperty>();
public List<CodegenProperty> allVars;
public List<String> allowableValues;
// list of all required parameters
public Set<String> mandatory = new HashSet<String>();
// Sorted sets of required parameters.
public Set<String> mandatory = new TreeSet<String>();
public Set<String> allMandatory;
public Set<String> imports = new TreeSet<String>();
public Boolean hasVars, emptyVars, hasMoreModels, hasEnums, isEnum;
public ExternalDocs externalDocs;
public Map<String, Object> vendorExtensions;
{
// By default these are the same collections. Where the code generator supports inheritance, composed models
// store the complete closure of owned and inherited properties in allVars and allMandatory.
allVars = vars;
allMandatory = mandatory;
}
}

View File

@@ -45,9 +45,12 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -124,8 +127,36 @@ public class DefaultCodegen {
}
// override with any special post-processing for all models
@SuppressWarnings("static-method")
@SuppressWarnings({ "static-method", "unchecked" })
public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
if (supportsInheritance) {
// Index all CodegenModels by name.
Map<String, CodegenModel> allModels = new HashMap<String, CodegenModel>();
for (Entry<String, Object> entry : objs.entrySet()) {
String modelName = entry.getKey();
Map<String, Object> inner = (Map<String, Object>) entry.getValue();
List<Map<String, Object>> models = (List<Map<String, Object>>) inner.get("models");
for (Map<String, Object> mo : models) {
CodegenModel cm = (CodegenModel) mo.get("model");
allModels.put(modelName, cm);
}
}
// Fix up all parent and interface CodegenModel references.
for (CodegenModel cm : allModels.values()) {
if (cm.parent != null) {
cm.parentModel = allModels.get(cm.parent);
}
if (cm.interfaces != null && !cm.interfaces.isEmpty()) {
cm.interfaceModels = new ArrayList<CodegenModel>(cm.interfaces.size());
for (String intf : cm.interfaces) {
CodegenModel intfModel = allModels.get(intf);
if (intfModel != null) {
cm.interfaceModels.add(intfModel);
}
}
}
}
}
return objs;
}
@@ -945,8 +976,18 @@ public class DefaultCodegen {
// TODO
} else if (model instanceof ComposedModel) {
final ComposedModel composed = (ComposedModel) model;
Map<String, Property> properties = new HashMap<String, Property>();
Map<String, Property> properties = new LinkedHashMap<String, Property>();
List<String> required = new ArrayList<String>();
Map<String, Property> allProperties;
List<String> allRequired;
if (supportsInheritance) {
allProperties = new LinkedHashMap<String, Property>();
allRequired = new ArrayList<String>();
m.allVars = new ArrayList<CodegenProperty>();
} else {
allProperties = null;
allRequired = null;
}
// parent model
final RefModel parent = (RefModel) composed.getParent();
if (parent != null) {
@@ -954,31 +995,29 @@ public class DefaultCodegen {
m.parentSchema = parentRef;
m.parent = toModelName(parent.getSimpleRef());
addImport(m, m.parent);
if (!supportsInheritance && allDefinitions != null) {
if (allDefinitions != null) {
final Model parentModel = allDefinitions.get(m.parentSchema);
if (parentModel instanceof ModelImpl) {
final ModelImpl _parent = (ModelImpl) parentModel;
if (_parent.getProperties() != null) {
properties.putAll(_parent.getProperties());
}
if (_parent.getRequired() != null) {
required.addAll(_parent.getRequired());
}
if (supportsInheritance) {
addProperties(allProperties, allRequired, parentModel, allDefinitions);
} else {
addProperties(properties, required, parentModel, allDefinitions);
}
}
}
// interfaces (intermediate models)
if (allDefinitions != null && composed.getInterfaces() != null) {
if (composed.getInterfaces() != null) {
if (m.interfaces == null)
m.interfaces = new ArrayList<String>();
for (RefModel _interface : composed.getInterfaces()) {
final String interfaceRef = toModelName(_interface.getSimpleRef());
final Model interfaceModel = allDefinitions.get(interfaceRef);
if (interfaceModel instanceof ModelImpl) {
final ModelImpl _interfaceModel = (ModelImpl) interfaceModel;
if (_interfaceModel.getProperties() != null) {
properties.putAll(_interfaceModel.getProperties());
}
if (_interfaceModel.getRequired() != null) {
required.addAll(_interfaceModel.getRequired());
m.interfaces.add(interfaceRef);
addImport(m, interfaceRef);
if (allDefinitions != null) {
final Model interfaceModel = allDefinitions.get(interfaceRef);
if (supportsInheritance) {
addProperties(allProperties, allRequired, interfaceModel, allDefinitions);
} else {
addProperties(properties, required, interfaceModel, allDefinitions);
}
}
}
@@ -990,15 +1029,12 @@ public class DefaultCodegen {
child = allDefinitions.get(childRef);
}
if (child != null && child instanceof ModelImpl) {
final ModelImpl _child = (ModelImpl) child;
if (_child.getProperties() != null) {
properties.putAll(_child.getProperties());
}
if (_child.getRequired() != null) {
required.addAll(_child.getRequired());
addProperties(properties, required, child, allDefinitions);
if (supportsInheritance) {
addProperties(allProperties, allRequired, child, allDefinitions);
}
}
addVars(m, properties, required);
addVars(m, properties, required, allProperties, allRequired);
} else {
ModelImpl impl = (ModelImpl) model;
if(impl.getEnum() != null && impl.getEnum().size() > 0) {
@@ -1014,7 +1050,7 @@ public class DefaultCodegen {
addVars(m, impl.getProperties(), impl.getRequired());
}
if(m.vars != null) {
if (m.vars != null) {
for(CodegenProperty prop : m.vars) {
postProcessModelProperty(m, prop);
}
@@ -1022,6 +1058,28 @@ public class DefaultCodegen {
return m;
}
protected void addProperties(Map<String, Property> properties, List<String> required, Model model,
Map<String, Model> allDefinitions) {
if (model instanceof ModelImpl) {
ModelImpl mi = (ModelImpl) model;
if (mi.getProperties() != null) {
properties.putAll(mi.getProperties());
}
if (mi.getRequired() != null) {
required.addAll(mi.getRequired());
}
} else if (model instanceof RefModel) {
String interfaceRef = toModelName(((RefModel) model).getSimpleRef());
Model interfaceModel = allDefinitions.get(interfaceRef);
addProperties(properties, required, interfaceModel, allDefinitions);
} else if (model instanceof ComposedModel) {
for (Model component :((ComposedModel) model).getAllOf()) {
addProperties(properties, required, component, allDefinitions);
}
}
}
/**
* Camelize the method name of the getter and setter
*
@@ -1263,6 +1321,7 @@ public class DefaultCodegen {
property.containerType = "map";
MapProperty ap = (MapProperty) p;
CodegenProperty cp = fromProperty("inner", ap.getAdditionalProperties());
property.items = cp;
property.baseType = getSwaggerType(p);
if (!languageSpecificPrimitives.contains(cp.baseType)) {
@@ -2157,45 +2216,65 @@ public class DefaultCodegen {
}
}
private void addVars(CodegenModel m, Map<String, Property> properties, Collection<String> required) {
if (properties != null && properties.size() > 0) {
private void addVars(CodegenModel m, Map<String, Property> properties, List<String> required) {
addVars(m, properties, required, null, null);
}
private void addVars(CodegenModel m, Map<String, Property> properties, List<String> required,
Map<String, Property> allProperties, List<String> allRequired) {
if (properties != null && !properties.isEmpty()) {
m.hasVars = true;
m.hasEnums = false;
final int totalCount = properties.size();
final Set<String> mandatory = required == null ? Collections.<String>emptySet() : new HashSet<String>(required);
int count = 0;
for (Map.Entry<String, Property> entry : properties.entrySet()) {
final String key = entry.getKey();
final Property prop = entry.getValue();
if (prop == null) {
LOGGER.warn("null property for " + key);
} else {
final CodegenProperty cp = fromProperty(key, prop);
cp.required = mandatory.contains(key) ? true : null;
if (cp.isEnum) {
m.hasEnums = true;
}
count += 1;
if (count != totalCount) {
cp.hasMore = true;
}
if (cp.isContainer != null) {
addImport(m, typeMapping.get("array"));
}
addImport(m, cp.baseType);
addImport(m, cp.complexType);
m.vars.add(cp);
}
}
m.mandatory = mandatory;
Set<String> mandatory = required == null ? Collections.<String> emptySet()
: new TreeSet<String>(required);
addVars(m, m.vars, properties, mandatory);
m.allMandatory = m.mandatory = mandatory;
} else {
m.emptyVars = true;
m.hasVars = false;
m.hasEnums = false;
}
if (allProperties != null) {
Set<String> allMandatory = allRequired == null ? Collections.<String> emptySet()
: new TreeSet<String>(allRequired);
addVars(m, m.allVars, allProperties, allMandatory);
m.allMandatory = allMandatory;
}
}
private void addVars(CodegenModel m, List<CodegenProperty> vars, Map<String, Property> properties, Set<String> mandatory) {
final int totalCount = properties.size();
int count = 0;
for (Map.Entry<String, Property> entry : properties.entrySet()) {
final String key = entry.getKey();
final Property prop = entry.getValue();
if (prop == null) {
LOGGER.warn("null property for " + key);
} else {
final CodegenProperty cp = fromProperty(key, prop);
cp.required = mandatory.contains(key) ? true : null;
if (cp.isEnum) {
// FIXME: if supporting inheritance, when called a second time for allProperties it is possible for
// m.hasEnums to be set incorrectly if allProperties has enumerations but properties does not.
m.hasEnums = true;
}
count++;
if (count != totalCount) {
cp.hasMore = true;
}
if (cp.isContainer != null) {
addImport(m, typeMapping.get("array"));
}
addImport(m, cp.baseType);
addImport(m, cp.complexType);
vars.add(cp);
}
}
}
/**

View File

@@ -47,23 +47,27 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
@SuppressWarnings("hiding")
private static final Logger LOGGER = LoggerFactory.getLogger(JavascriptClientCodegen.class);
private static final String PROJECT_NAME = "projectName";
private static final String MODULE_NAME = "moduleName";
private static final String PROJECT_DESCRIPTION = "projectDescription";
private static final String PROJECT_VERSION = "projectVersion";
private static final String PROJECT_LICENSE_NAME = "projectLicenseName";
private static final String USE_PROMISES = "usePromises";
private static final String OMIT_MODEL_METHODS = "omitModelMethods";
public static final String PROJECT_NAME = "projectName";
public static final String MODULE_NAME = "moduleName";
public static final String PROJECT_DESCRIPTION = "projectDescription";
public static final String PROJECT_VERSION = "projectVersion";
public static final String PROJECT_LICENSE_NAME = "projectLicenseName";
public static final String USE_PROMISES = "usePromises";
public static final String USE_INHERITANCE = "useInheritance";
public static final String EMIT_MODEL_METHODS = "emitModelMethods";
public static final String EMIT_JS_DOC = "emitJSDoc";
protected String projectName;
protected String moduleName;
protected String projectDescription;
protected String projectVersion;
protected String projectLicenseName;
protected String sourceFolder = "src";
protected String localVariablePrefix = "";
protected boolean usePromises = false;
protected boolean omitModelMethods = false;
protected boolean usePromises;
protected boolean emitModelMethods;
protected boolean emitJSDoc = true;
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";
@@ -105,8 +109,36 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
);
defaultIncludes = new HashSet<String>(languageSpecificPrimitives);
instantiationTypes.put("array", "Array");
instantiationTypes.put("list", "Array");
instantiationTypes.put("map", "Object");
typeMapping.clear();
typeMapping.put("array", "Array");
typeMapping.put("map", "Object");
typeMapping.put("List", "Array");
typeMapping.put("boolean", "Boolean");
typeMapping.put("string", "String");
typeMapping.put("int", "Integer"); // Huh? What is JS Integer?
typeMapping.put("float", "Number");
typeMapping.put("number", "Number");
typeMapping.put("DateTime", "Date"); // Should this be dateTime?
typeMapping.put("Date", "Date"); // Should this be date?
typeMapping.put("long", "Integer");
typeMapping.put("short", "Integer");
typeMapping.put("char", "String");
typeMapping.put("double", "Number");
typeMapping.put("object", "Object");
typeMapping.put("integer", "Integer");
// binary not supported in JavaScript client right now, using String as a workaround
typeMapping.put("ByteArray", "String"); // I don't see ByteArray defined in the Swagger docs.
typeMapping.put("binary", "String");
importMapping.clear();
cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC).defaultValue("src"));
cliOptions.add(new CliOption(CodegenConstants.LOCAL_VARIABLE_PREFIX, CodegenConstants.LOCAL_VARIABLE_PREFIX_DESC));
cliOptions.add(new CliOption(CodegenConstants.API_PACKAGE, CodegenConstants.API_PACKAGE_DESC));
cliOptions.add(new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC));
cliOptions.add(new CliOption(PROJECT_NAME,
"name of the project (Default: generated from info.title or \"swagger-js-client\")"));
cliOptions.add(new CliOption(MODULE_NAME,
@@ -120,9 +152,15 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
cliOptions.add(new CliOption(USE_PROMISES,
"use Promises as return values from the client API, instead of superagent callbacks")
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(OMIT_MODEL_METHODS,
"omits generation of getters and setters for model classes")
cliOptions.add(new CliOption(EMIT_MODEL_METHODS,
"generate getters and setters for model properties")
.defaultValue(Boolean.FALSE.toString()));
cliOptions.add(new CliOption(EMIT_JS_DOC,
"generate JSDoc comments")
.defaultValue(Boolean.TRUE.toString()));
cliOptions.add(new CliOption(USE_INHERITANCE,
"use JavaScript prototype chains & delegation for inheritance")
.defaultValue(Boolean.TRUE.toString()));
}
@Override
@@ -144,59 +182,47 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
public void processOpts() {
super.processOpts();
typeMapping = new HashMap<String, String>();
typeMapping.put("array", "Array");
typeMapping.put("List", "Array");
typeMapping.put("map", "Object");
typeMapping.put("object", "Object");
typeMapping.put("boolean", "Boolean");
typeMapping.put("char", "String");
typeMapping.put("string", "String");
typeMapping.put("short", "Integer");
typeMapping.put("int", "Integer");
typeMapping.put("integer", "Integer");
typeMapping.put("long", "Integer");
typeMapping.put("float", "Number");
typeMapping.put("double", "Number");
typeMapping.put("number", "Number");
typeMapping.put("DateTime", "Date");
typeMapping.put("Date", "Date");
typeMapping.put("file", "File");
// binary not supported in JavaScript client right now, using String as a workaround
typeMapping.put("binary", "String");
importMapping.clear();
if (additionalProperties.containsKey(PROJECT_NAME)) {
setProjectName(((String) additionalProperties.get(PROJECT_NAME)));
}
if (additionalProperties.containsKey(MODULE_NAME)) {
setModuleName(((String) additionalProperties.get(MODULE_NAME)));
}
if (additionalProperties.containsKey(PROJECT_DESCRIPTION)) {
setProjectDescription(((String) additionalProperties.get(PROJECT_DESCRIPTION)));
}
if (additionalProperties.containsKey(PROJECT_VERSION)) {
setProjectVersion(((String) additionalProperties.get(PROJECT_VERSION)));
}
if (additionalProperties.containsKey(PROJECT_LICENSE_NAME)) {
setProjectLicenseName(((String) additionalProperties.get(PROJECT_LICENSE_NAME)));
}
if (additionalProperties.containsKey(CodegenConstants.LOCAL_VARIABLE_PREFIX)) {
setLocalVariablePrefix((String) additionalProperties.get(CodegenConstants.LOCAL_VARIABLE_PREFIX));
}
if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) {
setSourceFolder((String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER));
}
if (additionalProperties.containsKey(USE_PROMISES)) {
setUsePromises(Boolean.parseBoolean((String)additionalProperties.get(USE_PROMISES)));
}
if (additionalProperties.containsKey(USE_INHERITANCE)) {
setUseInheritance(Boolean.parseBoolean((String)additionalProperties.get(USE_INHERITANCE)));
} else {
supportsInheritance = true;
}
if (additionalProperties.containsKey(EMIT_MODEL_METHODS)) {
setEmitModelMethods(Boolean.parseBoolean((String)additionalProperties.get(EMIT_MODEL_METHODS)));
}
if (additionalProperties.containsKey(EMIT_JS_DOC)) {
setEmitJSDoc(Boolean.parseBoolean((String)additionalProperties.get(EMIT_JS_DOC)));
}
}
@Override
public void preprocessSwagger(Swagger swagger) {
super.preprocessSwagger(swagger);
if (additionalProperties.containsKey(PROJECT_NAME)) {
projectName = ((String) additionalProperties.get(PROJECT_NAME));
}
if (additionalProperties.containsKey(MODULE_NAME)) {
moduleName = ((String) additionalProperties.get(MODULE_NAME));
}
if (additionalProperties.containsKey(PROJECT_DESCRIPTION)) {
projectDescription = ((String) additionalProperties.get(PROJECT_DESCRIPTION));
}
if (additionalProperties.containsKey(PROJECT_VERSION)) {
projectVersion = ((String) additionalProperties.get(PROJECT_VERSION));
}
if (additionalProperties.containsKey(CodegenConstants.LOCAL_VARIABLE_PREFIX)) {
localVariablePrefix = (String) additionalProperties.get(CodegenConstants.LOCAL_VARIABLE_PREFIX);
}
if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) {
sourceFolder = (String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER);
}
if (additionalProperties.containsKey(USE_PROMISES)) {
usePromises = Boolean.parseBoolean((String)additionalProperties.get(USE_PROMISES));
}
if (additionalProperties.containsKey(OMIT_MODEL_METHODS)) {
omitModelMethods = Boolean.parseBoolean((String)additionalProperties.get(OMIT_MODEL_METHODS));
}
if (swagger.getInfo() != null) {
Info info = swagger.getInfo();
if (StringUtils.isBlank(projectName) && info.getTitle() != null) {
@@ -211,9 +237,10 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
// when projectDescription is not specified, use info.description
projectDescription = info.getDescription();
}
if (info.getLicense() != null) {
License license = info.getLicense();
if (additionalProperties.get(PROJECT_LICENSE_NAME) == null) {
if (additionalProperties.get(PROJECT_LICENSE_NAME) == null) {
// when projectLicense is not specified, use info.license
if (info.getLicense() != null) {
License license = info.getLicense();
additionalProperties.put(PROJECT_LICENSE_NAME, license.getName());
}
}
@@ -237,10 +264,14 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
additionalProperties.put(MODULE_NAME, moduleName);
additionalProperties.put(PROJECT_DESCRIPTION, escapeText(projectDescription));
additionalProperties.put(PROJECT_VERSION, projectVersion);
additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage);
additionalProperties.put(CodegenConstants.LOCAL_VARIABLE_PREFIX, localVariablePrefix);
additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage);
additionalProperties.put(CodegenConstants.SOURCE_FOLDER, sourceFolder);
additionalProperties.put(USE_PROMISES, usePromises);
additionalProperties.put(OMIT_MODEL_METHODS, omitModelMethods);
additionalProperties.put(USE_INHERITANCE, supportsInheritance);
additionalProperties.put(EMIT_MODEL_METHODS, emitModelMethods);
additionalProperties.put(EMIT_JS_DOC, emitJSDoc);
// make api and model doc path available in mustache template
additionalProperties.put("apiDocPath", apiDocPath);
@@ -260,12 +291,56 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
@Override
public String apiFileFolder() {
return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar);
return outputFolder + '/' + sourceFolder + '/' + apiPackage().replace('.', '/');
}
@Override
public String modelFileFolder() {
return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar);
return outputFolder + '/' + sourceFolder + '/' + modelPackage().replace('.', '/');
}
public void setSourceFolder(String sourceFolder) {
this.sourceFolder = sourceFolder;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public void setLocalVariablePrefix(String localVariablePrefix) {
this.localVariablePrefix = localVariablePrefix;
}
public void setModuleName(String moduleName) {
this.moduleName = moduleName;
}
public void setProjectDescription(String projectDescription) {
this.projectDescription = projectDescription;
}
public void setProjectVersion(String projectVersion) {
this.projectVersion = projectVersion;
}
public void setProjectLicenseName(String projectLicenseName) {
this.projectLicenseName = projectLicenseName;
}
public void setUsePromises(boolean usePromises) {
this.usePromises = usePromises;
}
public void setUseInheritance(boolean useInheritance) {
this.supportsInheritance = useInheritance;
}
public void setEmitModelMethods(boolean emitModelMethods) {
this.emitModelMethods = emitModelMethods;
}
public void setEmitJSDoc(boolean emitJSDoc) {
this.emitJSDoc = emitJSDoc;
}
@Override
@@ -607,6 +682,92 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
return codegenModel;
}
private String trimBrackets(String s) {
if (s != null) {
int beginIdx = s.charAt(0) == '[' ? 1 : 0;
int endIdx = s.length();
if (s.charAt(endIdx - 1) == ']')
endIdx--;
return s.substring(beginIdx, endIdx);
}
return null;
}
private String getModelledType(String dataType) {
return "module:" + (StringUtils.isEmpty(modelPackage) ? "" : (modelPackage + "/")) + dataType;
}
private String getJSDocTypeWithBraces(CodegenModel cm, CodegenProperty cp) {
return "{" + getJSDocType(cm, cp) + "}";
}
private String getJSDocType(CodegenModel cm, CodegenProperty cp) {
if (Boolean.TRUE.equals(cp.isContainer)) {
if (cp.containerType.equals("array"))
return "Array.<" + getJSDocType(cm, cp.items) + ">";
else if (cp.containerType.equals("map"))
return "Object.<String, " + getJSDocType(cm, cp.items) + ">";
}
String dataType = trimBrackets(cp.datatypeWithEnum);
if (cp.isEnum) {
dataType = cm.classname + '.' + dataType;
}
if (isModelledType(cp))
dataType = getModelledType(dataType);
return dataType;
}
private boolean isModelledType(CodegenProperty cp) {
// N.B. enums count as modelled types, file is not modelled (SuperAgent uses some 3rd party library).
return cp.isEnum || !languageSpecificPrimitives.contains(cp.baseType == null ? cp.datatype : cp.baseType);
}
private String getJSDocTypeWithBraces(CodegenParameter cp) {
return "{" + getJSDocType(cp) + "}";
}
private String getJSDocType(CodegenParameter cp) {
String dataType = trimBrackets(cp.dataType);
if (isModelledType(cp))
dataType = getModelledType(dataType);
if (Boolean.TRUE.equals(cp.isListContainer)) {
return "Array.<" + dataType + ">";
} else if (Boolean.TRUE.equals(cp.isMapContainer)) {
return "Object.<String, " + dataType + ">";
}
return dataType;
}
private boolean isModelledType(CodegenParameter cp) {
// N.B. enums count as modelled types, file is not modelled (SuperAgent uses some 3rd party library).
return cp.isEnum || !languageSpecificPrimitives.contains(cp.baseType == null ? cp.dataType : cp.baseType);
}
private String getJSDocTypeWithBraces(CodegenOperation co) {
String jsDocType = getJSDocType(co);
return jsDocType == null ? null : "{" + jsDocType + "}";
}
private String getJSDocType(CodegenOperation co) {
String returnType = trimBrackets(co.returnType);
if (returnType != null) {
if (isModelledType(co))
returnType = getModelledType(returnType);
if (Boolean.TRUE.equals(co.isListContainer)) {
return "Array.<" + returnType + ">";
} else if (Boolean.TRUE.equals(co.isMapContainer)) {
return "Object.<String, " + returnType + ">";
}
}
return returnType;
}
private boolean isModelledType(CodegenOperation co) {
// This seems to be the only way to tell whether an operation return type is modelled.
return !Boolean.TRUE.equals(co.returnTypeIsPrimitive);
}
@SuppressWarnings("unchecked")
@Override
public Map<String, Object> postProcessOperations(Map<String, Object> objs) {
// Generate and store argument list string of each operation into
@@ -615,7 +776,7 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
if (operations != null) {
List<CodegenOperation> ops = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation operation : ops) {
List<String> argList = new ArrayList();
List<String> argList = new ArrayList<String>();
boolean hasOptionalParams = false;
for (CodegenParameter p : operation.allParams) {
if (p.required != null && p.required) {
@@ -631,20 +792,46 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
argList.add("callback");
}
operation.vendorExtensions.put("x-codegen-argList", StringUtils.join(argList, ", "));
// Store JSDoc type specification into vendor-extension: x-jsdoc-type.
for (CodegenParameter cp : operation.allParams) {
String jsdocType = getJSDocTypeWithBraces(cp);
cp.vendorExtensions.put("x-jsdoc-type", jsdocType);
}
String jsdocType = getJSDocTypeWithBraces(operation);
operation.vendorExtensions.put("x-jsdoc-type", jsdocType);
}
}
return objs;
}
@SuppressWarnings("unchecked")
@Override
public Map<String, Object> postProcessModels(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");
// Collect each model's required property names in *document order*.
// NOTE: can't use 'mandatory' as it is built from ModelImpl.getRequired(), which sorts names
// alphabetically and in any case the document order of 'required' and 'properties' can differ.
List<String> required = new ArrayList<String>();
List<String> allRequired = supportsInheritance ? new ArrayList<String>() : required;
cm.vendorExtensions.put("x-required", required);
cm.vendorExtensions.put("x-all-required", allRequired);
for (CodegenProperty var : cm.vars) {
Map<String, Object> allowableValues = var.allowableValues;
// Add JSDoc @type value for this property.
String jsDocType = getJSDocTypeWithBraces(cm, var);
var.vendorExtensions.put("x-jsdoc-type", jsDocType);
if (Boolean.TRUE.equals(var.required)) {
required.add(var.name);
}
// handle ArrayProperty
if (var.items != null) {
allowableValues = var.items.allowableValues;
@@ -679,6 +866,15 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo
}
allowableValues.put("enumVars", enumVars);
}
if (supportsInheritance) {
for (CodegenProperty var : cm.allVars) {
if (Boolean.TRUE.equals(var.required)) {
allRequired.add(var.name);
}
}
}
// set vendor-extension: x-codegen-hasMoreRequired
CodegenProperty lastRequired = null;
for (CodegenProperty var : cm.vars) {