Merge branch 'master' of https://github.com/swagger-api/swagger-codegen into feature/node-promise-cleanup

This commit is contained in:
Kristof Vrolijkx
2016-05-19 20:08:34 +02:00
249 changed files with 12301 additions and 15799 deletions

View File

@@ -99,6 +99,16 @@ public abstract class AbstractGenerator {
}
}
public String readResourceContents(String resourceFilePath) {
StringBuilder sb = new StringBuilder();
Scanner scanner = new Scanner(this.getClass().getResourceAsStream(getCPResourcePath(resourceFilePath)), "UTF-8");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
sb.append(line).append('\n');
}
return sb.toString();
}
public boolean embeddedTemplateExists(String name) {
return this.getClass().getClassLoader().getResource(getCPResourcePath(name)) != null;
}

View File

@@ -184,4 +184,5 @@ public interface CodegenConfig {
String getHttpUserAgent();
String getCommonTemplateDir();
}

View File

@@ -105,4 +105,14 @@ public class CodegenConstants {
public static final String SUPPORTS_ES6 = "supportsES6";
public static final String SUPPORTS_ES6_DESC = "Generate code that conforms to ES6.";
public static final String EXCLUDE_TESTS = "excludeTests";
public static final String EXCLUDE_TESTS_DESC = "Specifies that no tests are to be generated.";
public static final String GENERATE_API_TESTS = "generateApiTests";
public static final String GENERATE_API_TESTS_DESC = "Specifies that api tests are to be generated.";
public static final String GENERATE_MODEL_TESTS = "generateModelTests";
public static final String GENERATE_MODEL_TESTS_DESC = "Specifies that model tests are to be generated.";
}

View File

@@ -94,6 +94,7 @@ public class DefaultCodegen {
protected Map<String, String> modelDocTemplateFiles = new HashMap<String, String>();
protected String templateDir;
protected String embeddedTemplateDir;
protected String commonTemplateDir = "_common";
protected Map<String, Object> additionalProperties = new HashMap<String, Object>();
protected Map<String, Object> vendorExtensions = new HashMap<String, Object>();
protected List<SupportingFile> supportingFiles = new ArrayList<SupportingFile>();
@@ -441,6 +442,14 @@ public class DefaultCodegen {
}
}
public String getCommonTemplateDir() {
return this.commonTemplateDir;
}
public void setCommonTemplateDir(String commonTemplateDir) {
this.commonTemplateDir = commonTemplateDir;
}
public Map<String, String> apiDocTemplateFiles() {
return apiDocTemplateFiles;
}

View File

