[F#] minor improvements (#2825)

* Add template owner of F#

Add template owner of F#

* rename fsharp-giraffe-server

* add nmfisher to tech committee

* update windows batch file

* update doc
This commit is contained in:
William Cheng 2019-05-06 22:11:50 +08:00 committed by GitHub
parent 5e92ec1b4c
commit 909d454f9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 124 additions and 91 deletions

View File

@ -48,7 +48,7 @@ OpenAPI Generator allows generation of API client libraries (SDK generation), se
| | Languages/Frameworks |
|-|-|
**API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C**, **C#** (.net 2.0, 3.5 or later), **C++** (cpp-restsdk, Qt5, Tizen), **Clojure**, **Dart (1.x, 2.x)**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client), **Kotlin**, **Lua**, **Node.js** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types) **Objective-C**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (rust, rust-server), **Scala** (akka, http4s, scalaz, swagger-async-httpclient), **Swift** (2.x, 3.x, 4.x), **Typescript** (AngularJS, Angular (2.x - 7.x), Aurelia, Axios, Fetch, Inversify, jQuery, Node, Rxjs)
**Server stubs** | **Ada**, **C#** (ASP.NET Core, NancyFx), **C++** (Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **Go** (net/http, Gin), **Haskell** (Servant), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples)), **Kotlin** (Spring Boot, Ktor), **PHP** (Laravel, Lumen, Slim, Silex, [Symfony](https://symfony.com/), [Zend Expressive](https://github.com/zendframework/zend-expressive)), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** (rust-server), **Scala** ([Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), Scalatra)
**Server stubs** | **Ada**, **C#** (ASP.NET Core, NancyFx), **C++** (Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **F#** (Giraffe), **Go** (net/http, Gin), **Haskell** (Servant), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples)), **Kotlin** (Spring Boot, Ktor), **PHP** (Laravel, Lumen, Slim, Silex, [Symfony](https://symfony.com/), [Zend Expressive](https://github.com/zendframework/zend-expressive)), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** (rust-server), **Scala** ([Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), Scalatra)
**API documentation generators** | **HTML**, **Confluence Wiki**
**Configuration files** | [**Apache2**](https://httpd.apache.org/)
**Others** | **GraphQL**, **JMeter**, **MySQL Schema**
@ -663,6 +663,7 @@ Here is a list of template creators:
* C++ Pistache: @sebymiano
* C++ Restbed: @stkrwork
* Erlang Server: @galaxie
* F# (Giraffe) Server: @nmfisher
* Go Server: @guohuang
* Go (Gin) Server: @kemokemo
* GraphQL Express Server: @renepardon
@ -745,6 +746,7 @@ If you want to join the committee, please kindly apply by sending an email to te
| Elixir | @mrmstn (2018/12) |
| Elm | @eriktim (2018/09) |
| Erlang | @tsloughter (2017/11) @jfacorro (2018/10) @robertoaloi (2018/10) |
| F# | @nmfisher (2019/05) |
| Go | @antihax (2017/11) @bvwells (2017/12) @grokify (2018/07) @kemokemo (2018/09 |
| GraphQL | @renepardon (2018/12) |
| Groovy | |

View File

@ -27,6 +27,6 @@ fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -t modules/openapi-generator/src/main/resources/fsharp-giraffe-server -g fsharp-giraffe -o samples/server/petstore/fsharp-giraffe $@"
ags="generate -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -t modules/openapi-generator/src/main/resources/fsharp-giraffe-server -g fsharp-giraffe-server -o samples/server/petstore/fsharp-giraffe $@"
java ${JAVA_OPTS} -jar ${executable} ${ags}

View File

@ -5,6 +5,6 @@ If Not Exist %executable% (
)
REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M -DloggerPath=conf/log4j.properties
set ags=generate --artifact-id "fsharp-giraffe-petstore-server" -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g fsharp-giraffe -o samples\server\petstore\fsharp-giraffe
set ags=generate --artifact-id "fsharp-giraffe-petstore-server" -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g fsharp-giraffe-server -o samples\server\petstore\fsharp-giraffe
java %JAVA_OPTS% -jar %executable% %ags%

View File

@ -71,7 +71,7 @@ The following generators are available:
- [cpp-restbed-server](generators/cpp-restbed-server.md)
- [csharp-nancyfx](generators/csharp-nancyfx.md)
- [erlang-server](generators/erlang-server.md)
- [fsharp-giraffe](generators/fsharp-giraffe.md)
- [fsharp-giraffe-server](generators/fsharp-giraffe-server.md)
- [go-gin-server](generators/go-gin-server.md)
- [go-server](generators/go-server.md)
- [graphql-nodejs-express-server](generators/graphql-nodejs-express-server.md)

View File

@ -0,0 +1,25 @@
---
id: generator-opts-server-fsharp-giraffe-server
title: Config Options for fsharp-giraffe-server
sidebar_label: fsharp-giraffe-server
---
| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
|licenseUrl|The URL of the license| |http://localhost|
|licenseName|The name of the license| |NoLicense|
|packageCopyright|Specifies an AssemblyCopyright for the .NET Framework global assembly attributes stored in the AssemblyInfo file.| |No Copyright|
|packageAuthors|Specifies Authors property in the .NET Core project file.| |OpenAPI|
|packageTitle|Specifies an AssemblyTitle for the .NET Framework global assembly attributes stored in the AssemblyInfo file.| |OpenAPI Library|
|packageName|F# module name (convention: Title.Case).| |OpenAPI|
|packageVersion|F# package version.| |1.0.0|
|packageGuid|The GUID that will be associated with the C# project| |null|
|sourceFolder|source folder for generated code| |OpenAPI/src|
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|useDateTimeOffset|Use DateTimeOffset to model date-time properties| |false|
|useCollection|Deserialize array types to Collection<T> instead of List<T>.| |false|
|returnICollection|Return ICollection<T> instead of the concrete type.| |false|
|useSwashbuckle|Uses the Swashbuckle.AspNetCore NuGet package for documentation.| |false|
|generateBody|Generates method body.| |true|
|buildTarget|Target the build for a program or library.| |program|

View File

@ -85,11 +85,11 @@ public abstract class AbstractFSharpCodegen extends DefaultCodegen implements Co
outputFolder = this.getName();
embeddedTemplateDir = templateDir = this.getName();
collectionTypes = new HashSet<String>(Arrays.asList("list", "seq"));
mapTypes = new HashSet<String>(
Arrays.asList("IDictionary")
Arrays.asList("IDictionary")
);
reservedWords.addAll(
@ -101,12 +101,12 @@ public abstract class AbstractFSharpCodegen extends DefaultCodegen implements Co
"localVarHttpContentTypes", "localVarHttpContentType",
"localVarStatusCode",
// F# reserved words
"abstract", "and", "as", "async", "await", "assert", "base","begin", "bool", "break", "byte", "case", "catch", "char", "checked",
"abstract", "and", "as", "async", "await", "assert", "base", "begin", "bool", "break", "byte", "case", "catch", "char", "checked",
"class", "const", "continue", "decimal", "default", "delegate", "do", "done", "double", "downcast", "downto", "dynamic",
"elif", "else", "end", "enum", "event", "exception", "explicit", "extern", "false", "finally", "fixed", "float", "for",
"foreach", "fun", "function", "if", "in", "inherit", "inline", "int", "interface", "internal", "is", "lazy", "let", "let!", "lock",
"match", "match!", "member", "module", "mutable", "namespace", "new", "not", "null", "of", "open", "option", "or", "override", "params",
"private", "public", "raise", "rec", "return", "return!", "sealed", "select", "static", "string", "struct", "then", "to",
"private", "public", "raise", "rec", "return", "return!", "sealed", "select", "static", "string", "struct", "then", "to",
"true", "try", "type", "upcast", "use", "use!", "val", "void", "volatile", "when", "while", "with", "yield", "yield!")
);
@ -174,7 +174,7 @@ public abstract class AbstractFSharpCodegen extends DefaultCodegen implements Co
// nullable type
nullableType = new HashSet<String>(
Arrays.asList("decimal", "bool", "int", "float", "long", "double", "string", "Guid","apiKey")
Arrays.asList("decimal", "bool", "int", "float", "long", "double", "string", "Guid", "apiKey")
);
}
@ -390,65 +390,66 @@ public abstract class AbstractFSharpCodegen extends DefaultCodegen implements Co
}
/*
* F# does not allow forward declarations, so files must be imported in the correct order.
* Output of CodeGen models must therefore bein dependency order (rather than alphabetical order, which seems to be the default).
* We achieve this by creating a comparator to check whether the first model contains any properties of the comparison model's type
* This could probably be made more efficient if absolutely needed.
*/
* F# does not allow forward declarations, so files must be imported in the correct order.
* Output of CodeGen models must therefore bein dependency order (rather than alphabetical order, which seems to be the default).
* We achieve this by creating a comparator to check whether the first model contains any properties of the comparison model's type
* This could probably be made more efficient if absolutely needed.
*/
@SuppressWarnings({"unchecked"})
public Map<String,Object> postProcessDependencyOrders(final Map<String, Object> objs) {
Comparator<String> comparator = new Comparator<String>() {
@Override public int compare(String key1, String key2) {
// Get the corresponding models
CodegenModel model1 = ModelUtils.getModelByName(key1, objs);
CodegenModel model2 = ModelUtils.getModelByName(key2, objs);
public Map<String, Object> postProcessDependencyOrders(final Map<String, Object> objs) {
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String key1, String key2) {
// Get the corresponding models
CodegenModel model1 = ModelUtils.getModelByName(key1, objs);
CodegenModel model2 = ModelUtils.getModelByName(key2, objs);
List<String> complexVars1 = new ArrayList<String>();
List<String> complexVars2 = new ArrayList<String>();
for(CodegenProperty prop : model1.vars) {
if(prop.complexType != null)
complexVars1.add(prop.complexType);
}
for(CodegenProperty prop : model2.vars) {
if(prop.complexType != null)
complexVars2.add(prop.complexType);
}
// if first has complex vars and second has none, first is greater
if(complexVars1.size() > 0 && complexVars2.size() == 0)
return 1;
List<String> complexVars1 = new ArrayList<String>();
List<String> complexVars2 = new ArrayList<String>();
// if second has complex vars and first has none, first is lesser
if(complexVars1.size() == 0 && complexVars2.size() > 0)
return -1;
for (CodegenProperty prop : model1.vars) {
if (prop.complexType != null)
complexVars1.add(prop.complexType);
}
for (CodegenProperty prop : model2.vars) {
if (prop.complexType != null)
complexVars2.add(prop.complexType);
}
// if first has complex var that matches the second's key, first is greater
if(complexVars1.contains(key2))
return 1;
// if first has complex vars and second has none, first is greater
if (complexVars1.size() > 0 && complexVars2.size() == 0)
return 1;
// if second has complex var that matches the first's key, first is lesser
if(complexVars2.contains(key1))
return -1;
// if second has complex vars and first has none, first is lesser
if (complexVars1.size() == 0 && complexVars2.size() > 0)
return -1;
// if none of the above, don't care
return 0;
// if first has complex var that matches the second's key, first is greater
if (complexVars1.contains(key2))
return 1;
}
// if second has complex var that matches the first's key, first is lesser
if (complexVars2.contains(key1))
return -1;
// if none of the above, don't care
return 0;
}
};
PriorityQueue<String> queue = new PriorityQueue<String>(objs.size(), comparator);
for(Object k : objs.keySet()) {
queue.add(k.toString());
for (Object k : objs.keySet()) {
queue.add(k.toString());
}
Map<String,Object> sorted = new LinkedHashMap<String,Object>();
while(queue.size() > 0) {
String key = queue.poll();
sorted.put(key, objs.get(key));
Map<String, Object> sorted = new LinkedHashMap<String, Object>();
while (queue.size() > 0) {
String key = queue.poll();
sorted.put(key, objs.get(key));
}
return sorted;
}
}
/**
* F# differs from other languages in that Enums are not _true_ objects; enums are compiled to integral types.
@ -789,6 +790,7 @@ public abstract class AbstractFSharpCodegen extends DefaultCodegen implements Co
/**
* Return the default value of the property
*
* @param p OpenAPI property object
* @return string presentation of the default value of the property
*/
@ -840,17 +842,17 @@ public abstract class AbstractFSharpCodegen extends DefaultCodegen implements Co
return reservedWords.contains(word);
}
public String getNullableType(Schema p, String type) {
if (languageSpecificPrimitives.contains(type)) {
if (isSupportNullable() && ModelUtils.isNullable(p) && nullableType.contains(type)) {
return type + " option";
if (languageSpecificPrimitives.contains(type)) {
if (isSupportNullable() && ModelUtils.isNullable(p) && nullableType.contains(type)) {
return type + " option";
} else {
return type;
}
} else {
return type;
return null;
}
} else {
return null;
}
}
@Override
@ -864,11 +866,11 @@ public abstract class AbstractFSharpCodegen extends DefaultCodegen implements Co
}
if (typeMapping.containsKey(openAPIType)) {
type = typeMapping.get(openAPIType);
String languageType = getNullableType(p, type);
if (languageType != null) {
return languageType;
}
type = typeMapping.get(openAPIType);
String languageType = getNullableType(p, type);
if (languageType != null) {
return languageType;
}
} else {
type = openAPIType;
}
@ -949,7 +951,7 @@ public abstract class AbstractFSharpCodegen extends DefaultCodegen implements Co
@Override
public String modelTestFileFolder() {
return outputFolder + File.separator + testFolder;
return outputFolder + File.separator + testFolder;
}
@Override
@ -962,9 +964,13 @@ public abstract class AbstractFSharpCodegen extends DefaultCodegen implements Co
return toModelName(name) + "Tests";
}
public void setLicenseUrl(String licenseUrl) {this.licenseUrl = licenseUrl;}
public void setLicenseUrl(String licenseUrl) {
this.licenseUrl = licenseUrl;
}
public void setLicenseName(String licenseName) {this.licenseName = licenseName;}
public void setLicenseName(String licenseName) {
this.licenseName = licenseName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;

View File

@ -62,18 +62,18 @@ public class FsharpGiraffeServerCodegen extends AbstractFSharpCodegen {
private boolean generateBody = true;
private String buildTarget = "program";
private String projectSdk = SDK_WEB;
public FsharpGiraffeServerCodegen() {
super();
modelPackage = "Model";
apiTemplateFiles.put("Handler.mustache", "Handler.fs");
apiTemplateFiles.put("HandlerParams.mustache", "HandlerParams.fs");
apiTemplateFiles.put("ServiceInterface.mustache", "ServiceInterface.fs");
apiTemplateFiles.put("ServiceImpl.mustache", "Service.fs");
apiTestTemplateFiles.put("HandlerTests.mustache", ".fs");
apiTestTemplateFiles.put("HandlerTestsHelper.mustache", "Helper.fs");
apiTemplateFiles.put("Handler.mustache", "Handler.fs");
apiTemplateFiles.put("HandlerParams.mustache", "HandlerParams.fs");
apiTemplateFiles.put("ServiceInterface.mustache", "ServiceInterface.fs");
apiTemplateFiles.put("ServiceImpl.mustache", "Service.fs");
apiTestTemplateFiles.put("HandlerTests.mustache", ".fs");
apiTestTemplateFiles.put("HandlerTestsHelper.mustache", "Helper.fs");
modelTemplateFiles.put("Model.mustache", ".fs");
embeddedTemplateDir = templateDir = "fsharp-giraffe-server";
@ -152,15 +152,15 @@ public class FsharpGiraffeServerCodegen extends AbstractFSharpCodegen {
public CodegenType getTag() {
return CodegenType.SERVER;
}
@Override
public String getName() {
return "fsharp-giraffe";
return "fsharp-giraffe-server";
}
@Override
public String getHelp() {
return "Generates a fsharp-giraffe server.";
return "Generates a F# Giraffe server (beta).";
}
@Override
@ -190,7 +190,7 @@ public class FsharpGiraffeServerCodegen extends AbstractFSharpCodegen {
additionalProperties.put(PROJECT_SDK, projectSdk);
// TODO - should we be supporting a Giraffe class library?
if (isLibrary)
if (isLibrary)
LOGGER.warn("Library flag not currently supported.");
String authFolder = sourceFolder + File.separator + "auth";
@ -207,11 +207,11 @@ public class FsharpGiraffeServerCodegen extends AbstractFSharpCodegen {
supportingFiles.add(new SupportingFile("AuthSchemes.mustache", authFolder, "AuthSchemes.fs"));
supportingFiles.add(new SupportingFile("Helpers.mustache", helperFolder, "Helpers.fs"));
supportingFiles.add(new SupportingFile("CustomHandlers.mustache", implFolder, "CustomHandlers.fs"));
supportingFiles.add(new SupportingFile("Project.Tests.fsproj.mustache",testFolder, packageName + "Tests.fsproj"));
supportingFiles.add(new SupportingFile("TestHelper.mustache",testFolder, "TestHelper.fs"));
supportingFiles.add(new SupportingFile("Project.Tests.fsproj.mustache", testFolder, packageName + "Tests.fsproj"));
supportingFiles.add(new SupportingFile("TestHelper.mustache", testFolder, "TestHelper.fs"));
// TODO - support Swashbuckle
if (useSwashbuckle)
if (useSwashbuckle)
LOGGER.warn("Swashbuckle flag not currently supported, this will be ignored.");
}
@ -221,9 +221,9 @@ public class FsharpGiraffeServerCodegen extends AbstractFSharpCodegen {
@Override
public String modelFileFolder() {
return super.modelFileFolder().replace("Model","model");
return super.modelFileFolder().replace("Model", "model");
}
@Override
public String apiFileFolder() {
return super.apiFileFolder() + File.separator + "api";
@ -235,7 +235,7 @@ public class FsharpGiraffeServerCodegen extends AbstractFSharpCodegen {
@Override()
public String toModelImport(String name) {
return packageName + "." + modelPackage() + "." + name;
return packageName + "." + modelPackage() + "." + name;
}
@Override
@ -249,13 +249,13 @@ public class FsharpGiraffeServerCodegen extends AbstractFSharpCodegen {
return result;
}
@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
generateJSONSpecFile(objs);
generateYAMLSpecFile(objs);
return super.postProcessSupportingFileData(objs);
}
}
@Override
protected void processOperation(CodegenOperation operation) {