Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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 8bbeb8b
Show file tree
Hide file tree
Showing 35 changed files with 515 additions and 82 deletions.
1 change: 1 addition & 0 deletions Dockerfile
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-maven-plugin ${GEN_DIR}/modules/openapi-generator-maven-plugin
COPY ./modules/openapi-generator-online ${GEN_DIR}/modules/openapi-generator-online 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-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 ./modules/openapi-generator ${GEN_DIR}/modules/openapi-generator
COPY ./pom.xml ${GEN_DIR} COPY ./pom.xml ${GEN_DIR}


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


#### Template Creator #### 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: Here is a list of template creators:
* API Clients: * API Clients:
* Ada: @stcarrez * Ada: @stcarrez
Expand Down
1 change: 1 addition & 0 deletions bin/utils/release_version_update.sh
Expand Up @@ -36,6 +36,7 @@ echo "Release preparation: replacing $FROM with $TO in different files"
declare -a files=("modules/openapi-generator-cli/pom.xml" declare -a files=("modules/openapi-generator-cli/pom.xml"
"modules/openapi-generator-gradle-plugin/gradle.properties" "modules/openapi-generator-gradle-plugin/gradle.properties"
"modules/openapi-generator-gradle-plugin/pom.xml" "modules/openapi-generator-gradle-plugin/pom.xml"
"modules/openapi-generator-core/pom.xml"
"modules/openapi-generator-maven-plugin/pom.xml" "modules/openapi-generator-maven-plugin/pom.xml"
"modules/openapi-generator-online/pom.xml" "modules/openapi-generator-online/pom.xml"
"modules/openapi-generator/pom.xml" "modules/openapi-generator/pom.xml"
Expand Down
Expand Up @@ -70,6 +70,10 @@ public class Generate implements Runnable {
description = "folder containing the template files") description = "folder containing the template files")
private String templateDir; private String templateDir;


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

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


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

if (isNotEmpty(apiPackage)) { if (isNotEmpty(apiPackage)) {
configurator.setApiPackage(apiPackage); configurator.setApiPackage(apiPackage);
} }
Expand Down
16 changes: 16 additions & 0 deletions modules/openapi-generator-core/pom.xml
@@ -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);

}
15 changes: 15 additions & 0 deletions modules/openapi-generator/pom.xml
Expand Up @@ -215,6 +215,16 @@
<artifactId>jmustache</artifactId> <artifactId>jmustache</artifactId>
<version>${jmustache-version}</version> <version>${jmustache-version}</version>
</dependency> </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> <dependency>
<groupId>commons-io</groupId> <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
Expand Down Expand Up @@ -300,6 +310,11 @@
<artifactId>jackson-datatype-threetenbp</artifactId> <artifactId>jackson-datatype-threetenbp</artifactId>
<version>${jackson-threetenbp-version}</version> <version>${jackson-threetenbp-version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-core</artifactId>
<version>4.0.0-SNAPSHOT</version>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>
<repository> <repository>
Expand Down
Expand Up @@ -22,6 +22,7 @@
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.Arrays; import java.util.Arrays;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.api.TemplatingGenerator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


Expand All @@ -30,7 +31,7 @@
import java.util.Scanner; import java.util.Scanner;
import java.util.regex.Pattern; import java.util.regex.Pattern;


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


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


import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
Expand Down Expand Up @@ -149,6 +150,8 @@ public interface CodegenConfig {


Compiler processCompiler(Compiler compiler); Compiler processCompiler(Compiler compiler);


TemplatingEngineAdapter processTemplatingEngine(TemplatingEngineAdapter templatingEngine);

String sanitizeTag(String tag); String sanitizeTag(String tag);


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


void setTemplatingEngine(TemplatingEngineAdapter s);

TemplatingEngineAdapter getTemplatingEngine();

public boolean isEnableMinimalUpdate(); public boolean isEnableMinimalUpdate();


public void setEnableMinimalUpdate(boolean isEnableMinimalUpdate); public void setEnableMinimalUpdate(boolean isEnableMinimalUpdate);

} }
Expand Up @@ -184,6 +184,9 @@ public class CodegenConstants {
public static final String DOTNET_FRAMEWORK = "targetFramework"; public static final String DOTNET_FRAMEWORK = "targetFramework";
public static final String DOTNET_FRAMEWORK_DESC = "The target .NET framework version."; 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 MODEL_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case, original}


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

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


Expand Down Expand Up @@ -462,6 +466,12 @@ public Compiler processCompiler(Compiler compiler) {
return 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 // override with any special text escaping logic
@SuppressWarnings("static-method") @SuppressWarnings("static-method")
public String escapeText(String input) { public String escapeText(String input) {
Expand Down Expand Up @@ -3828,6 +3838,16 @@ public String sanitizeName(String name) {
return sanitizeName(name, "\\W"); 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) * Sanitize name (parameter, property, method, etc)
* *
Expand Down

0 comments on commit 8bbeb8b

Please sign in to comment.