@@ -2,6 +2,7 @@ package io.swagger.codegen;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import io.swagger.codegen.ignore.CodegenIgnoreProcessor;
import io.swagger.models.*;
import io.swagger.models.auth.OAuth2Definition;
import io.swagger.models.auth.SecuritySchemeDefinition;
@@ -24,6 +25,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
protected CodegenConfig config;
protected ClientOptInput opts;
protected Swagger swagger;
protected CodegenIgnoreProcessor ignoreProcessor;
@Override
public Generator opts(ClientOptInput opts) {
@@ -31,8 +33,11 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
this.swagger = opts.getSwagger();
this.config = opts.getConfig();
this.config.additionalProperties().putAll(opts.getOpts().getProperties());
ignoreProcessor = new CodegenIgnoreProcessor(this.config.getOutputDir());
return this;
}
@@ -41,6 +46,10 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
Boolean generateApis = null;
Boolean generateModels = null;
Boolean generateSupportingFiles = null;
Boolean generateApiTests = null;
Boolean generateApiDocumentation = null;
Boolean generateModelTests = null;
Boolean generateModelDocumentation = null;
Set<String> modelsToGenerate = null;
Set<String> apisToGenerate = null;
@@ -68,6 +77,18 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
supportingFilesToGenerate = new HashSet<String>(Arrays.asList(supportingFiles.split(",")));
}
}
if(System.getProperty("modelTests") != null) {
generateModelTests = Boolean.valueOf(System.getProperty("modelTests"));
}
if(System.getProperty("modelDocs") != null) {
generateModelDocumentation = Boolean.valueOf(System.getProperty("modelDocs"));
}
if(System.getProperty("apiTests") != null) {
generateApiTests = Boolean.valueOf(System.getProperty("apiTests"));
}
if(System.getProperty("apiDocs") != null) {
generateApiDocumentation = Boolean.valueOf(System.getProperty("apiDocs"));
}
if(generateApis == null && generateModels == null && generateSupportingFiles == null) {
// no specifics are set, generate everything
@@ -85,6 +106,28 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
}
}
// model/api tests and documentation options rely on parent generate options (api or model) and no other options.
// They default to true in all scenarios and can only be marked false explicitly
if (generateModelTests == null) {
generateModelTests = true;
}
if (generateModelDocumentation == null) {
generateModelDocumentation = true;
}
if (generateApiTests == null) {
generateApiTests = true;
}
if (generateApiDocumentation == null) {
generateApiDocumentation = true;
}
// Additional properties added for tests to exclude references in project related files
config.additionalProperties().put(CodegenConstants.GENERATE_API_TESTS, generateApiTests);
config.additionalProperties().put(CodegenConstants.GENERATE_MODEL_TESTS, generateModelTests);
if(Boolean.FALSE.equals(generateApiTests) && Boolean.FALSE.equals(generateModelTests)) {
config.additionalProperties().put(CodegenConstants.EXCLUDE_TESTS, Boolean.TRUE);
}
if (swagger == null || config == null) {
throw new RuntimeException("missing swagger input or config!");
}
@@ -159,7 +202,6 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
String basePath = hostBuilder.toString();
String basePathWithoutHost = swagger.getBasePath();
// resolve inline models
InlineModelResolver inlineModelResolver = new InlineModelResolver();
inlineModelResolver.flatten(swagger);
@@ -267,66 +309,46 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
LOGGER.info("Skipped overwriting " + filename);
continue;
}
String templateFile = getFullTemplateFile(config, templateName);
String template = readTemplate(templateFile);
Template tmpl = Mustache.compiler()
.withLoader(new Mustache.TemplateLoader() {
@Override
public Reader getTemplate(String name) {
return getTemplateReader(getFullTemplateFile(config, name + ".mustache"));
}
})
.defaultValue("")
.compile(template);
writeToFile(filename, tmpl.execute(models));
files.add(new File(filename));
File written = processTemplateToFile(models, templateName, filename);
if(written != null) {
files.add(written);
}
}
// to generate model test files
for (String templateName : config.modelTestTemplateFiles().keySet()) {
String suffix = config.modelTestTemplateFiles().get(templateName);
String filename = config.modelTestFileFolder() + File.separator + config.toModelTestFilename(name) + suffix;
// do not overwrite test file that already exists
if (new File(filename).exists()) {
LOGGER.info("File exists. Skipped overwriting " + filename);
continue;
if(generateModelTests) {
// to generate model test files
for (String templateName : config.modelTestTemplateFiles().keySet()) {
String suffix = config.modelTestTemplateFiles().get(templateName);
String filename = config.modelTestFileFolder() + File.separator + config.toModelTestFilename(name) + suffix;
// do not overwrite test file that already exists
if (new File(filename).exists()) {
LOGGER.info("File exists. Skipped overwriting " + filename);
continue;
}
File written = processTemplateToFile(models, templateName, filename);
if (written != null) {
files.add(written);
}
}
String templateFile = getFullTemplateFile(config, templateName);
String template = readTemplate(templateFile);
Template tmpl = Mustache.compiler()
.withLoader(new Mustache.TemplateLoader() {
@Override
public Reader getTemplate(String name) {
return getTemplateReader(getFullTemplateFile(config, name + ".mustache"));
}
})
.defaultValue("")
.compile(template);
writeToFile(filename, tmpl.execute(models));
files.add(new File(filename));
}
// to generate model documentation files
for (String templateName : config.modelDocTemplateFiles().keySet()) {
String suffix = config.modelDocTemplateFiles().get(templateName);
String filename = config.modelDocFileFolder() + File.separator + config.toModelDocFilename(name) + suffix;
if (!config.shouldOverwrite(filename)) {
LOGGER.info("Skipped overwriting " + filename);
continue;
if(generateModelDocumentation) {
// to generate model documentation files
for (String templateName : config.modelDocTemplateFiles().keySet()) {
String suffix = config.modelDocTemplateFiles().get(templateName);
String filename = config.modelDocFileFolder() + File.separator + config.toModelDocFilename(name) + suffix;
if (!config.shouldOverwrite(filename)) {
LOGGER.info("Skipped overwriting " + filename);
continue;
}
File written = processTemplateToFile(models, templateName, filename);
if (written != null) {
files.add(written);
}
}
String templateFile = getFullTemplateFile(config, templateName);
String template = readTemplate(templateFile);
Template tmpl = Mustache.compiler()
.withLoader(new Mustache.TemplateLoader() {
@Override
public Reader getTemplate(String name) {
return getTemplateReader(getFullTemplateFile(config, name + ".mustache"));
}
})
.defaultValue("")
.compile(template);
writeToFile(filename, tmpl.execute(models));
files.add(new File(filename));
}
} catch (Exception e) {
throw new RuntimeException("Could not generate model '" + name + "'", e);
@@ -401,68 +423,44 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
continue;
}
String templateFile = getFullTemplateFile(config, templateName);
String template = readTemplate(templateFile);
Template tmpl = Mustache.compiler()
.withLoader(new Mustache.TemplateLoader() {
@Override
public Reader getTemplate(String name) {
return getTemplateReader(getFullTemplateFile(config, name + ".mustache"));
}
})
.defaultValue("")
.compile(template);
writeToFile(filename, tmpl.execute(operation));
files.add(new File(filename));
File written = processTemplateToFile(operation, templateName, filename);
if(written != null) {
files.add(written);
}
}
// to generate api test files
for (String templateName : config.apiTestTemplateFiles().keySet()) {
String filename = config.apiTestFilename(templateName, tag);
// do not overwrite test file that already exists
if (new File(filename).exists()) {
LOGGER.info("File exists. Skipped overwriting " + filename);
continue;
}
String templateFile = getFullTemplateFile(config, templateName);
String template = readTemplate(templateFile);
Template tmpl = Mustache.compiler()
.withLoader(new Mustache.TemplateLoader() {
@Override
public Reader getTemplate(String name) {
return getTemplateReader(getFullTemplateFile(config, name + ".mustache"));
}
})
.defaultValue("")
.compile(template);
if(generateApiTests) {
// to generate api test files
for (String templateName : config.apiTestTemplateFiles().keySet()) {
String filename = config.apiTestFilename(templateName, tag);
// do not overwrite test file that already exists
if (new File(filename).exists()) {
LOGGER.info("File exists. Skipped overwriting " + filename);
continue;
}
writeToFile(filename, tmpl.execute(operation));
files.add(new File(filename));
File written = processTemplateToFile(operation, templateName, filename);
if (written != null) {
files.add(written);
}
}
}
// to generate api documentation files
for (String templateName : config.apiDocTemplateFiles().keySet()) {
String filename = config.apiDocFilename(templateName, tag);
if (!config.shouldOverwrite(filename) && new File(filename).exists()) {
LOGGER.info("Skipped overwriting " + filename);
continue;
if(generateApiDocumentation) {
// to generate api documentation files
for (String templateName : config.apiDocTemplateFiles().keySet()) {
String filename = config.apiDocFilename(templateName, tag);
if (!config.shouldOverwrite(filename) && new File(filename).exists()) {
LOGGER.info("Skipped overwriting " + filename);
continue;
}
File written = processTemplateToFile(operation, templateName, filename);
if (written != null) {
files.add(written);
}
}
String templateFile = getFullTemplateFile(config, templateName);
String template = readTemplate(templateFile);
Template tmpl = Mustache.compiler()
.withLoader(new Mustache.TemplateLoader() {
@Override
public Reader getTemplate(String name) {
return getTemplateReader(getFullTemplateFile(config, name + ".mustache"));
}
})
.defaultValue("")
.compile(template);
writeToFile(filename, tmpl.execute(operation));
files.add(new File(filename));
}
} catch (Exception e) {
@@ -544,53 +542,95 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
}
}
if(shouldGenerate) {
if (templateFile.endsWith("mustache")) {
String template = readTemplate(templateFile);
Template tmpl = Mustache.compiler()
.withLoader(new Mustache.TemplateLoader() {
@Override
public Reader getTemplate(String name) {
return getTemplateReader(getFullTemplateFile(config, name + ".mustache"));
}
})
.defaultValue("")
.compile(template);
if(ignoreProcessor.allowsFile(new File(outputFilename))) {
if (templateFile.endsWith("mustache")) {
String template = readTemplate(templateFile);
Template tmpl = Mustache.compiler()
.withLoader(new Mustache.TemplateLoader() {
@Override
public Reader getTemplate(String name) {
return getTemplateReader(getFullTemplateFile(config, name + ".mustache"));
}
})
.defaultValue("")
.compile(template);
writeToFile(outputFilename, tmpl.execute(bundle));
files.add(new File(outputFilename));
} else {
InputStream in = null;
try {
in = new FileInputStream(templateFile);
} catch (Exception e) {
// continue
}
if (in == null) {
in = this.getClass().getClassLoader().getResourceAsStream(getCPResourcePath(templateFile));
}
File outputFile = new File(outputFilename);
OutputStream out = new FileOutputStream(outputFile, false);
if (in != null) {
LOGGER.info("writing file " + outputFile);
IOUtils.copy(in, out);
writeToFile(outputFilename, tmpl.execute(bundle));
files.add(new File(outputFilename));
} else {
if (in == null) {
LOGGER.error("can't open " + templateFile + " for input");
InputStream in = null;
try {
in = new FileInputStream(templateFile);
} catch (Exception e) {
// continue
}
if (in == null) {
in = this.getClass().getClassLoader().getResourceAsStream(getCPResourcePath(templateFile));
}
File outputFile = new File(outputFilename);
OutputStream out = new FileOutputStream(outputFile, false);
if (in != null) {
LOGGER.info("writing file " + outputFile);
IOUtils.copy(in, out);
} else {
if (in == null) {
LOGGER.error("can't open " + templateFile + " for input");
}
}
files.add(outputFile);
}
files.add(outputFile);
} else {
LOGGER.info("Skipped generation of " + outputFilename + " due to rule in .swagger-codegen-ignore");
}
}
} catch (Exception e) {
throw new RuntimeException("Could not generate supporting file '" + support + "'", e);
}
}
// Consider .swagger-codegen-ignore a supporting file
// Output .swagger-codegen-ignore if it doesn't exist and wasn't explicitly created by a generator
final String swaggerCodegenIgnore = ".swagger-codegen-ignore";
String ignoreFileNameTarget = config.outputFolder() + File.separator + swaggerCodegenIgnore;
File ignoreFile = new File(ignoreFileNameTarget);
if(!ignoreFile.exists()) {
String ignoreFileNameSource = File.separator + config.getCommonTemplateDir() + File.separator + swaggerCodegenIgnore;
String ignoreFileContents = readResourceContents(ignoreFileNameSource);
try {
writeToFile(ignoreFileNameTarget, ignoreFileContents);
} catch (IOException e) {
throw new RuntimeException("Could not generate supporting file '" + swaggerCodegenIgnore + "'", e);
}
files.add(ignoreFile);
}
}
config.processSwagger(swagger);
return files;
}
private File processTemplateToFile(Map<String, Object> templateData, String templateName, String outputFilename) throws IOException {
if(ignoreProcessor.allowsFile(new File(outputFilename.replaceAll("//", "/")))) {
String templateFile = getFullTemplateFile(config, templateName);
String template = readTemplate(templateFile);
Template tmpl = Mustache.compiler()
.withLoader(new Mustache.TemplateLoader() {
@Override
public Reader getTemplate(String name) {
return getTemplateReader(getFullTemplateFile(config, name + ".mustache"));
}
})
.defaultValue("")
.compile(template);
writeToFile(outputFilename, tmpl.execute(templateData));
return new File(outputFilename);
}
LOGGER.info("Skipped generation of " + outputFilename + " due to rule in .swagger-codegen-ignore");
return null;
}
private static void processMimeTypes(List<String> mimeTypeList, Map<String, Object> operation, String source) {
if (mimeTypeList != null && mimeTypeList.size() > 0) {
List<Map<String, String>> c = new ArrayList<Map<String, String>>();

View File

@@ -0,0 +1,134 @@
package io.swagger.codegen.ignore;
import com.google.common.collect.ImmutableList;
import io.swagger.codegen.ignore.rules.DirectoryRule;
import io.swagger.codegen.ignore.rules.Rule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class CodegenIgnoreProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(CodegenIgnoreProcessor.class);
private final String outputPath;
private List<Rule> exclusionRules = new ArrayList<>();
private List<Rule> inclusionRules = new ArrayList<>();
public CodegenIgnoreProcessor(String outputPath) {
this.outputPath = outputPath;
final File directory = new File(outputPath);
if(directory.exists() && directory.isDirectory()){
final File codegenIgnore = new File(directory, ".swagger-codegen-ignore");
if(codegenIgnore.exists() && codegenIgnore.isFile()){
try {
loadCodegenRules(codegenIgnore);
} catch (IOException e) {
LOGGER.error("Could not process .swagger-codegen-ignore.", e.getMessage());
}
} else {
// log info message
LOGGER.info("No .swagger-codegen-ignore file found.");
}
}
}
void loadCodegenRules(File codegenIgnore) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(codegenIgnore))) {
String line;
// NOTE: Comments that start with a : (e.g. //:) are pulled from git documentation for .gitignore
// see: https://github.com/git/git/blob/90f7b16b3adc78d4bbabbd426fb69aa78c714f71/Documentation/gitignore.txt
while ((line = reader.readLine()) != null) {
if(
//: A blank line matches no files, so it can serve as a separator for readability.
line.length() == 0
) continue;
Rule rule = Rule.create(line);
// rule could be null here if it's a COMMENT, for example
if(rule != null) {
if (Boolean.TRUE.equals(rule.getNegated())) {
inclusionRules.add(rule);
} else {
exclusionRules.add(rule);
}
}
}
}
}
public boolean allowsFile(File targetFile) {
File file = new File(new File(this.outputPath).toURI().relativize(targetFile.toURI()).getPath());
Boolean directoryExcluded = false;
Boolean exclude = false;
if(exclusionRules.size() == 0 && inclusionRules.size() == 0) {
return true;
}
// NOTE: We *must* process all exclusion rules
for (int i = 0; i < exclusionRules.size(); i++) {
Rule current = exclusionRules.get(i);
Rule.Operation op = current.evaluate(file.getPath());
switch (op){
case EXCLUDE:
exclude = true;
// Include rule can't override rules that exclude a file by some parent directory.
if(current instanceof DirectoryRule) {
directoryExcluded = true;
}
break;
case INCLUDE:
// This won't happen here.
break;
case NOOP:
break;
case EXCLUDE_AND_TERMINATE:
i = exclusionRules.size();
break;
}
}
if(exclude) {
// Only need to process inclusion rules if we've been excluded
for (int i = 0; exclude && i < inclusionRules.size(); i++) {
Rule current = inclusionRules.get(i);
Rule.Operation op = current.evaluate(file.getPath());
// At this point exclude=true means the file should be ignored.
// op == INCLUDE means we have to flip that flag.
if(op.equals(Rule.Operation.INCLUDE)) {
if(current instanceof DirectoryRule && directoryExcluded) {
// e.g
// baz/
// !foo/bar/baz/
// NOTE: Possibly surprising side effect:
// foo/bar/baz/
// !bar/
exclude = false;
} else if (!directoryExcluded) {
// e.g.
// **/*.log
// !ISSUE_1234.log
exclude = false;
}
}
}
}
return Boolean.FALSE.equals(exclude);
}
public List<Rule> getInclusionRules() {
return ImmutableList.copyOf(inclusionRules);
}
public List<Rule> getExclusionRules() {
return ImmutableList.copyOf(exclusionRules);
}
}

