diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java new file mode 100644 index 000000000000..029f46ed1b50 --- /dev/null +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/NancyFXServerCodegen.java @@ -0,0 +1,127 @@ +package io.swagger.codegen.languages; + +import io.swagger.codegen.CodegenConstants; +import io.swagger.codegen.CodegenOperation; +import io.swagger.codegen.CodegenType; +import io.swagger.codegen.SupportingFile; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Arrays; + +public class NancyFXServerCodegen extends AbstractCSharpCodegen { + + protected String sourceFolder = "src" + File.separator + packageName; + protected String packageGuid = "{" + java.util.UUID.randomUUID().toString().toUpperCase() + "}"; + + @SuppressWarnings("hiding") + protected Logger LOGGER = LoggerFactory.getLogger(NancyFXServerCodegen.class); + + public NancyFXServerCodegen() { + super(); + + outputFolder = "generated-code" + File.separator + this.getName(); + + modelTemplateFiles.put("model.mustache", ".cs"); + apiTemplateFiles.put("api.mustache", ".cs"); + + // contextually reserved words + setReservedWordsLowerCase( + Arrays.asList("var", "async", "await", "dynamic", "yield") + ); + + cliOptions.clear(); + + // CLI options + addOption(CodegenConstants.PACKAGE_NAME, + "C# package name (convention: Title.Case).", + this.packageName); + + addOption(CodegenConstants.PACKAGE_VERSION, + "C# package version.", + this.packageVersion); + + addOption(CodegenConstants.SOURCE_FOLDER, + CodegenConstants.SOURCE_FOLDER_DESC, + sourceFolder); + + // CLI Switches + addSwitch(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, + CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG_DESC, + this.sortParamsByRequiredFlag); + + addSwitch(CodegenConstants.OPTIONAL_PROJECT_FILE, + CodegenConstants.OPTIONAL_PROJECT_FILE_DESC, + this.optionalProjectFileFlag); + + addSwitch(CodegenConstants.USE_DATETIME_OFFSET, + CodegenConstants.USE_DATETIME_OFFSET_DESC, + this.useDateTimeOffsetFlag); + + addSwitch(CodegenConstants.USE_COLLECTION, + CodegenConstants.USE_COLLECTION_DESC, + this.useCollection); + + addSwitch(CodegenConstants.RETURN_ICOLLECTION, + CodegenConstants.RETURN_ICOLLECTION_DESC, + this.returnICollection); + } + + @Override + public CodegenType getTag() { + return CodegenType.SERVER; + } + + @Override + public String getName() { + return "nancyfx"; + } + + @Override + public String getHelp() { + return "Generates a NancyFX Web API server."; + } + + @Override + public void processOpts() { + super.processOpts(); + + String packageFolder = sourceFolder + File.separator + packageName; + apiPackage = packageName + ".Api"; + modelPackage = packageName + ".Models"; + + if (optionalProjectFileFlag) { + supportingFiles.add(new SupportingFile("Solution.mustache", "", packageName + ".sln")); + supportingFiles.add(new SupportingFile("Project.mustache", sourceFolder, packageName + ".csproj")); + } + additionalProperties.put("packageGuid", packageGuid); + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + sourceFolder + File.separator + "Api"; + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder + File.separator + "Models"; + } + + @Override + protected void processOperation(CodegenOperation operation) { + super.processOperation(operation); + + // HACK: Unlikely in the wild, but we need to clean operation paths for MVC Routing + if (operation.path != null) { + String original = operation.path; + operation.path = operation.path.replace("?", "/"); + if (!original.equals(operation.path)) { + LOGGER.warn("Normalized " + original + " to " + operation.path + ". Please verify generated source."); + } + } + + // Converts, for example, PUT to HttpPut for controller attributes + operation.httpMethod = "Http" + operation.httpMethod.substring(0, 1) + operation.httpMethod.substring(1).toLowerCase(); + } +} diff --git a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig index f0d0fde5e576..868922a6ddf8 100644 --- a/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig +++ b/modules/swagger-codegen/src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig @@ -16,6 +16,7 @@ io.swagger.codegen.languages.JavascriptClientCodegen io.swagger.codegen.languages.JavascriptClosureAngularClientCodegen io.swagger.codegen.languages.JavaJerseyServerCodegen io.swagger.codegen.languages.JMeterCodegen +io.swagger.codegen.languages.NancyFXServerCodegen io.swagger.codegen.languages.NodeJSServerCodegen io.swagger.codegen.languages.ObjcClientCodegen io.swagger.codegen.languages.PerlClientCodegen diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/Project.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/Project.mustache new file mode 100644 index 000000000000..3a753d150f6b --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/Project.mustache @@ -0,0 +1,54 @@ + + + + Debug + AnyCPU + {{packageGuid}} + Library + Properties + {{packageTitle}} + {{packageTitle}} + {{^supportsUWP}} + {{targetFramework}} + {{/supportsUWP}} + {{#supportsUWP}} + UAP + 10.0.10240.0 + 10.0.10240.0 + 14 + {{/supportsUWP}} + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/Solution.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/Solution.mustache new file mode 100644 index 000000000000..7f2d34e366ea --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/Solution.mustache @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +VisualStudioVersion = 12.0.0.0 +MinimumVisualStudioVersion = 10.0.0.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{packageName}}", "src\{{packageName}}\{{packageName}}.csproj", "{{packageGuid}}" +EndProject +Global +GlobalSection(SolutionConfigurationPlatforms) = preSolution +Debug|Any CPU = Debug|Any CPU +Release|Any CPU = Release|Any CPU +EndGlobalSection +GlobalSection(ProjectConfigurationPlatforms) = postSolution +{{packageGuid}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU +{{packageGuid}}.Debug|Any CPU.Build.0 = Debug|Any CPU +{{packageGuid}}.Release|Any CPU.ActiveCfg = Release|Any CPU +{{packageGuid}}.Release|Any CPU.Build.0 = Release|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Debug|Any CPU.Build.0 = Debug|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Release|Any CPU.ActiveCfg = Release|Any CPU +{19F1DEBC-DE5E-4517-8062-F000CD499087}.Release|Any CPU.Build.0 = Release|Any CPU +EndGlobalSection +GlobalSection(SolutionProperties) = preSolution +HideSolutionNode = FALSE +EndGlobalSection +EndGlobal \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/api.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/api.mustache new file mode 100644 index 000000000000..e9c5c919898f --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/api.mustache @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNet.Mvc; +using Newtonsoft.Json; +using Swashbuckle.SwaggerGen.Annotations; +using {{packageName}}.Models; + +namespace {{packageName}}.Controllers +{ {{#operations}} + /// + /// {{description}} + /// {{#description}}{{#basePath}} + [Route("{{basePath}}")] + {{/basePath}}[Description("{{description}}")]{{/description}} + public class {{classname}}Controller : Controller + { {{#operation}} + + /// + /// {{#summary}}{{summary}}{{/summary}} + /// + {{#notes}}/// {{notes}}{{/notes}}{{#allParams}} + /// {{description}}{{/allParams}}{{#responses}} + /// {{message}}{{/responses}} + [{{httpMethod}}] + [Route("{{path}}")] + [SwaggerOperation("{{operationId}}")]{{#returnType}} + [SwaggerResponse(200, type: typeof({{&returnType}}))]{{/returnType}} + public {{#returnType}}IActionResult{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}}({{#allParams}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) + { {{#returnType}} + string exampleJson = null; + {{#isListCollection}}{{>listReturn}}{{/isListCollection}}{{^isListCollection}}{{#isMapContainer}}{{>mapReturn}}{{/isMapContainer}}{{^isMapContainer}}{{>objectReturn}}{{/isMapContainer}}{{/isListCollection}} + {{!TODO: defaultResponse, examples, auth, consumes, produces, nickname, externalDocs, imports, security}} + return new ObjectResult(example);{{/returnType}}{{^returnType}} + throw new NotImplementedException();{{/returnType}} + } +{{/operation}} + } +{{/operations}} +} diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/bodyParam.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/bodyParam.mustache new file mode 100644 index 000000000000..02b0fa1d2dea --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/bodyParam.mustache @@ -0,0 +1 @@ +{{#isBodyParam}}[FromBody]{{&dataType}} {{paramName}}{{/isBodyParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/formParam.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/formParam.mustache new file mode 100644 index 000000000000..1e743e1e4c73 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/formParam.mustache @@ -0,0 +1 @@ +{{#isFormParam}}[FromForm]{{&dataType}} {{paramName}}{{/isFormParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/headerParam.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/headerParam.mustache new file mode 100644 index 000000000000..e61cadb11315 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/headerParam.mustache @@ -0,0 +1 @@ +{{#isHeaderParam}}[FromHeader]{{&dataType}} {{paramName}}{{/isHeaderParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/listReturn.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/listReturn.mustache new file mode 100644 index 000000000000..d609e67148c2 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/listReturn.mustache @@ -0,0 +1,4 @@ + + var example = exampleJson != null + ? JsonConvert.DeserializeObject<{{returnContainer}}<{{#returnType}}{{{returnType}}}{{/returnType}}>>(exampleJson) + : Enumerable.Empty<{{#returnType}}{{{returnType}}}{{/returnType}}>(); \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/mapReturn.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/mapReturn.mustache new file mode 100644 index 000000000000..856fb1b3507c --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/mapReturn.mustache @@ -0,0 +1,4 @@ + + var example = exampleJson != null + ? JsonConvert.DeserializeObject>(exampleJson) + : new Dictionary<{{#returnType}}{{{returnType}}}{{/returnType}}>(); \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/model.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/model.mustache new file mode 100644 index 000000000000..08aaed01f3db --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/model.mustache @@ -0,0 +1,154 @@ +using System; +using System.Linq; +using System.IO; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Runtime.Serialization; +using Newtonsoft.Json; + +{{#models}} +{{#model}} +namespace {{packageName}}.Models +{ + /// + /// {{description}} + /// + public partial class {{classname}} : {{#parent}}{{{parent}}}, {{/parent}} IEquatable<{{classname}}> + { + /// + /// Initializes a new instance of the class. + /// +{{#vars}} /// {{#description}}{{description}}{{/description}}{{^description}}{{name}}{{/description}}{{#required}} (required){{/required}}{{#defaultValue}} (default to {{defaultValue}}){{/defaultValue}}. +{{/vars}} + public {{classname}}({{#vars}}{{{datatype}}} {{name}} = null{{#hasMore}}, {{/hasMore}}{{/vars}}) + { + {{#vars}}{{#required}}// to ensure "{{name}}" is required (not null) + if ({{name}} == null) + { + throw new InvalidDataException("{{name}} is a required property for {{classname}} and cannot be null"); + } + else + { + this.{{name}} = {{name}}; + } + {{/required}}{{/vars}}{{#vars}}{{^required}}{{#defaultValue}}// use default value if no "{{name}}" provided + if ({{name}} == null) + { + this.{{name}} = {{{defaultValue}}}; + } + else + { + this.{{name}} = {{name}}; + } + {{/defaultValue}}{{^defaultValue}}this.{{name}} = {{name}}; + {{/defaultValue}}{{/required}}{{/vars}} + } + + {{#vars}} + /// + /// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{{description}}}{{/description}} + /// {{#description}} + /// {{{description}}}{{/description}} + public {{{datatype}}} {{name}} { get; set; } + + {{/vars}} + + /// + /// Returns the string presentation of the object + /// + /// String presentation of the object + public override string ToString() + { + var sb = new StringBuilder(); + sb.Append("class {{classname}} {\n"); + {{#vars}}sb.Append(" {{name}}: ").Append({{name}}).Append("\n"); + {{/vars}} + sb.Append("}\n"); + return sb.ToString(); + } + + /// + /// Returns the JSON string presentation of the object + /// + /// JSON string presentation of the object + public {{#parent}} new {{/parent}}string ToJson() + { + return JsonConvert.SerializeObject(this, Formatting.Indented); + } + + /// + /// Returns true if objects are equal + /// + /// Object to be compared + /// Boolean + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals(({{classname}})obj); + } + + /// + /// Returns true if {{classname}} instances are equal + /// + /// Instance of {{classname}} to be compared + /// Boolean + public bool Equals({{classname}} other) + { + + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return {{#vars}}{{#isNotContainer}} + ( + this.{{name}} == other.{{name}} || + this.{{name}} != null && + this.{{name}}.Equals(other.{{name}}) + ){{#hasMore}} && {{/hasMore}}{{/isNotContainer}}{{^isNotContainer}} + ( + this.{{name}} == other.{{name}} || + this.{{name}} != null && + this.{{name}}.SequenceEqual(other.{{name}}) + ){{#hasMore}} && {{/hasMore}}{{/isNotContainer}}{{/vars}}{{^vars}}false{{/vars}}; + } + + /// + /// Gets the hash code + /// + /// Hash code + public override int GetHashCode() + { + // credit: http://stackoverflow.com/a/263416/677735 + unchecked // Overflow is fine, just wrap + { + int hash = 41; + // Suitable nullity checks etc, of course :) + {{#vars}} + if (this.{{name}} != null) + hash = hash * 59 + this.{{name}}.GetHashCode(); + {{/vars}} + return hash; + } + } + + #region Operators + + public static bool operator ==({{classname}} left, {{classname}} right) + { + return Equals(left, right); + } + + public static bool operator !=({{classname}} left, {{classname}} right) + { + return !Equals(left, right); + } + + #endregion Operators + + } +{{/model}} +{{/models}} +} diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/objectReturn.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/objectReturn.mustache new file mode 100644 index 000000000000..4059a61ac0b8 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/objectReturn.mustache @@ -0,0 +1,4 @@ + + var example = exampleJson != null + ? JsonConvert.DeserializeObject<{{#returnType}}{{{returnType}}}{{/returnType}}>(exampleJson) + : default({{#returnType}}{{{returnType}}}{{/returnType}}); \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/pathParam.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/pathParam.mustache new file mode 100644 index 000000000000..5aa27eb4cb3e --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/pathParam.mustache @@ -0,0 +1 @@ +{{#isPathParam}}[FromRoute]{{&dataType}} {{paramName}}{{/isPathParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/queryParam.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/queryParam.mustache new file mode 100644 index 000000000000..42ce87a2b7fe --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/queryParam.mustache @@ -0,0 +1 @@ +{{#isQueryParam}}[FromQuery]{{&dataType}} {{paramName}}{{/isQueryParam}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/nancyfx/tags.mustache b/modules/swagger-codegen/src/main/resources/nancyfx/tags.mustache new file mode 100644 index 000000000000..c97df19949e6 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/nancyfx/tags.mustache @@ -0,0 +1 @@ +{{!TODO: Need iterable tags object...}}{{#tags}}, Tags = new[] { {{/tags}}"{{#tags}}{{tag}} {{/tags}}"{{#tags}} }{{/tags}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/NancyFXServerOptionsProvider.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/NancyFXServerOptionsProvider.java new file mode 100644 index 000000000000..e24df8847138 --- /dev/null +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/options/NancyFXServerOptionsProvider.java @@ -0,0 +1,35 @@ +package io.swagger.codegen.options; + +import com.google.common.collect.ImmutableMap; +import io.swagger.codegen.CodegenConstants; + +import java.util.Map; + +public class NancyFXServerOptionsProvider implements OptionsProvider { + public static final String PACKAGE_NAME_VALUE = "swagger_server_nancyfx"; + public static final String PACKAGE_VERSION_VALUE = "1.0.0-SNAPSHOT"; + public static final String SOURCE_FOLDER_VALUE = "src_nancyfx"; + + @Override + public String getLanguage() { + return "nancyfx"; + } + + @Override + public Map createOptions() { + ImmutableMap.Builder builder = new ImmutableMap.Builder(); + return builder.put(CodegenConstants.PACKAGE_NAME, PACKAGE_NAME_VALUE) + .put(CodegenConstants.PACKAGE_VERSION, PACKAGE_VERSION_VALUE) + .put(CodegenConstants.SOURCE_FOLDER, SOURCE_FOLDER_VALUE) + .put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, "true") + .put(CodegenConstants.USE_DATETIME_OFFSET, "true") + .put(CodegenConstants.USE_COLLECTION, "false") + .put(CodegenConstants.RETURN_ICOLLECTION, "false") + .build(); + } + + @Override + public boolean isServer() { + return true; + } +}