Skip to content
Permalink
Browse files

Feature: Experimental Handlebars support (rienafairefr) (#2657)

* new module: openapi-generator-core
* templating engine adapters to support extension (currently only Handlebars)
* new `-e` templating engine CLI option
* adapt Generator to process Template with the passed TemplatingEngineAdpater
* add a MustacheEngineAdapter to the codegen in the unit tests
* force default MustacheEngineAdapter
* copy new core module in the root Dockerfile
* add processTemplatingEngine to CodegenConfig, to be overriden by Codegen classes if needed
* support multiple file extensions per templating engine adapter
* Extends handlebars experimental adapter with explicit contextual resolvers (e.g. map processing)
* Add new openapi-generator-core/pom.xml to release_version_update.sh
* A detailed message will be logged on missing handlebars helper
* Adds README documentation around template default and beta options
* Moves mustache package under new templating package
* Include built-in handlebars helpers which require explicit registration, and custom `startsWith` helper.
  • Loading branch information...
jimschubert committed Apr 26, 2019
1 parent 61ed2ee commit 8bbeb8b7e34f70811fb12254d570c801bcee8a12
Showing with 515 additions and 82 deletions.
  1. +1 −0 Dockerfile
  2. +8 −2 README.md
  3. +1 −0 bin/utils/release_version_update.sh
  4. +8 −0 modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java
  5. +16 −0 modules/openapi-generator-core/pom.xml
  6. +40 −0 ...pi-generator-core/src/main/java/org/openapitools/codegen/api/AbstractTemplatingEngineAdapter.java
  7. +30 −0 ...es/openapi-generator-core/src/main/java/org/openapitools/codegen/api/TemplatingEngineAdapter.java
  8. +17 −0 modules/openapi-generator-core/src/main/java/org/openapitools/codegen/api/TemplatingGenerator.java
  9. +15 −0 modules/openapi-generator/pom.xml
  10. +2 −1 modules/openapi-generator/src/main/java/org/openapitools/codegen/AbstractGenerator.java
  11. +7 −1 modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java
  12. +3 −0 modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java
  13. +20 −0 modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java
  14. +25 −32 modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java
  15. +28 −33 modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java
  16. +1 −1 ...les/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCSharpCodegen.java
  17. +1 −1 modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java
  18. +1 −1 modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ErlangClientCodegen.java
  19. +1 −1 modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java
  20. +1 −1 modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinServerCodegen.java
  21. +1 −1 ...i-generator/src/main/java/org/openapitools/codegen/languages/ScalaPlayFrameworkServerCodegen.java
  22. +75 −0 .../openapi-generator/src/main/java/org/openapitools/codegen/templating/HandlebarsEngineAdapter.java
  23. +52 −0 ...es/openapi-generator/src/main/java/org/openapitools/codegen/templating/MustacheEngineAdapter.java
  24. +65 −0 ...openapi-generator/src/main/java/org/openapitools/codegen/templating/handlebars/StringHelpers.java
  25. +1 −1 ...pi-generator/src/main/java/org/openapitools/codegen/{ → templating}/mustache/CamelCaseLambda.java
  26. +1 −1 ...i-generator/src/main/java/org/openapitools/codegen/{ → templating}/mustache/CaseFormatLambda.java
  27. +1 −1 ...api-generator/src/main/java/org/openapitools/codegen/{ → templating}/mustache/IndentedLambda.java
  28. +1 −1 ...enerator/src/main/java/org/openapitools/codegen/{ → templating}/mustache/JoinWithCommaLambda.java
  29. +1 −1 ...pi-generator/src/main/java/org/openapitools/codegen/{ → templating}/mustache/LowercaseLambda.java
  30. +1 −1 ...pi-generator/src/main/java/org/openapitools/codegen/{ → templating}/mustache/TitlecaseLambda.java
  31. +1 −1 ...pi-generator/src/main/java/org/openapitools/codegen/{ → templating}/mustache/UppercaseLambda.java
  32. 0 modules/openapi-generator/src/main/resources/typescript-axios/git_push.sh.mustache
  33. +1 −0 ...napi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJerseyServerCodegenTest.java
  34. +86 −0 ...api-generator/src/test/java/org/openapitools/codegen/templating/handlebars/StringHelpersTest.java
  35. +2 −0 pom.xml
@@ -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}