View File

@@ -0,0 +1,20 @@
package io.swagger.codegen.ignore.rules;
import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.util.List;
public class DirectoryRule extends FileRule {
private PathMatcher matcher = null;
DirectoryRule(List<Part> syntax, String definition) {
super(syntax, definition);
matcher = FileSystems.getDefault().getPathMatcher("glob:**/"+this.getPattern());
}
@Override
public Boolean matches(String relativePath) {
return matcher.matches(FileSystems.getDefault().getPath(relativePath));
}
}

View File

@@ -0,0 +1,20 @@
package io.swagger.codegen.ignore.rules;
import java.util.List;
/**
* An ignore rule which matches everything.
*/
public class EverythingRule extends Rule {
EverythingRule(List<Part> syntax, String definition) {
super(syntax, definition);
}
@Override
public Boolean matches(String relativePath) {
return true;
}
@Override
protected Operation getExcludeOperation(){ return Operation.EXCLUDE_AND_TERMINATE; }
}

View File

@@ -0,0 +1,20 @@
package io.swagger.codegen.ignore.rules;
import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.util.List;
public class FileRule extends Rule {
private PathMatcher matcher = null;
FileRule(List<Part> syntax, String definition) {
super(syntax, definition);
matcher = FileSystems.getDefault().getPathMatcher("glob:"+this.getPattern());
}
@Override
public Boolean matches(String relativePath) {
return matcher.matches(FileSystems.getDefault().getPath(relativePath));
}
}

