Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Templating Engine API and handlebars support #690

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ COPY ./modules/openapi-generator-gradle-plugin ${GEN_DIR}/modules/openapi-genera
COPY ./modules/openapi-generator-maven-plugin ${GEN_DIR}/modules/openapi-generator-maven-plugin
COPY ./modules/openapi-generator-online ${GEN_DIR}/modules/openapi-generator-online
COPY ./modules/openapi-generator-cli ${GEN_DIR}/modules/openapi-generator-cli
COPY ./modules/openapi-generator-core ${GEN_DIR}/modules/openapi-generator-core
COPY ./modules/openapi-generator ${GEN_DIR}/modules/openapi-generator
COPY ./pom.xml ${GEN_DIR}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ public class Generate implements Runnable {
description = "folder containing the template files")
private String templateDir;

@Option(name = {"-e", "--engine"}, title = "templating engine",
description = "templating engine, for now \"mustache\" and \"handlebars\" are supported")
private String templatingEngine;

@Option(
name = {"-a", "--auth"},
title = "authorization",
Expand Down Expand Up @@ -273,6 +277,10 @@ public void run() {
configurator.setTemplateDir(templateDir);
}

if (isNotEmpty(templatingEngine)) {
configurator.setTemplatingEngineName(templatingEngine);
}

if (isNotEmpty(apiPackage)) {
configurator.setApiPackage(apiPackage);
}
Expand Down
16 changes: 16 additions & 0 deletions modules/openapi-generator-core/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>openapi-generator-project</artifactId>
<groupId>org.openapitools</groupId>
<version>4.0.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>openapi-generator-core</artifactId>
<name>openapi-generator-core</name>
<url>https://github.com/openapitools/openapi-generator</url>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.openapitools.codegen.api;

import java.io.IOException;
import java.util.Map;

/**
* Each templating engine is called by an Adapter, selected at runtime
*/
public interface TemplatingEngineAdapter{

/**
* Compiles a template into a string
*
* @param generator From where we can fetch the templates content (e.g. an instance of DefaultGenerator)
* @param bundle The map of values to pass to the template
* @param templateFile The name of the template (e.g. model.mustache )
* @return the processed template result
* @throws IOException an error ocurred in the template processing
*/
String compileTemplate(TemplatingGenerator generator, Map<String, Object> bundle,
String templateFile) throws IOException;

/**
* During generation, if a supporting file has a file extension that is
* inside that array, then it is considered a templated supporting file
* and we use the templating engine adapter to generate it
* @return string array of the valid file extensions for this templating engine
*/
String[] getFileExtensions();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.openapitools.codegen.api;

/**
* interface to the full template content
* implementers might take into account the -t cli option,
* look in the resources for a language specific template, etc
*/
public interface TemplatingGenerator {

/**
* returns the template content by name
* @param name the template name (e.g. model.mustache)
* @return the contents of that template
*/
String getFullTemplateContents(String name);

}
10 changes: 10 additions & 0 deletions modules/openapi-generator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,11 @@
<artifactId>jmustache</artifactId>
<version>${jmustache-version}</version>
</dependency>
<dependency>
<groupId>com.github.jknack</groupId>
<artifactId>handlebars</artifactId>
<version>${handlebars.java-version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
Expand Down Expand Up @@ -300,6 +305,11 @@
<artifactId>jackson-datatype-threetenbp</artifactId>
<version>${jackson-threetenbp-version}</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-core</artifactId>
<version>4.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
<repositories>
<repository>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.openapitools.codegen;

import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.api.TemplatingGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -26,7 +27,7 @@
import java.util.Scanner;
import java.util.regex.Pattern;

public abstract class AbstractGenerator {
public abstract class AbstractGenerator implements TemplatingGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractGenerator.class);

@SuppressWarnings("static-method")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openapitools.codegen.api.TemplatingEngineAdapter;

public interface CodegenConfig {
CodegenType getTag();
Expand Down Expand Up @@ -149,6 +150,8 @@ public interface CodegenConfig {

Compiler processCompiler(Compiler compiler);

TemplatingEngineAdapter processTemplatingEngine(TemplatingEngineAdapter templatingEngine);

String sanitizeTag(String tag);

String toApiFilename(String name);
Expand Down Expand Up @@ -260,4 +263,7 @@ public interface CodegenConfig {
*/
void setOpenAPI(OpenAPI openAPI);

void setTemplatingEngine(TemplatingEngineAdapter s);

TemplatingEngineAdapter getTemplatingEngine();
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ public class CodegenConstants {
public static final String DOTNET_FRAMEWORK = "targetFramework";
public static final String DOTNET_FRAMEWORK_DESC = "The target .NET framework version.";

public static final String TEMPLATING_ENGINE = "templatingEngine";
public static final String TEMPLATING_ENGINE_DESC = "The templating engine plugin to use";

public static enum MODEL_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case, original}

public static enum ENUM_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case, original, UPPERCASE}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.openapitools.codegen.CodegenDiscriminator.MappedModel;
import org.openapitools.codegen.api.TemplatingEngineAdapter;
import org.openapitools.codegen.config.GeneratorProperties;
import org.openapitools.codegen.examples.ExampleGenerator;
import org.openapitools.codegen.serializer.SerializerUtils;
import org.openapitools.codegen.templating.MustacheEngineAdapter;
import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -111,6 +113,7 @@ public class DefaultCodegen implements CodegenConfig {
protected String ignoreFilePathOverride;
// flag to indicate whether to use environment variable to post process file
protected boolean enablePostProcessFile = false;
private TemplatingEngineAdapter templatingEngine = new MustacheEngineAdapter();

// make openapi available to all methods
protected OpenAPI openAPI;
Expand Down Expand Up @@ -460,6 +463,12 @@ public Compiler processCompiler(Compiler compiler) {
return compiler;
}

// override with any special handling for the templating engine
@SuppressWarnings("unused")
public TemplatingEngineAdapter processTemplatingEngine(TemplatingEngineAdapter templatingEngine) {
return templatingEngine;
}

// override with any special text escaping logic
@SuppressWarnings("static-method")
public String escapeText(String input) {
Expand Down Expand Up @@ -3804,6 +3813,16 @@ public String sanitizeName(String name) {
return sanitizeName(name, "\\W");
}

@Override
public void setTemplatingEngine(TemplatingEngineAdapter templatingEngine) {
this.templatingEngine = templatingEngine;
}

@Override
public TemplatingEngineAdapter getTemplatingEngine() {
return this.templatingEngine;
}

/**
* Sanitize name (parameter, property, method, etc)
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@

package org.openapitools.codegen;

import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
Expand All @@ -36,7 +34,10 @@
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.config.GeneratorProperties;
import org.openapitools.codegen.api.TemplatingEngineAdapter;
import org.openapitools.codegen.ignore.CodegenIgnoreProcessor;
import org.openapitools.codegen.templating.MustacheEngineAdapter;
import org.openapitools.codegen.config.GeneratorProperties;
import org.openapitools.codegen.utils.ImplementationVersion;
import org.openapitools.codegen.utils.ModelUtils;
import org.openapitools.codegen.utils.URLPathUtils;
Expand All @@ -54,6 +55,7 @@ public class DefaultGenerator extends AbstractGenerator implements Generator {
protected ClientOptInput opts;
protected OpenAPI openAPI;
protected CodegenIgnoreProcessor ignoreProcessor;
protected TemplatingEngineAdapter templatingEngine;
private Boolean generateApis = null;
private Boolean generateModels = null;
private Boolean generateSupportingFiles = null;
Expand All @@ -73,6 +75,7 @@ public Generator opts(ClientOptInput opts) {
this.openAPI = opts.getOpenAPI();
this.config = opts.getConfig();
this.config.additionalProperties().putAll(opts.getOpts().getProperties());
this.templatingEngine = this.config.getTemplatingEngine();

String ignoreFileLocation = this.config.getIgnoreFilePathOverride();
if (ignoreFileLocation != null) {
Expand All @@ -91,6 +94,13 @@ public Generator opts(ClientOptInput opts) {
return this;
}

private void configPostProcessMustacheCompiler() {
if (this.templatingEngine instanceof MustacheEngineAdapter) {
MustacheEngineAdapter mustacheEngineAdapter = (MustacheEngineAdapter) this.templatingEngine;
mustacheEngineAdapter.setCompiler(this.config.processCompiler(mustacheEngineAdapter.getCompiler()));
}
}

/**
* Programmatically disable the output of .openapi-generator/VERSION, .openapi-generator-ignore,
* or other metadata files used by OpenAPI Generator.
Expand Down Expand Up @@ -698,21 +708,9 @@ private void generateSupportingFiles(List<File> files, Map<String, Object> bundl
}

if (ignoreProcessor.allowsFile(new File(outputFilename))) {
if (templateFile.endsWith("mustache")) {
String template = readTemplate(templateFile);
Mustache.Compiler compiler = Mustache.compiler();
compiler = config.processCompiler(compiler);
Template tmpl = 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));
if (Arrays.stream(templatingEngine.getFileExtensions()).anyMatch(templateFile::endsWith)) {
String templateContent = templatingEngine.compileTemplate(this, bundle, support.templateFile);
writeToFile(outputFilename, templateContent);
File written = new File(outputFilename);
files.add(written);
if (config.isEnablePostProcessFile()) {
Expand Down Expand Up @@ -890,6 +888,9 @@ public List<File> generate() {
configureGeneratorProperties();
configureOpenAPIInfo();

// If the template adapter is mustache, we'll set the config-modified Compiler.
configPostProcessMustacheCompiler();

List<File> files = new ArrayList<File>();
// models
List<String> filteredSchemas = ModelUtils.getSchemasUsedOnlyInFormParam(openAPI);
Expand All @@ -910,24 +911,16 @@ public List<File> generate() {
return files;
}

@Override
public String getFullTemplateContents(String templateName) {
return readTemplate(getFullTemplateFile(config, templateName));
}

protected File processTemplateToFile(Map<String, Object> templateData, String templateName, String outputFilename) throws IOException {
String adjustedOutputFilename = outputFilename.replaceAll("//", "/").replace('/', File.separatorChar);
if (ignoreProcessor.allowsFile(new File(adjustedOutputFilename))) {
String templateFile = getFullTemplateFile(config, templateName);
String template = readTemplate(templateFile);
Mustache.Compiler compiler = Mustache.compiler();
compiler = config.processCompiler(compiler);
Template tmpl = compiler
.withLoader(new Mustache.TemplateLoader() {
@Override
public Reader getTemplate(String name) {
return getTemplateReader(getFullTemplateFile(config, name + ".mustache"));
}
})
.defaultValue("")
.compile(template);

writeToFile(adjustedOutputFilename, tmpl.execute(templateData));
String templateContent = templatingEngine.compileTemplate(this, templateData, templateName);
writeToFile(adjustedOutputFilename, templateContent);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, also missing extension of the templating engine:

compiler = config.processCompiler(compiler);

return new File(adjustedOutputFilename);
}

Expand Down
Loading