@@ -426,9 +426,12 @@ SYNOPSIS
[--artifact-version <artifact version>]
[(-c <configuration file> | --config <configuration file>)]
[-D <system properties>...]
[(-e <templating engine> | --engine <templating engine>)]
[--enable-post-process-file]
[(-g <generator name> | --generator-name <generator name>)]
[--git-repo-id <git repo id>] [--git-user-id <git user id>]
[--group-id <group id>] [--http-user-agent <http user agent>]
[--generate-alias-as-model] [--git-repo-id <git repo id>]
[--git-user-id <git user id>] [--group-id <group id>]
[--http-user-agent <http user agent>]
(-i <spec file> | --input-spec <spec file>)
[--ignore-file-override <ignore file override location>]
[--import-mappings <import mappings>...]
@@ -584,6 +587,9 @@ OpenAPI Generator core team members are contributors who have been making signif
:heart: = Link to support the contributor directly

#### Template Creator

**NOTE**: Embedded templates are only supported in _Mustache_ format. Support for all other formats is experimental and subject to change at any time.

Here is a list of template creators:
* API Clients:
* Ada: @stcarrez
@@ -36,6 +36,7 @@ echo "Release preparation: replacing $FROM with $TO in different files"
declare -a files=("modules/openapi-generator-cli/pom.xml"
"modules/openapi-generator-gradle-plugin/gradle.properties"
"modules/openapi-generator-gradle-plugin/pom.xml"
"modules/openapi-generator-core/pom.xml"
"modules/openapi-generator-maven-plugin/pom.xml"
"modules/openapi-generator-online/pom.xml"
"modules/openapi-generator/pom.xml"
@@ -70,6 +70,10 @@
description = "folder containing the template files")
private String templateDir;

@Option(name = {"-e", "--engine"}, title = "templating engine",
description = "templating engine: \"mustache\" (default) or \"handlebars\" (beta)")
private String templatingEngine;

@Option(
name = {"-a", "--auth"},
title = "authorization",
@@ -284,6 +288,10 @@ public void run() {
configurator.setTemplateDir(templateDir);
}

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

if (isNotEmpty(apiPackage)) {
configurator.setApiPackage(apiPackage);
}
@@ -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>
@@ -0,0 +1,40 @@
package org.openapitools.codegen.api;

import java.util.Locale;

/**
* Provides abstractions around the template engine adapter interface, for reuse by implementers.
*/
public abstract class AbstractTemplatingEngineAdapter implements TemplatingEngineAdapter {

/**
* Gets all possible template paths for a given location.
*
* @param location The full location of the template.
*
* @return A new array of locations, modified according to the extensions or other adapter rules.
*/
protected String[] getModifiedFileLocation(String location) {
String[] extensions = getFileExtensions();
String[] result = new String[extensions.length];
for (int i = 0; i < extensions.length; i++) {
String extension = extensions[i];
result[i] = String.format(Locale.ROOT, "%s.%s", getPathWithoutExtension(location), extension);
}
return result;
}

/**
* Returns the path without an extension for an input location.
*
* @param location The location of the file, with original file extension intact.
*
* @return The full path, without extension (e.g. /path/to/file.txt => /path/to/file)
*/
private String getPathWithoutExtension(String location) {
if (location == null) return null;
int idx = location.lastIndexOf('.');
if (idx == -1) return location;
return location.substring(0, idx);
}
}
@@ -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();
}
@@ -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);

}
@@ -215,6 +215,16 @@
<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>com.github.jknack</groupId>
<artifactId>handlebars-jackson2</artifactId>
<version>${handlebars.java-version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
@@ -300,6 +310,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>
@@ -22,6 +22,7 @@
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.api.TemplatingGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@@ -30,7 +31,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);

/**
@@ -24,6 +24,7 @@
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.servers.ServerVariable;
import org.openapitools.codegen.api.TemplatingEngineAdapter;

import java.io.File;
import java.util.List;
@@ -149,6 +150,8 @@

Compiler processCompiler(Compiler compiler);

TemplatingEngineAdapter processTemplatingEngine(TemplatingEngineAdapter templatingEngine);

String sanitizeTag(String tag);

String toApiFilename(String name);
@@ -260,8 +263,11 @@
*/
void setOpenAPI(OpenAPI openAPI);

void setTemplatingEngine(TemplatingEngineAdapter s);

TemplatingEngineAdapter getTemplatingEngine();

public boolean isEnableMinimalUpdate();

public void setEnableMinimalUpdate(boolean isEnableMinimalUpdate);

}
@@ -184,6 +184,9 @@
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: \"mustache\" (default) or \"handlebars\" (beta)";

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}
@@ -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;
@@ -111,6 +113,8 @@
protected String ignoreFilePathOverride;
// flag to indicate whether to use environment variable to post process file
protected boolean enablePostProcessFile = false;
private TemplatingEngineAdapter templatingEngine = new MustacheEngineAdapter();

// flag to indicate whether to only update files whose contents have changed
protected boolean enableMinimalUpdate = false;

@@ -462,6 +466,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) {
@@ -3828,6 +3838,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)
*
Oops, something went wrong.

0 comments on commit 8bbeb8b

Please sign in to comment.
You can’t perform that action at this time.