View File

@@ -0,0 +1,134 @@
package io.swagger.codegen.ignore.rules;
import java.util.ArrayList;
import java.util.List;
public class IgnoreLineParser {
enum Token {
MATCH_ALL("**"),
MATCH_ANY("*"),
ESCAPED_EXCLAMATION("\\!"),
ESCAPED_SPACE("\\ "),
PATH_DELIM("/"),
NEGATE("!"),
TEXT(null),
DIRECTORY_MARKER("/"),
ROOTED_MARKER("/"),
COMMENT(null);
private String pattern;
Token(String pattern) {
this.pattern = pattern;
}
public String getPattern() {
return pattern;
}
}
// NOTE: Comments that start with a : (e.g. //:) are pulled from git documentation for .gitignore
// see: https://github.com/git/git/blob/90f7b16b3adc78d4bbabbd426fb69aa78c714f71/Documentation/gitignore.txt
static List<Part> parse(String text) throws ParserException {
List<Part> parts = new ArrayList<>();
StringBuilder sb = new StringBuilder();
String current = null;
String next = null;
char[] characters = text.toCharArray();
for (int i = 0, totalLength = characters.length; i < totalLength; i++) {
char character = characters[i];
current = String.valueOf(character);
next = i < totalLength - 1 ? String.valueOf(characters[i + 1]) : null;
if (i == 0) {
if ("#".equals(current)) {
//: A line starting with # serves as a comment.
parts.add(new Part(Token.COMMENT, text));
i = totalLength; // rather than early return
continue;
} else if ("!".equals(current)) {
if (i == totalLength - 1) {
throw new ParserException("Negation with no negated pattern.");
} else {
parts.add(new Part(Token.NEGATE));
continue;
}
} else if ("\\".equals(current) && "#".equals(next)) {
//: Put a backslash ("`\`") in front of the first hash for patterns
//: that begin with a hash.
// NOTE: Just push forward and drop the escape character. Falls through to TEXT token.
current = next;
next = null;
i++;
}
}
if (Token.MATCH_ANY.pattern.equals(current)) {
if (Token.MATCH_ANY.pattern.equals(next)) {
// peek ahead for invalid pattern. Slightly inefficient, but acceptable.
if ((i+2 < totalLength - 1) &&
String.valueOf(characters[i+2]).equals(Token.MATCH_ANY.pattern)) {
// It doesn't matter where we are in the pattern, *** is invalid.
throw new ParserException("The pattern *** is invalid.");
}
parts.add(new Part(Token.MATCH_ALL));
i++;
continue;
} else {
parts.add(new Part(Token.MATCH_ANY));
continue;
}
}
if (i == 0 && Token.ROOTED_MARKER.pattern.equals(current)) {
parts.add(new Part(Token.ROOTED_MARKER));
continue;
}
if ("\\".equals(current) && " ".equals(next)) {
parts.add(new Part(Token.ESCAPED_SPACE));
i++;
continue;
} else if ("\\".equals(current) && "!".equals(next)) {
parts.add(new Part(Token.ESCAPED_EXCLAMATION));
i++;
continue;
}
if (Token.PATH_DELIM.pattern.equals(current)) {
if (i != totalLength - 1) {
if (sb.length() > 0) {
parts.add(new Part(Token.TEXT, sb.toString()));
sb.delete(0, sb.length());
}
parts.add(new Part(Token.PATH_DELIM));
if(Token.PATH_DELIM.pattern.equals(next)) {
// ignore doubled path delims. NOTE: doesn't do full lookahead, so /// will result in //
i++;
}
continue;
} else if (i == totalLength - 1) {
parts.add(new Part(Token.TEXT, sb.toString()));
sb.delete(0, sb.length());
parts.add(new Part(Token.DIRECTORY_MARKER));
continue;
}
}
sb.append(current);
}
if (sb.length() > 0) {
// NOTE: All spaces escaped spaces are a special token, ESCAPED_SPACE
//: Trailing spaces are ignored unless they are quoted with backslash ("`\`")
parts.add(new Part(Token.TEXT, sb.toString().trim()));
}
return parts;
}
}

View File

@@ -0,0 +1,26 @@
package io.swagger.codegen.ignore.rules;
import java.util.List;
public class InvalidRule extends Rule {
private final String reason;
InvalidRule(List<Part> syntax, String definition, String reason) {
super(syntax, definition);
this.reason = reason;
}
@Override
public Boolean matches(String relativePath) {
return null;
}
@Override
public Operation evaluate(String relativePath) {
return Operation.NOOP;
}
public String getReason() {
return reason;
}
}

View File

@@ -0,0 +1,15 @@
package io.swagger.codegen.ignore.rules;
public class ParserException extends Exception {
/**
* Constructs a new exception with the specified detail message. The
* cause is not initialized, and may subsequently be initialized by
* a call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public ParserException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,24 @@
package io.swagger.codegen.ignore.rules;
class Part {
private final IgnoreLineParser.Token token;
private final String value;
public Part(IgnoreLineParser.Token token, String value) {
this.token = token;
this.value = value;
}
public Part(IgnoreLineParser.Token token) {
this.token = token;
this.value = token.getPattern();
}
public IgnoreLineParser.Token getToken() {
return token;
}
public String getValue() {
return value;
}
}

View File

@@ -0,0 +1,58 @@
package io.swagger.codegen.ignore.rules;
import java.util.List;
import java.util.regex.Pattern;
/**
* A special case rule which matches files only if they're located
* in the same directory as the .swagger-codegen-ignore file.
*/
public class RootedFileRule extends Rule {
private String definedFilename = null;
private String definedExtension = null;
RootedFileRule(List<Part> syntax, String definition) {
super(syntax, definition);
int separatorIndex = definition.lastIndexOf(".");
definedFilename = getFilenamePart(definition, separatorIndex);
definedExtension = getExtensionPart(definition, separatorIndex);
}
private String getFilenamePart(final String input, int stopIndex){
return input.substring('/' == input.charAt(0) ? 1 : 0, stopIndex > 0 ? stopIndex : input.length());
}
private String getExtensionPart(final String input, int stopIndex) {
return input.substring(stopIndex > 0 ? stopIndex+1: input.length(), input.length());
}
@Override
public Boolean matches(String relativePath) {
// NOTE: Windows-style separator isn't supported, so File.pathSeparator would be incorrect here.
// NOTE: lastIndexOf rather than contains because /file.txt is acceptable while path/file.txt is not.
// relativePath will be passed by CodegenIgnoreProcessor and is relative to .codegen-ignore.
boolean isSingleFile = relativePath.lastIndexOf("/") <= 0;
if(isSingleFile) {
int separatorIndex = relativePath.lastIndexOf(".");
final String filename = getFilenamePart(relativePath, separatorIndex);
final String extension = getExtensionPart(relativePath, separatorIndex);
boolean extensionMatches = definedExtension.equals(extension) || definedExtension.equals(IgnoreLineParser.Token.MATCH_ANY.getPattern());
if(extensionMatches && definedFilename.contains(IgnoreLineParser.Token.MATCH_ANY.getPattern())) {
// TODO: Evaluate any other escape requirements here.
Pattern regex = Pattern.compile(
definedFilename
.replaceAll(Pattern.quote("."), "\\\\Q.\\\\E")
.replaceAll(Pattern.quote("*"), ".*?") // non-greedy match on 0+ any character
);
return regex.matcher(filename).matches();
}
return extensionMatches && definedFilename.equals(filename);
}
return false;
}
}

View File

@@ -0,0 +1,175 @@
package io.swagger.codegen.ignore.rules;
import java.util.List;
public abstract class Rule {
public enum Operation {EXCLUDE, INCLUDE, NOOP, EXCLUDE_AND_TERMINATE}
// The original rule
private final String definition;
private final List<Part> syntax;
Rule(List<Part> syntax, String definition) {
this.syntax = syntax;
this.definition = definition;
}
public abstract Boolean matches(String relativePath);
public String getDefinition() {
return this.definition;
}
protected String getPattern() {
if(syntax == null) return this.definition;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < syntax.size(); i++) {
Part current = syntax.get(i);
switch(current.getToken()){
case MATCH_ALL:
case MATCH_ANY:
case ESCAPED_EXCLAMATION:
case ESCAPED_SPACE:
case PATH_DELIM:
case TEXT:
case DIRECTORY_MARKER:
sb.append(current.getValue());
break;
case NEGATE:
case ROOTED_MARKER:
case COMMENT:
break;
}
}
return sb.toString();
}
/**
* Whether or not the rule should be negated. !foo means foo should be removed from previous matches.
* Example: **\/*.bak excludes all backup. Adding !/test.bak will include test.bak in the project root.
* <p>
* NOTE: It is not possible to re-include a file if a parent directory of that file is excluded.
*/
public Boolean getNegated() {
return this.syntax != null && this.syntax.size() > 0 && this.syntax.get(0).getToken() == IgnoreLineParser.Token.NEGATE;
}
public Operation evaluate(String relativePath) {
if (Boolean.TRUE.equals(matches(relativePath))) {
if(Boolean.TRUE.equals(this.getNegated())) {
return this.getIncludeOperation();
}
return this.getExcludeOperation();
}
return Operation.NOOP;
}
protected Operation getIncludeOperation(){ return Operation.INCLUDE; }
protected Operation getExcludeOperation(){ return Operation.EXCLUDE; }
public static Rule create(String definition) {
// NOTE: Comments that start with a : (e.g. //:) are pulled from git documentation for .gitignore
// see: https://github.com/git/git/blob/90f7b16b3adc78d4bbabbd426fb69aa78c714f71/Documentation/gitignore.txt
Rule rule = null;
if (definition.equals(".")) {
return new InvalidRule(null, definition, "Pattern '.' is invalid.");
} else if (definition.equals("!.")) {
return new InvalidRule(null, definition, "Pattern '!.' is invalid.");
} else if (definition.startsWith("..")) {
return new InvalidRule(null, definition, "Pattern '..' is invalid.");
}
try {
List<Part> result = IgnoreLineParser.parse(definition);
Boolean directoryOnly = null;
if (result.size() == 0) {
return rule;
} else if (result.size() == 1) {
// single-character filename only
Part part = result.get(0);
if (IgnoreLineParser.Token.MATCH_ANY.equals(part.getToken())) {
rule = new RootedFileRule(result, definition);
} else {
rule = new FileRule(result, definition);
}
} else {
IgnoreLineParser.Token head = result.get(0).getToken();
//: An optional prefix "`!`" which negates the pattern; any
//: matching file excluded by a previous pattern will become
//: included again. It is not possible to re-include a file if a parent
//: directory of that file is excluded. Git doesn't list excluded
//: directories for performance reasons, so any patterns on contained
//: files have no effect, no matter where they are defined.
//: Put a backslash ("`\`") in front of the first "`!`" for patterns
//: that begin with a literal "`!`", for example, "`\!important!.txt`".
// see this.getNegated();
//: If the pattern ends with a slash, it is removed for the
//: purpose of the following description, but it would only find
//: a match with a directory. In other words, `foo/` will match a
//: directory `foo` and paths underneath it, but will not match a
//: regular file or a symbolic link `foo` (this is consistent
//: with the way how pathspec works in general in Git).
directoryOnly = IgnoreLineParser.Token.DIRECTORY_MARKER.equals(result.get(result.size() - 1).getToken());
if (directoryOnly) {
rule = new DirectoryRule(result, definition);
} else if (IgnoreLineParser.Token.PATH_DELIM.equals(head)) {
//: A leading slash matches the beginning of the pathname.
//: For example, "/{asterisk}.c" matches "cat-file.c" but not
//: "mozilla-sha1/sha1.c".
rule = new RootedFileRule(result, definition);
} else {
// case 1
//: If the pattern does not contain a slash '/', Git treats it as
//: a shell glob pattern and checks for a match against the
//: pathname relative to the location of the `.gitignore` file
//: (relative to the toplevel of the work tree if not from a
//: `.gitignore` file).
// case 2
//: Otherwise, Git treats the pattern as a shell glob suitable
//: for consumption by fnmatch(3) with the FNM_PATHNAME flag:
//: wildcards in the pattern will not match a / in the pathname.
//: For example, "Documentation/{asterisk}.html" matches
//: "Documentation/git.html" but not "Documentation/ppc/ppc.html"
//: or "tools/perf/Documentation/perf.html".
// case 3
//: Two consecutive asterisks ("`**`") in patterns matched against
//: full pathname may have special meaning:
//:
//: - A leading "`**`" followed by a slash means match in all
//: directories. For example, "`**/foo`" matches file or directory
//: "`foo`" anywhere, the same as pattern "`foo`". "`**/foo/bar`"
//: matches file or directory "`bar`" anywhere that is directly
//: under directory "`foo`".
//:
//: - A trailing "`/**`" matches everything inside. For example,
//: "`abc/**`" matches all files inside directory "`abc`", relative
//: to the location of the `.gitignore` file, with infinite depth.
//:
//: - A slash followed by two consecutive asterisks then a slash
//: matches zero or more directories. For example, "`a/**/b`"
//: matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on.
//:
//: - Other consecutive asterisks are considered invalid.
rule = new FileRule(result, definition);
}
}
} catch (ParserException e) {
e.printStackTrace();
return new InvalidRule(null, definition, e.getMessage());
}
return rule;
}
}

View File

@@ -23,6 +23,7 @@ public abstract class AbstractJavaJAXRSServerCodegen extends JavaClientCodegen
public AbstractJavaJAXRSServerCodegen()
{
super();
apiTestTemplateFiles.clear(); // TODO: add test template
}
@Override

View File

@@ -137,6 +137,11 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
@Override
public void processOpts() {
super.processOpts();
Boolean excludeTests = false;
if(additionalProperties.containsKey(CodegenConstants.EXCLUDE_TESTS)) {
excludeTests = Boolean.valueOf(additionalProperties.get(CodegenConstants.EXCLUDE_TESTS).toString());
}
apiPackage = "Api";
modelPackage = "Model";
@@ -234,7 +239,10 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
// copy package.config to nuget's standard location for project-level installs
supportingFiles.add(new SupportingFile("packages.config.mustache", packageFolder + File.separator, "packages.config"));
supportingFiles.add(new SupportingFile("packages_test.config.mustache", testPackageFolder + File.separator, "packages.config"));
if(Boolean.FALSE.equals(excludeTests)) {
supportingFiles.add(new SupportingFile("packages_test.config.mustache", testPackageFolder + File.separator, "packages.config"));
}
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
@@ -247,11 +255,9 @@ public class CSharpClientCodegen extends AbstractCSharpCodegen {
supportingFiles.add(new SupportingFile("Solution.mustache", "", packageName + ".sln"));
supportingFiles.add(new SupportingFile("Project.mustache", packageFolder, packageName + ".csproj"));
// TODO: Check if test project output is enabled, partially related to #2506. Should have options for:
// 1) No test project
// 2) No model tests
// 3) No api tests
supportingFiles.add(new SupportingFile("TestProject.mustache", testPackageFolder, testPackageName + ".csproj"));
if(Boolean.FALSE.equals(excludeTests)) {
supportingFiles.add(new SupportingFile("TestProject.mustache", testPackageFolder, testPackageName + ".csproj"));
}
}
additionalProperties.put("apiDocPath", apiDocPath);

View File

@@ -19,6 +19,7 @@ public class GroovyClientCodegen extends JavaClientCodegen {
outputFolder = "generated-code/groovy";
modelTemplateFiles.put("model.mustache", ".groovy");
apiTemplateFiles.put(templateFileName, ".groovy");
apiTestTemplateFiles.clear(); // TODO: add test template
embeddedTemplateDir = templateDir = "Groovy";
apiPackage = "io.swagger.api";

View File

@@ -36,7 +36,9 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig {
protected String artifactId = "swagger-java-client";
protected String artifactVersion = "1.0.0";
protected String projectFolder = "src" + File.separator + "main";
protected String projectTestFolder = "src" + File.separator + "test";
protected String sourceFolder = projectFolder + File.separator + "java";
protected String testFolder = projectTestFolder + File.separator + "java";
protected String localVariablePrefix = "";
protected boolean fullJavaUtil;
protected String javaUtilPrefix = "";
@@ -52,6 +54,7 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig {
outputFolder = "generated-code" + File.separator + "java";
modelTemplateFiles.put("model.mustache", ".java");
apiTemplateFiles.put("api.mustache", ".java");
apiTestTemplateFiles.put("api_test.mustache", ".java");
embeddedTemplateDir = templateDir = "Java";
apiPackage = "io.swagger.client.api";
modelPackage = "io.swagger.client.model";
@@ -366,6 +369,11 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig {
return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', '/');
}
@Override
public String apiTestFileFolder() {
return outputFolder + "/" + testFolder + "/" + apiPackage().replace('.', '/');
}
@Override
public String modelFileFolder() {
return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', '/');
@@ -391,6 +399,11 @@ public class JavaClientCodegen extends DefaultCodegen implements CodegenConfig {
return toModelName(name);
}
@Override
public String toApiTestFilename(String name) {
return toApiName(name) + "Test";
}
@Override
public String toVarName(String name) {
// sanitize name

View File

@@ -25,6 +25,7 @@ public class JavaInflectorServerCodegen extends JavaClientCodegen {
sourceFolder = "src/gen/java";
modelTemplateFiles.put("model.mustache", ".java");
apiTemplateFiles.put("api.mustache", ".java");
apiTestTemplateFiles.clear(); // TODO: add test template
embeddedTemplateDir = templateDir = "JavaInflector";
invokerPackage = "io.swagger.handler";
artifactId = "swagger-inflector-server";

View File

@@ -31,6 +31,7 @@ public class JavaResteasyServerCodegen extends JavaClientCodegen implements Code
apiTemplateFiles.put("apiService.mustache", ".java");
apiTemplateFiles.put("apiServiceImpl.mustache", ".java");
apiTemplateFiles.put("apiServiceFactory.mustache", ".java");
apiTestTemplateFiles.clear(); // TODO: add test template
apiPackage = "io.swagger.api";
modelPackage = "io.swagger.model";

View File

@@ -226,10 +226,6 @@ public class ObjcClientCodegen extends DefaultCodegen implements CodegenConfig {
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);
additionalProperties.put("modelFilesPath", modelFilesPath);
additionalProperties.put("coreFilesPath", coreFilesPath);
additionalProperties.put("apiFilesPath", apiFilesPath);
modelPackage = podName;
apiPackage = podName;
@@ -253,6 +249,7 @@ public class ObjcClientCodegen extends DefaultCodegen implements CodegenConfig {
supportingFiles.add(new SupportingFile("JSONValueTransformer+ISO8601.h", coreFileFolder(), "JSONValueTransformer+ISO8601.h"));
supportingFiles.add(new SupportingFile("Configuration-body.mustache", coreFileFolder(), classPrefix + "Configuration.m"));
supportingFiles.add(new SupportingFile("Configuration-header.mustache", coreFileFolder(), classPrefix + "Configuration.h"));
supportingFiles.add(new SupportingFile("api-protocol.mustache", coreFileFolder(), classPrefix + "Api.h"));
supportingFiles.add(new SupportingFile("podspec.mustache", "", podName + ".podspec"));
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));

View File

@@ -34,8 +34,8 @@ public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig {
public static final String COMPOSER_VENDOR_NAME = "composerVendorName";
public static final String COMPOSER_PROJECT_NAME = "composerProjectName";
protected String invokerPackage = "Swagger\\Client";
protected String composerVendorName = "swagger";
protected String composerProjectName = "swagger-client";
protected String composerVendorName = null;
protected String composerProjectName = null;
protected String packagePath = "SwaggerClient-php";
protected String artifactVersion = null;
protected String srcBasePath = "lib";
@@ -128,7 +128,9 @@ public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig {
cliOptions.add(new CliOption(PACKAGE_PATH, "The main package name for classes. e.g. GeneratedPetstore"));
cliOptions.add(new CliOption(SRC_BASE_PATH, "The directory under packagePath to serve as source root."));
cliOptions.add(new CliOption(COMPOSER_VENDOR_NAME, "The vendor name used in the composer package name. The template uses {{composerVendorName}}/{{composerProjectName}} for the composer package name. e.g. yaypets. IMPORTANT NOTE (2016/03): composerVendorName will be deprecated and replaced by gitUserId in the next swagger-codegen release"));
cliOptions.add(new CliOption(CodegenConstants.GIT_USER_ID, CodegenConstants.GIT_USER_ID_DESC));
cliOptions.add(new CliOption(COMPOSER_PROJECT_NAME, "The project name used in the composer package name. The template uses {{composerVendorName}}/{{composerProjectName}} for the composer package name. e.g. petstore-client. IMPORTANT NOTE (2016/03): composerProjectName will be deprecated and replaced by gitRepoId in the next swagger-codegen release"));
cliOptions.add(new CliOption(CodegenConstants.GIT_REPO_ID, CodegenConstants.GIT_REPO_ID_DESC));
cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_VERSION, "The version to use in the composer package version field. e.g. 1.2.3"));
}
@@ -216,12 +218,24 @@ public class PhpClientCodegen extends DefaultCodegen implements CodegenConfig {
additionalProperties.put(COMPOSER_PROJECT_NAME, composerProjectName);
}
if (additionalProperties.containsKey(CodegenConstants.GIT_USER_ID)) {
this.setGitUserId((String) additionalProperties.get(CodegenConstants.GIT_USER_ID));
} else {
additionalProperties.put(CodegenConstants.GIT_USER_ID, gitUserId);
}
if (additionalProperties.containsKey(COMPOSER_VENDOR_NAME)) {
this.setComposerVendorName((String) additionalProperties.get(COMPOSER_VENDOR_NAME));
} else {
additionalProperties.put(COMPOSER_VENDOR_NAME, composerVendorName);
}
if (additionalProperties.containsKey(CodegenConstants.GIT_REPO_ID)) {
this.setGitRepoId((String) additionalProperties.get(CodegenConstants.GIT_REPO_ID));
} else {
additionalProperties.put(CodegenConstants.GIT_REPO_ID, gitRepoId);
}
if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_VERSION)) {
this.setArtifactVersion((String) additionalProperties.get(CodegenConstants.ARTIFACT_VERSION));
} else {

View File

@@ -116,6 +116,11 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
@Override
public void processOpts() {
super.processOpts();
Boolean excludeTests = false;
if(additionalProperties.containsKey(CodegenConstants.EXCLUDE_TESTS)) {
excludeTests = Boolean.valueOf(additionalProperties.get(CodegenConstants.EXCLUDE_TESTS).toString());
}
if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) {
setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME));
@@ -145,13 +150,20 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("setup.mustache", "", "setup.py"));
supportingFiles.add(new SupportingFile("tox.mustache", "", "tox.ini"));
supportingFiles.add(new SupportingFile("test-requirements.mustache", "", "test-requirements.txt"));
supportingFiles.add(new SupportingFile("requirements.mustache", "", "requirements.txt"));
supportingFiles.add(new SupportingFile("api_client.mustache", swaggerFolder, "api_client.py"));
supportingFiles.add(new SupportingFile("rest.mustache", swaggerFolder, "rest.py"));
supportingFiles.add(new SupportingFile("configuration.mustache", swaggerFolder, "configuration.py"));
supportingFiles.add(new SupportingFile("__init__package.mustache", swaggerFolder, "__init__.py"));
supportingFiles.add(new SupportingFile("__init__model.mustache", modelPackage, "__init__.py"));
supportingFiles.add(new SupportingFile("__init__api.mustache", apiPackage, "__init__.py"));
supportingFiles.add(new SupportingFile("__init__test.mustache", testFolder, "__init__.py"));
if(Boolean.FALSE.equals(excludeTests)) {
supportingFiles.add(new SupportingFile("__init__test.mustache", testFolder, "__init__.py"));
}
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
}

View File

@@ -20,6 +20,7 @@ public class SpringBootServerCodegen extends JavaClientCodegen implements Codege
outputFolder = "generated-code/javaSpringBoot";
modelTemplateFiles.put("model.mustache", ".java");
apiTemplateFiles.put(templateFileName, ".java");
apiTestTemplateFiles.clear(); // TODO: add test template
embeddedTemplateDir = templateDir = "JavaSpringBoot";
apiPackage = "io.swagger.api";
modelPackage = "io.swagger.model";

View File

@@ -18,6 +18,7 @@ public class SpringMVCServerCodegen extends JavaClientCodegen implements Codegen
outputFolder = "generated-code/javaSpringMVC";
modelTemplateFiles.put("model.mustache", ".java");
apiTemplateFiles.put(templateFileName, ".java");
apiTestTemplateFiles.clear(); // TODO: add test template
embeddedTemplateDir = templateDir = "JavaSpringMVC";
apiPackage = "io.swagger.api";
modelPackage = "io.swagger.model";

View File

@@ -342,7 +342,7 @@ public class SwiftCodegen extends DefaultCodegen implements CodegenConfig {
// Ensure that the enum type doesn't match a reserved word or
// the variable name doesn't match the generated enum type or the
// Swift compiler will generate an error
if (isReservedWord(codegenProperty.datatypeWithEnum) || name.equals(codegenProperty.datatypeWithEnum)) {
if (isReservedWord(codegenProperty.datatypeWithEnum) || toVarName(name).equals(codegenProperty.datatypeWithEnum)) {
codegenProperty.datatypeWithEnum = codegenProperty.datatypeWithEnum + "Enum";
}
}