├── .gitignore ├── .travis.yml ├── README.md ├── build.cmd ├── gen_client.cmd ├── gen_client_bitbucket20.cmd ├── pom.xml ├── regen_project.cmd └── src └── main ├── java └── uk │ └── co │ └── itofinity │ └── codegen │ ├── AbstractCSharpCodegen.java │ ├── CSharpRefitClientCodegen.java │ └── CsharprefitcodegenGenerator.java └── resources ├── META-INF └── services │ └── io.swagger.codegen.CodegenConfig └── csharprefit ├── ApiClient.mustache ├── Project.mustache ├── README.mustache ├── Solution.mustache ├── TestProject.mustache ├── api.mustache ├── api_doc.mustache ├── api_test.mustache ├── appveyor.mustache ├── enumClass.mustache ├── gitignore.mustache ├── model.mustache ├── modelEnum.mustache ├── modelGeneric.mustache ├── modelInnerEnum.mustache ├── model_doc.mustache ├── model_test.mustache ├── mono_nunit_test.mustache ├── partial_header.mustache ├── shared_project.mustache ├── shared_projitems.mustache └── visibility.mustache /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | clients/ 3 | gen_client_petstore.cmd 4 | gen_client_bitbucket20.cmd 5 | target/ 6 | tools/swagger-codegen-cli-2.2.3.jar 7 | CSharpRefitCodegen-swagger-codegen.iml 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | deploy: 3 | provider: releases 4 | api_key: 5 | secure: m6FYT4fT3/qhjvp/X65MnJPVDgjOrALsZsosBwLALyV+03ReiiJHQxSCepogGMD1QyLw/v6V4q7NJHtezxkDkjx+7UYMqiwj5/R+zcltIryA8Upjv8agxQJiBkRHjXZtlDom+xD3fmYDzv/02KnvK7ysygSkOL8n9oAGzeRCL98DlBpbpQslYmGTKVU2muyid5+uoX4gc1ZyNV+V42fI8biP0yRJdsjgEsjQjQ8RH4qg8/agRHBGOcNW/TXCuSnUgSA3EcKwaK72+yvZWLIIvJO9nPilTH0Ndzl3ykY3HWq1o8nA6NUbXSnKvo7l/XNcc6jTMIx14snXYgIGlXSCA6CTtegZigY1Ad3c+/4otijCezivNQqNwmbcIDaHTslCrOheLaXPGaceWYnnbu0Yi/pkIwpCNugWBwcNvyx88MfboUns17ZYIpBeKcIxAF0Fiami0eJfboYoPcrVSOpMcYj+Wv9gSEgGGvCX0A5duBZ6ZlnLAGW+MBSsm+gqvAhUNOlGxvEh6RFj3fX1eMJVoBXJjrwgV4T6Xl/v+tX1wwTcWjf17ygNHPIVyIUp1PichX5OK5KBfJYhsLMPS6/bujZwwl69HF7v+fUsBWXcmo+gzYyl0IwSQzApd5Oyk/Nr6SQ3oA4rGFHfxImQGHN+ju6g8tgb41g2g4fkpP/DUAs= 6 | file: /home/travis/build/itofinity/swagger-csharp-refit/target/CSharpRefitCodegen-swagger-codegen-1.0.0.jar 7 | skip_cleanup: true 8 | on: 9 | repo: itofinity/swagger-csharp-refit 10 | tags: true 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | swaggger_csharp_refit\# Swagger Codegen for the CSharpRefitCodegen library 2 | 3 | ## Overview 4 | This is a generator for building C# Refit based REST API clinet libraries from swagger.json files. 5 | 6 | ### Why? 7 | The existing Swagger code generators use [RestSharp](http://restsharp.org/) which is great, but I personally find bloated. I prefer the lightweight [Refit](https://github.com/paulcbetts/refit) approach. 8 | The existing Swagger code generators for C# do not handle snake_case object names used by non-C# languages in their swagger.json. 9 | 10 | ## What's Swagger? 11 | The goal of Swagger� is to define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via Swagger, a consumer can understand and interact with the remote service with a minimal amount of implementation logic. Similar to what interfaces have done for lower-level programming, Swagger removes the guesswork in calling the service. 12 | 13 | 14 | Check out [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) for additional information about the Swagger project, including additional libraries with support for other languages and more. 15 | 16 | ## Usage 17 | 18 | ### To build the generator 19 | Clone this repository. 20 | 21 | Once inside the repository folder clone the submodule: 22 | ``` 23 | git submodule init 24 | git submodule update 25 | ``` 26 | and then in the swagger-csharp-refit folder run (you will need Java + Maven installed): 27 | ``` 28 | build.cmd 29 | ``` 30 | or 31 | ``` 32 | mvn clean package 33 | ``` 34 | This will generate the codge generator 35 | ``` 36 | target/CSharpRefitCodegen-swagger-codegen-1.0.0.jar 37 | ``` 38 | 39 | ### To run the generator 40 | #### From the repository 41 | First build the generator, see above. 42 | Then download the [Swagger Codegen Cli](http://central.maven.org/maven2/io/swagger/swagger-codegen-cli/2.2.3/swagger-codegen-cli-2.2.3.jar) into the.\tools folder. 43 | Then run: 44 | ``` 45 | gen_client.cmd -i {url_or_path_to_swagger_json} -o clients/{client_name} 46 | ``` 47 | or 48 | ``` 49 | java -cp target/CSharpRefitCodegen-swagger-codegen-1.0.0.jar;tools/swagger-codegen-cli-2.2.3.jar io.swagger.codegen.SwaggerCodegen generate -l csharprefit -i {url_or_path_to_swagger_json} -o clients/{client_name} 50 | ``` 51 | #### From artifact 52 | Download the [latest jar](https://github.com/itofinity/swagger-csharp-refit/releases/latest) 53 | 54 | 55 | .\gen_client_bitbucket20.cmd gives an example of a more feature rich call. 56 | 57 | ## How was this built? 58 | The starting point was the existing CSharp generator code in swagger, this was extracted and applied over the top of a custom generator started using the [Making your own codegen modules](https://github.com/swagger-api/swagger-codegen#making-your-own-codegen-modules) process. 59 | 60 | It was tested against the Bitbucket [swagger.json](https://api.bitbucket.org/swagger.json) 61 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | mvn clean package -------------------------------------------------------------------------------- /gen_client.cmd: -------------------------------------------------------------------------------- 1 | java -cp target/CSharpRefitCodegen-swagger-codegen-1.0.2.jar;tools/swagger-codegen-cli-2.2.3.jar io.swagger.codegen.SwaggerCodegen generate -l csharprefit %* -------------------------------------------------------------------------------- /gen_client_bitbucket20.cmd: -------------------------------------------------------------------------------- 1 | rmdir /S /Q clients\bitbucket 2 | set PROJ_NAME=Itofinity.Bitbucket.Rest.Refit 3 | rem rmdir /S /Q ..\%PROJ_NAME% 4 | call gen_client.cmd ^ 5 | -i https://api.bitbucket.org/swagger.json ^ 6 | -o ^ 7 | clients/%PROJ_NAME% --api-package Api --model-package Model -DpackageName=%PROJ_NAME% -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | io.swagger 5 | CSharpRefitCodegen-swagger-codegen 6 | jar 7 | CSharpRefitCodegen-swagger-codegen 8 | 1.0.2 9 | 10 | 2.2.0 11 | 12 | 13 | 14 | 15 | org.apache.maven.plugins 16 | maven-surefire-plugin 17 | 2.12 18 | 19 | 20 | 21 | loggerPath 22 | conf/log4j.properties 23 | 24 | 25 | -Xms512m -Xmx1500m 26 | methods 27 | pertest 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-jar-plugin 35 | 2.2 36 | 37 | 38 | 39 | jar 40 | test-jar 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | org.codehaus.mojo 50 | build-helper-maven-plugin 51 | 52 | 53 | add_sources 54 | generate-sources 55 | 56 | add-source 57 | 58 | 59 | 60 | src/main/java 61 | 62 | 63 | 64 | 65 | add_test_sources 66 | generate-test-sources 67 | 68 | add-test-source 69 | 70 | 71 | 72 | src/test/java 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.apache.maven.plugins 80 | maven-compiler-plugin 81 | 3.6.1 82 | 83 | 1.7 84 | 1.7 85 | 86 | 87 | 88 | 89 | 90 | 91 | io.swagger 92 | swagger-codegen 93 | ${swagger-codegen-version} 94 | provided 95 | 96 | 97 | 98 | 2.2.3 99 | 1.0.0 100 | 4.8.1 101 | 102 | 103 | -------------------------------------------------------------------------------- /regen_project.cmd: -------------------------------------------------------------------------------- 1 | java -jar .\tools\swagger-codegen-cli-2.2.3.jar meta -o . -n CSharpRefitCodegen -p uk.co.itofinity.codegen -------------------------------------------------------------------------------- /src/main/java/uk/co/itofinity/codegen/AbstractCSharpCodegen.java: -------------------------------------------------------------------------------- 1 | package uk.co.itofinity.codegen; 2 | 3 | import io.swagger.codegen.*; 4 | import io.swagger.models.properties.*; 5 | import org.apache.commons.lang3.StringUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.io.File; 10 | import java.util.*; 11 | 12 | public abstract class AbstractCSharpCodegen extends DefaultCodegen implements CodegenConfig { 13 | 14 | protected boolean optionalProjectFileFlag = true; 15 | protected boolean optionalEmitDefaultValue = false; 16 | protected boolean optionalMethodArgumentFlag = true; 17 | protected boolean useDateTimeOffsetFlag = false; 18 | protected boolean useCollection = false; 19 | protected boolean returnICollection = false; 20 | protected boolean netCoreProjectFileFlag = false; 21 | 22 | protected String packageVersion = "1.0.0"; 23 | protected String packageName = "IO.Swagger"; 24 | protected String packageTitle = "Swagger Library"; 25 | protected String packageProductName = "SwaggerLibrary"; 26 | protected String packageDescription = "A library generated from a Swagger doc"; 27 | protected String packageCompany = "Swagger"; 28 | protected String packageCopyright = "No Copyright"; 29 | protected String packageAuthors = "Swagger"; 30 | 31 | protected String interfacePrefix = "I"; 32 | 33 | protected String sourceFolder = "src"; 34 | 35 | // TODO: Add option for test folder output location. Nice to allow e.g. ./test instead of ./src. 36 | // This would require updating relative paths (e.g. path to main project file in test project file) 37 | protected String testFolder = sourceFolder; 38 | 39 | protected Set collectionTypes; 40 | protected Set mapTypes; 41 | 42 | protected Logger LOGGER = LoggerFactory.getLogger(AbstractCSharpCodegen.class); 43 | 44 | public AbstractCSharpCodegen() { 45 | super(); 46 | 47 | // C# does not use import mapping 48 | importMapping.clear(); 49 | 50 | outputFolder = "generated-code" + File.separator + this.getName(); 51 | embeddedTemplateDir = templateDir = this.getName(); 52 | 53 | collectionTypes = new HashSet( 54 | Arrays.asList( 55 | "IList", "List", 56 | "ICollection", "Collection", 57 | "IEnumerable") 58 | ); 59 | 60 | mapTypes = new HashSet( 61 | Arrays.asList("IDictionary") 62 | ); 63 | 64 | setReservedWordsLowerCase( 65 | Arrays.asList( 66 | // set "client" as a reserved word to avoid conflicts with IO.Swagger.Client 67 | // this is a workaround and can be removed if c# api client is updated to use 68 | // fully qualified name 69 | "client", "parameter", 70 | // local variable names in API methods (endpoints) 71 | "localVarPath", "localVarPathParams", "localVarQueryParams", "localVarHeaderParams", 72 | "localVarFormParams", "localVarFileParams", "localVarStatusCode", "localVarResponse", 73 | "localVarPostBody", "localVarHttpHeaderAccepts", "localVarHttpHeaderAccept", 74 | "localVarHttpContentTypes", "localVarHttpContentType", 75 | "localVarStatusCode", 76 | // C# reserved words 77 | "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", 78 | "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else", 79 | "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", 80 | "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock", 81 | "long", "namespace", "new", "null", "object", "operator", "out", "override", "params", 82 | "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", 83 | "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw", 84 | "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", 85 | "virtual", "void", "volatile", "while", "version") 86 | ); 87 | 88 | // TODO: Either include fully qualified names here or handle in DefaultCodegen via lastIndexOf(".") search 89 | languageSpecificPrimitives = new HashSet( 90 | Arrays.asList( 91 | "String", 92 | "string", 93 | "bool?", 94 | "double?", 95 | "decimal?", 96 | "int?", 97 | "long?", 98 | "float?", 99 | "byte[]", 100 | "ICollection", 101 | "Collection", 102 | "List", 103 | "Dictionary", 104 | "DateTime?", 105 | "DateTimeOffset?", 106 | "String", 107 | "Boolean", 108 | "Double", 109 | "Int32", 110 | "Int64", 111 | "Float", 112 | "Guid?", 113 | "System.IO.Stream", // not really a primitive, we include it to avoid model import 114 | "Object") 115 | ); 116 | 117 | instantiationTypes.put("array", "List"); 118 | instantiationTypes.put("list", "List"); 119 | instantiationTypes.put("map", "Dictionary"); 120 | 121 | // Nullable types here assume C# 2 support is not part of base 122 | typeMapping = new HashMap(); 123 | typeMapping.put("string", "string"); 124 | typeMapping.put("binary", "byte[]"); 125 | typeMapping.put("bytearray", "byte[]"); 126 | typeMapping.put("boolean", "bool?"); 127 | typeMapping.put("integer", "int?"); 128 | typeMapping.put("float", "float?"); 129 | typeMapping.put("long", "long?"); 130 | typeMapping.put("double", "double?"); 131 | typeMapping.put("number", "decimal?"); 132 | typeMapping.put("datetime", "DateTime?"); 133 | typeMapping.put("date", "DateTime?"); 134 | typeMapping.put("file", "System.IO.Stream"); 135 | typeMapping.put("array", "List"); 136 | typeMapping.put("list", "List"); 137 | typeMapping.put("map", "Dictionary"); 138 | typeMapping.put("object", "Object"); 139 | typeMapping.put("uuid", "Guid?"); 140 | } 141 | 142 | public void setReturnICollection(boolean returnICollection) { 143 | this.returnICollection = returnICollection; 144 | } 145 | 146 | public void setOptionalEmitDefaultValue(boolean optionalEmitDefaultValue) { 147 | this.optionalEmitDefaultValue = optionalEmitDefaultValue; 148 | } 149 | 150 | public void setUseCollection(boolean useCollection) { 151 | this.useCollection = useCollection; 152 | if (useCollection) { 153 | typeMapping.put("array", "Collection"); 154 | typeMapping.put("list", "Collection"); 155 | 156 | instantiationTypes.put("array", "Collection"); 157 | instantiationTypes.put("list", "Collection"); 158 | } 159 | } 160 | 161 | public void setOptionalMethodArgumentFlag(boolean flag) { 162 | this.optionalMethodArgumentFlag = flag; 163 | } 164 | 165 | public void setNetCoreProjectFileFlag(boolean flag) { 166 | this.netCoreProjectFileFlag = flag; 167 | } 168 | 169 | protected void addOption(String key, String description, String defaultValue) { 170 | CliOption option = new CliOption(key, description); 171 | if (defaultValue != null) option.defaultValue(defaultValue); 172 | cliOptions.add(option); 173 | } 174 | 175 | protected void addSwitch(String key, String description, Boolean defaultValue) { 176 | CliOption option = CliOption.newBoolean(key, description); 177 | if (defaultValue != null) option.defaultValue(defaultValue.toString()); 178 | cliOptions.add(option); 179 | } 180 | 181 | public void useDateTimeOffset(boolean flag) { 182 | this.useDateTimeOffsetFlag = flag; 183 | if (flag) typeMapping.put("datetime", "DateTimeOffset?"); 184 | else typeMapping.put("datetime", "DateTime?"); 185 | } 186 | 187 | @Override 188 | public void processOpts() { 189 | super.processOpts(); 190 | 191 | // {{packageVersion}} 192 | if (additionalProperties.containsKey(CodegenConstants.PACKAGE_VERSION)) { 193 | setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION)); 194 | } else { 195 | additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion); 196 | } 197 | 198 | // {{sourceFolder}} 199 | if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) { 200 | setSourceFolder((String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER)); 201 | } else { 202 | additionalProperties.put(CodegenConstants.SOURCE_FOLDER, this.sourceFolder); 203 | } 204 | 205 | // {{packageName}} 206 | if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) { 207 | setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME)); 208 | } else { 209 | additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName); 210 | } 211 | 212 | if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) { 213 | LOGGER.warn(String.format("%s is not used by C# generators. Please use %s", CodegenConstants.INVOKER_PACKAGE, CodegenConstants.PACKAGE_NAME)); 214 | } 215 | 216 | // {{packageTitle}} 217 | if (additionalProperties.containsKey(CodegenConstants.PACKAGE_TITLE)) { 218 | setPackageTitle((String) additionalProperties.get(CodegenConstants.PACKAGE_TITLE)); 219 | } else { 220 | additionalProperties.put(CodegenConstants.PACKAGE_TITLE, packageTitle); 221 | } 222 | 223 | // {{packageProductName}} 224 | if (additionalProperties.containsKey(CodegenConstants.PACKAGE_PRODUCTNAME)) { 225 | setPackageProductName((String) additionalProperties.get(CodegenConstants.PACKAGE_PRODUCTNAME)); 226 | } else { 227 | additionalProperties.put(CodegenConstants.PACKAGE_PRODUCTNAME, packageProductName); 228 | } 229 | 230 | // {{packageDescription}} 231 | if (additionalProperties.containsKey(CodegenConstants.PACKAGE_DESCRIPTION)) { 232 | setPackageDescription((String) additionalProperties.get(CodegenConstants.PACKAGE_DESCRIPTION)); 233 | } else { 234 | additionalProperties.put(CodegenConstants.PACKAGE_DESCRIPTION, packageDescription); 235 | } 236 | 237 | // {{packageCompany}} 238 | if (additionalProperties.containsKey(CodegenConstants.PACKAGE_COMPANY)) { 239 | setPackageCompany((String) additionalProperties.get(CodegenConstants.PACKAGE_COMPANY)); 240 | } else { 241 | additionalProperties.put(CodegenConstants.PACKAGE_COMPANY, packageCompany); 242 | } 243 | 244 | // {{packageCopyright}} 245 | if (additionalProperties.containsKey(CodegenConstants.PACKAGE_COPYRIGHT)) { 246 | setPackageCopyright((String) additionalProperties.get(CodegenConstants.PACKAGE_COPYRIGHT)); 247 | } else { 248 | additionalProperties.put(CodegenConstants.PACKAGE_COPYRIGHT, packageCopyright); 249 | } 250 | 251 | // {{packageAuthors}} 252 | if (additionalProperties.containsKey(CodegenConstants.PACKAGE_AUTHORS)) { 253 | setPackageAuthors((String) additionalProperties.get(CodegenConstants.PACKAGE_AUTHORS)); 254 | } else { 255 | additionalProperties.put(CodegenConstants.PACKAGE_AUTHORS, packageAuthors); 256 | } 257 | 258 | // {{useDateTimeOffset}} 259 | if (additionalProperties.containsKey(CodegenConstants.USE_DATETIME_OFFSET)) { 260 | useDateTimeOffset(Boolean.valueOf(additionalProperties.get(CodegenConstants.USE_DATETIME_OFFSET).toString())); 261 | } 262 | additionalProperties.put(CodegenConstants.USE_DATETIME_OFFSET, useDateTimeOffsetFlag); 263 | 264 | if (additionalProperties.containsKey(CodegenConstants.USE_COLLECTION)) { 265 | setUseCollection(Boolean.valueOf(additionalProperties.get(CodegenConstants.USE_COLLECTION).toString())); 266 | } 267 | 268 | if (additionalProperties.containsKey(CodegenConstants.RETURN_ICOLLECTION)) { 269 | setReturnICollection(Boolean.valueOf(additionalProperties.get(CodegenConstants.RETURN_ICOLLECTION).toString())); 270 | } 271 | 272 | if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES)) { 273 | setOptionalEmitDefaultValue(Boolean.valueOf(additionalProperties.get(CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES).toString())); 274 | } 275 | 276 | if (additionalProperties.containsKey(CodegenConstants.NETCORE_PROJECT_FILE)) { 277 | setNetCoreProjectFileFlag(Boolean.valueOf(additionalProperties.get(CodegenConstants.NETCORE_PROJECT_FILE).toString())); 278 | } 279 | 280 | if (additionalProperties.containsKey(CodegenConstants.INTERFACE_PREFIX)) { 281 | String useInterfacePrefix = additionalProperties.get(CodegenConstants.INTERFACE_PREFIX).toString(); 282 | if("false".equals(useInterfacePrefix.toLowerCase())) { 283 | setInterfacePrefix(""); 284 | } else if(!"true".equals(useInterfacePrefix.toLowerCase())) { 285 | // NOTE: if user passes "true" explicitly, we use the default I- prefix. The other supported case here is a custom prefix. 286 | setInterfacePrefix(sanitizeName(useInterfacePrefix)); 287 | } 288 | } 289 | 290 | // This either updates additionalProperties with the above fixes, or sets the default if the option was not specified. 291 | additionalProperties.put(CodegenConstants.INTERFACE_PREFIX, interfacePrefix); 292 | } 293 | 294 | @Override 295 | public Map postProcessModels(Map objs) { 296 | List models = (List) objs.get("models"); 297 | for (Object _mo : models) { 298 | Map mo = (Map) _mo; 299 | CodegenModel cm = (CodegenModel) mo.get("model"); 300 | for (CodegenProperty var : cm.vars) { 301 | // check to see if model name is same as the property name 302 | // which will result in compilation error 303 | // if found, prepend with _ to workaround the limitation 304 | if (var.name.equalsIgnoreCase(cm.name)) { 305 | var.name = "_" + var.name; 306 | } 307 | } 308 | } 309 | // process enum in models 310 | return postProcessModelsEnum(objs); 311 | } 312 | 313 | @Override 314 | public Map postProcessOperations(Map objs) { 315 | super.postProcessOperations(objs); 316 | if (objs != null) { 317 | Map operations = (Map) objs.get("operations"); 318 | if (operations != null) { 319 | List ops = (List) operations.get("operation"); 320 | for (CodegenOperation operation : ops) { 321 | 322 | // Check return types for collection 323 | if (operation.returnType != null) { 324 | String typeMapping; 325 | int namespaceEnd = operation.returnType.lastIndexOf("."); 326 | if (namespaceEnd > 0) { 327 | typeMapping = operation.returnType.substring(namespaceEnd); 328 | } else { 329 | typeMapping = operation.returnType; 330 | } 331 | 332 | if (this.collectionTypes.contains(typeMapping)) { 333 | operation.isListContainer = true; 334 | operation.returnContainer = operation.returnType; 335 | if (this.returnICollection && ( 336 | typeMapping.startsWith("List") || 337 | typeMapping.startsWith("Collection"))) { 338 | // NOTE: ICollection works for both List and Collection 339 | int genericStart = typeMapping.indexOf("<"); 340 | if (genericStart > 0) { 341 | operation.returnType = "ICollection" + typeMapping.substring(genericStart); 342 | } 343 | } 344 | } else { 345 | operation.returnContainer = operation.returnType; 346 | operation.isMapContainer = this.mapTypes.contains(typeMapping); 347 | } 348 | } 349 | 350 | processOperation(operation); 351 | } 352 | } 353 | } 354 | 355 | return objs; 356 | } 357 | 358 | protected void processOperation(CodegenOperation operation) { 359 | // default noop 360 | } 361 | 362 | @Override 363 | public String apiFileFolder() { 364 | return outputFolder + File.separator + sourceFolder + File.separator + packageName + ".Shared" + File.separator + apiPackage(); 365 | } 366 | 367 | @Override 368 | public String modelFileFolder() { 369 | return outputFolder + File.separator + sourceFolder + File.separator + packageName + ".Shared" + File.separator + modelPackage(); 370 | } 371 | 372 | @Override 373 | public String toModelFilename(String name) { 374 | // should be the same as the model name 375 | return toModelName(name); 376 | } 377 | 378 | @Override 379 | public String toOperationId(String operationId) { 380 | // throw exception if method name is empty (should not occur as an auto-generated method name will be used) 381 | if (StringUtils.isEmpty(operationId)) { 382 | throw new RuntimeException("Empty method name (operationId) not allowed"); 383 | } 384 | 385 | // method name cannot use reserved keyword, e.g. return 386 | if (isReservedWord(operationId)) { 387 | LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + camelize(sanitizeName("call_" + operationId))); 388 | operationId = "call_" + operationId; 389 | } 390 | 391 | return camelize(sanitizeName(operationId)); 392 | } 393 | 394 | @Override 395 | public String toVarName(String name) { 396 | // sanitize name 397 | name = sanitizeName(name); 398 | 399 | // if it's all uppper case, do nothing 400 | if (name.matches("^[A-Z_]*$")) { 401 | return name; 402 | } 403 | 404 | // camelize the variable name 405 | // pet_id => PetId 406 | name = camelize(name); 407 | 408 | // for reserved word or word starting with number, append _ 409 | if (isReservedWord(name) || name.matches("^\\d.*")) { 410 | name = escapeReservedWord(name); 411 | } 412 | 413 | return name; 414 | } 415 | 416 | @Override 417 | public String toParamName(String name) { 418 | // sanitize name 419 | name = sanitizeName(name); 420 | 421 | // replace - with _ e.g. created-at => created_at 422 | name = name.replaceAll("-", "_"); 423 | 424 | // if it's all uppper case, do nothing 425 | if (name.matches("^[A-Z_]*$")) { 426 | return name; 427 | } 428 | 429 | // camelize(lower) the variable name 430 | // pet_id => petId 431 | //name = camelize(name, true); 432 | 433 | // for reserved word or word starting with number, append _ 434 | if (isReservedWord(name) || name.matches("^\\d.*")) { 435 | name = escapeReservedWord(name); 436 | } 437 | 438 | return name; 439 | } 440 | 441 | @Override 442 | public String escapeReservedWord(String name) { 443 | if(this.reservedWordsMappings().containsKey(name)) { 444 | return this.reservedWordsMappings().get(name); 445 | } 446 | return "_" + name; 447 | } 448 | 449 | /** 450 | * Return the example value of the property 451 | * 452 | * @param p Swagger property object 453 | * @return string presentation of the example value of the property 454 | */ 455 | @Override 456 | public String toExampleValue(Property p) { 457 | if (p instanceof StringProperty) { 458 | StringProperty dp = (StringProperty) p; 459 | if (dp.getExample() != null) { 460 | return "\"" + dp.getExample().toString() + "\""; 461 | } 462 | } else if (p instanceof BooleanProperty) { 463 | BooleanProperty dp = (BooleanProperty) p; 464 | if (dp.getExample() != null) { 465 | return dp.getExample().toString(); 466 | } 467 | } else if (p instanceof DateProperty) { 468 | // TODO 469 | } else if (p instanceof DateTimeProperty) { 470 | // TODO 471 | } else if (p instanceof DoubleProperty) { 472 | DoubleProperty dp = (DoubleProperty) p; 473 | if (dp.getExample() != null) { 474 | return dp.getExample().toString(); 475 | } 476 | } else if (p instanceof FloatProperty) { 477 | FloatProperty dp = (FloatProperty) p; 478 | if (dp.getExample() != null) { 479 | return dp.getExample().toString(); 480 | } 481 | } else if (p instanceof IntegerProperty) { 482 | IntegerProperty dp = (IntegerProperty) p; 483 | if (dp.getExample() != null) { 484 | return dp.getExample().toString(); 485 | } 486 | } else if (p instanceof LongProperty) { 487 | LongProperty dp = (LongProperty) p; 488 | if (dp.getExample() != null) { 489 | return dp.getExample().toString(); 490 | } 491 | } 492 | 493 | return null; 494 | } 495 | 496 | /** 497 | * Return the default value of the property 498 | * 499 | * @param p Swagger property object 500 | * @return string presentation of the default value of the property 501 | */ 502 | @Override 503 | public String toDefaultValue(Property p) { 504 | if (p instanceof StringProperty) { 505 | StringProperty dp = (StringProperty) p; 506 | if (dp.getDefault() != null) { 507 | String _default = dp.getDefault(); 508 | if (dp.getEnum() == null) { 509 | return "\"" + _default + "\""; 510 | } else { 511 | // convert to enum var name later in postProcessModels 512 | return _default; 513 | } 514 | } 515 | } else if (p instanceof BooleanProperty) { 516 | BooleanProperty dp = (BooleanProperty) p; 517 | if (dp.getDefault() != null) { 518 | return dp.getDefault().toString(); 519 | } 520 | } else if (p instanceof DateProperty) { 521 | // TODO 522 | } else if (p instanceof DateTimeProperty) { 523 | // TODO 524 | } else if (p instanceof DoubleProperty) { 525 | DoubleProperty dp = (DoubleProperty) p; 526 | if (dp.getDefault() != null) { 527 | return dp.getDefault().toString(); 528 | } 529 | } else if (p instanceof FloatProperty) { 530 | FloatProperty dp = (FloatProperty) p; 531 | if (dp.getDefault() != null) { 532 | return String.format("%1$sF", dp.getDefault()); 533 | } 534 | } else if (p instanceof IntegerProperty) { 535 | IntegerProperty dp = (IntegerProperty) p; 536 | if (dp.getDefault() != null) { 537 | return dp.getDefault().toString(); 538 | } 539 | } else if (p instanceof LongProperty) { 540 | LongProperty dp = (LongProperty) p; 541 | if (dp.getDefault() != null) { 542 | return dp.getDefault().toString(); 543 | } 544 | } 545 | 546 | return null; 547 | } 548 | 549 | @Override 550 | public String getSwaggerType(Property p) { 551 | String swaggerType = super.getSwaggerType(p); 552 | String type; 553 | if (typeMapping.containsKey(swaggerType.toLowerCase())) { 554 | type = typeMapping.get(swaggerType.toLowerCase()); 555 | if (languageSpecificPrimitives.contains(type)) { 556 | return type; 557 | } 558 | } else { 559 | type = swaggerType; 560 | } 561 | return toModelName(type); 562 | } 563 | 564 | @Override 565 | public String getTypeDeclaration(Property p) { 566 | if (p instanceof ArrayProperty) { 567 | ArrayProperty ap = (ArrayProperty) p; 568 | Property inner = ap.getItems(); 569 | return getSwaggerType(p) + "<" + getTypeDeclaration(inner) + ">"; 570 | } else if (p instanceof MapProperty) { 571 | MapProperty mp = (MapProperty) p; 572 | Property inner = mp.getAdditionalProperties(); 573 | 574 | return getSwaggerType(p) + ""; 575 | } 576 | return super.getTypeDeclaration(p); 577 | } 578 | 579 | @Override 580 | public String toModelName(String name) { 581 | if (!StringUtils.isEmpty(modelNamePrefix)) { 582 | name = modelNamePrefix + "_" + name; 583 | } 584 | 585 | if (!StringUtils.isEmpty(modelNameSuffix)) { 586 | name = name + "_" + modelNameSuffix; 587 | } 588 | 589 | name = sanitizeName(name); 590 | 591 | // model name cannot use reserved keyword, e.g. return 592 | if (isReservedWord(name)) { 593 | LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + name)); 594 | name = "model_" + name; // e.g. return => ModelReturn (after camelize) 595 | } 596 | 597 | // model name starts with number 598 | if (name.matches("^\\d.*")) { 599 | LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + camelize("model_" + name)); 600 | name = "model_" + name; // e.g. 200Response => Model200Response (after camelize) 601 | } 602 | 603 | // camelize the model name 604 | // phone_number => PhoneNumber 605 | return camelize(name); 606 | } 607 | 608 | @Override 609 | public String apiTestFileFolder() { 610 | return outputFolder + ".Test"; 611 | } 612 | 613 | @Override 614 | public String modelTestFileFolder() { 615 | return outputFolder + ".Test"; 616 | } 617 | 618 | @Override 619 | public String toApiTestFilename(String name) { 620 | return toApiName(name) + "Tests"; 621 | } 622 | 623 | @Override 624 | public String toModelTestFilename(String name) { 625 | return toModelName(name) + "Tests"; 626 | } 627 | 628 | public void setPackageName(String packageName) { 629 | this.packageName = packageName; 630 | } 631 | 632 | public void setPackageVersion(String packageVersion) { 633 | this.packageVersion = packageVersion; 634 | } 635 | 636 | public void setPackageTitle(String packageTitle) { 637 | this.packageTitle = packageTitle; 638 | } 639 | 640 | public void setPackageProductName(String packageProductName) { 641 | this.packageProductName = packageProductName; 642 | } 643 | 644 | public void setPackageDescription(String packageDescription) { 645 | this.packageDescription = packageDescription; 646 | } 647 | 648 | public void setPackageCompany(String packageCompany) { 649 | this.packageCompany = packageCompany; 650 | } 651 | 652 | public void setPackageCopyright(String packageCopyright) { 653 | this.packageCopyright = packageCopyright; 654 | } 655 | 656 | public void setPackageAuthors(String packageAuthors) { 657 | this.packageAuthors = packageAuthors; 658 | } 659 | 660 | public void setSourceFolder(String sourceFolder) { 661 | this.sourceFolder = sourceFolder; 662 | } 663 | 664 | public String getInterfacePrefix() { 665 | return interfacePrefix; 666 | } 667 | 668 | public void setInterfacePrefix(final String interfacePrefix) { 669 | this.interfacePrefix = interfacePrefix; 670 | } 671 | 672 | @Override 673 | public String toEnumVarName(String name, String datatype) { 674 | if (name.length() == 0) { 675 | return "Empty"; 676 | } 677 | 678 | // for symbol, e.g. $, # 679 | if (getSymbolName(name) != null) { 680 | return camelize(getSymbolName(name)); 681 | } 682 | 683 | String enumName = sanitizeName(name); 684 | 685 | enumName = enumName.replaceFirst("^_", ""); 686 | enumName = enumName.replaceFirst("_$", ""); 687 | 688 | enumName = camelize(enumName) + "Enum"; 689 | 690 | if (enumName.matches("\\d.*")) { // starts with number 691 | return "_" + enumName; 692 | } else { 693 | return enumName; 694 | } 695 | } 696 | 697 | @Override 698 | public String toEnumName(CodegenProperty property) { 699 | return sanitizeName(camelize(property.name)) + "Enum"; 700 | } 701 | 702 | /* 703 | @Override 704 | public String toEnumName(CodegenProperty property) { 705 | String enumName = sanitizeName(property.name); 706 | if (!StringUtils.isEmpty(modelNamePrefix)) { 707 | enumName = modelNamePrefix + "_" + enumName; 708 | } 709 | 710 | if (!StringUtils.isEmpty(modelNameSuffix)) { 711 | enumName = enumName + "_" + modelNameSuffix; 712 | } 713 | 714 | // model name cannot use reserved keyword, e.g. return 715 | if (isReservedWord(enumName)) { 716 | LOGGER.warn(enumName + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + enumName)); 717 | enumName = "model_" + enumName; // e.g. return => ModelReturn (after camelize) 718 | } 719 | 720 | if (enumName.matches("\\d.*")) { // starts with number 721 | return "_" + enumName; 722 | } else { 723 | return enumName; 724 | } 725 | } 726 | */ 727 | 728 | public String testPackageName() { 729 | return this.packageName + ".Test"; 730 | } 731 | 732 | @Override 733 | public String escapeQuotationMark(String input) { 734 | // remove " to avoid code injection 735 | return input.replace("\"", ""); 736 | } 737 | 738 | @Override 739 | public String escapeUnsafeCharacters(String input) { 740 | return input.replace("*/", "*_/").replace("/*", "/_*").replace("--", "- -"); 741 | } 742 | 743 | } 744 | -------------------------------------------------------------------------------- /src/main/java/uk/co/itofinity/codegen/CSharpRefitClientCodegen.java: -------------------------------------------------------------------------------- 1 | package uk.co.itofinity.codegen; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import io.swagger.codegen.*; 5 | import io.swagger.models.Model; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.io.File; 10 | import java.util.*; 11 | 12 | import static org.apache.commons.lang3.StringUtils.isEmpty; 13 | 14 | public class CSharpRefitClientCodegen extends AbstractCSharpCodegen { 15 | @SuppressWarnings({"unused", "hiding"}) 16 | private static final Logger LOGGER = LoggerFactory.getLogger(CSharpRefitClientCodegen.class); 17 | private static final String NET45 = "v4.5"; 18 | private static final String NET35 = "v3.5"; 19 | private static final String NETSTANDARD20 = "netStandard2.0"; 20 | private static final String UWP = "uwp"; 21 | private static final String DATA_TYPE_WITH_ENUM_EXTENSION = "plainDatatypeWithEnum"; 22 | 23 | protected String packageGuid = "{" + java.util.UUID.randomUUID().toString().toUpperCase() + "}"; 24 | protected String clientPackage = "IO.Swagger.Client"; 25 | protected String localVariablePrefix = ""; 26 | protected String apiDocPath = "docs/"; 27 | protected String modelDocPath = "docs/"; 28 | 29 | protected String targetFramework = NET45; 30 | protected String targetFrameworkNuget = "net45"; 31 | protected boolean supportsAsync = Boolean.TRUE; 32 | protected boolean supportsUWP = Boolean.FALSE; 33 | protected boolean netStandard = Boolean.FALSE; 34 | protected boolean generatePropertyChanged = Boolean.FALSE; 35 | protected Map regexModifiers; 36 | protected final Map frameworks; 37 | 38 | // By default, generated code is considered public 39 | protected boolean nonPublicApi = Boolean.FALSE; 40 | 41 | public CSharpRefitClientCodegen() { 42 | super(); 43 | modelTemplateFiles.put("model.mustache", ".cs"); 44 | apiTemplateFiles.put("api.mustache", ".cs"); 45 | 46 | modelDocTemplateFiles.put("model_doc.mustache", ".md"); 47 | apiDocTemplateFiles.put("api_doc.mustache", ".md"); 48 | 49 | cliOptions.clear(); 50 | 51 | // CLI options 52 | addOption(CodegenConstants.PACKAGE_NAME, 53 | "C# package name (convention: Title.Case).", 54 | this.packageName); 55 | 56 | addOption(CodegenConstants.PACKAGE_VERSION, 57 | "C# package version.", 58 | this.packageVersion); 59 | 60 | addOption(CodegenConstants.SOURCE_FOLDER, 61 | CodegenConstants.SOURCE_FOLDER_DESC, 62 | sourceFolder); 63 | 64 | addOption(CodegenConstants.OPTIONAL_PROJECT_GUID, 65 | CodegenConstants.OPTIONAL_PROJECT_GUID_DESC, 66 | null); 67 | 68 | addOption(CodegenConstants.INTERFACE_PREFIX, 69 | CodegenConstants.INTERFACE_PREFIX_DESC, 70 | interfacePrefix); 71 | 72 | CliOption framework = new CliOption( 73 | CodegenConstants.DOTNET_FRAMEWORK, 74 | CodegenConstants.DOTNET_FRAMEWORK_DESC 75 | ); 76 | frameworks = new ImmutableMap.Builder() 77 | .put(NET35, ".NET Framework 3.5 compatible") 78 | .put(NET45, ".NET Framework 4.5+ compatible") 79 | .put(NETSTANDARD20, ".NET Standard 2.0 compatible") 80 | .put(UWP, "Universal Windows Platform (IMPORTANT: this will be decommissioned and replaced by v5.0)") 81 | .build(); 82 | framework.defaultValue(this.targetFramework); 83 | framework.setEnum(frameworks); 84 | cliOptions.add(framework); 85 | 86 | // CLI Switches 87 | addSwitch(CodegenConstants.HIDE_GENERATION_TIMESTAMP, 88 | CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC, 89 | this.hideGenerationTimestamp); 90 | 91 | addSwitch(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, 92 | CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG_DESC, 93 | this.sortParamsByRequiredFlag); 94 | 95 | addSwitch(CodegenConstants.USE_DATETIME_OFFSET, 96 | CodegenConstants.USE_DATETIME_OFFSET_DESC, 97 | this.useDateTimeOffsetFlag); 98 | 99 | addSwitch(CodegenConstants.USE_COLLECTION, 100 | CodegenConstants.USE_COLLECTION_DESC, 101 | this.useCollection); 102 | 103 | addSwitch(CodegenConstants.RETURN_ICOLLECTION, 104 | CodegenConstants.RETURN_ICOLLECTION_DESC, 105 | this.returnICollection); 106 | 107 | addSwitch(CodegenConstants.OPTIONAL_METHOD_ARGUMENT, 108 | "C# Optional method argument, e.g. void square(int x=10) (.net 4.0+ only).", 109 | this.optionalMethodArgumentFlag); 110 | 111 | 112 | addSwitch(CodegenConstants.OPTIONAL_PROJECT_FILE, 113 | CodegenConstants.OPTIONAL_PROJECT_FILE_DESC, 114 | this.optionalProjectFileFlag); 115 | 116 | addSwitch(CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES, 117 | CodegenConstants.OPTIONAL_EMIT_DEFAULT_VALUES_DESC, 118 | this.optionalEmitDefaultValue); 119 | 120 | addSwitch(CodegenConstants.GENERATE_PROPERTY_CHANGED, 121 | CodegenConstants.PACKAGE_DESCRIPTION_DESC, 122 | this.generatePropertyChanged); 123 | 124 | // NOTE: This will reduce visibility of all public members in templates. Users can use InternalsVisibleTo 125 | // https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute(v=vs.110).aspx 126 | // to expose to shared code if the generated code is not embedded into another project. Otherwise, users of codegen 127 | // should rely on default public visibility. 128 | addSwitch(CodegenConstants.NON_PUBLIC_API, 129 | CodegenConstants.NON_PUBLIC_API_DESC, 130 | this.nonPublicApi); 131 | 132 | addSwitch(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, 133 | CodegenConstants.ALLOW_UNICODE_IDENTIFIERS_DESC, 134 | this.allowUnicodeIdentifiers); 135 | 136 | addSwitch(CodegenConstants.NETCORE_PROJECT_FILE, 137 | CodegenConstants.NETCORE_PROJECT_FILE_DESC, 138 | this.netCoreProjectFileFlag); 139 | 140 | regexModifiers = new HashMap(); 141 | regexModifiers.put('i', "IgnoreCase"); 142 | regexModifiers.put('m', "Multiline"); 143 | regexModifiers.put('s', "Singleline"); 144 | regexModifiers.put('x', "IgnorePatternWhitespace"); 145 | } 146 | 147 | @Override 148 | public void processOpts() { 149 | super.processOpts(); 150 | 151 | // default HIDE_GENERATION_TIMESTAMP to true 152 | if (!additionalProperties.containsKey(CodegenConstants.HIDE_GENERATION_TIMESTAMP)) { 153 | additionalProperties.put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, Boolean.TRUE.toString()); 154 | } else { 155 | additionalProperties.put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, 156 | Boolean.valueOf(additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP).toString())); 157 | } 158 | 159 | if(isEmpty(apiPackage)) { 160 | apiPackage = "Api"; 161 | } 162 | if(isEmpty(modelPackage)) { 163 | modelPackage = "Model"; 164 | } 165 | clientPackage = "Client"; 166 | 167 | Boolean excludeTests = false; 168 | if(additionalProperties.containsKey(CodegenConstants.EXCLUDE_TESTS)) { 169 | excludeTests = Boolean.valueOf(additionalProperties.get(CodegenConstants.EXCLUDE_TESTS).toString()); 170 | } 171 | 172 | additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage); 173 | additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage); 174 | additionalProperties.put("clientPackage", clientPackage); 175 | additionalProperties.put("emitDefaultValue", optionalEmitDefaultValue); 176 | 177 | if (!additionalProperties.containsKey("validatable")) { 178 | // default validatable to true if not set 179 | additionalProperties.put("validatable", true); 180 | } 181 | 182 | if (additionalProperties.containsKey(CodegenConstants.DOTNET_FRAMEWORK)) { 183 | setTargetFramework((String) additionalProperties.get(CodegenConstants.DOTNET_FRAMEWORK)); 184 | } else { 185 | // Ensure default is set. 186 | setTargetFramework(NET45); 187 | additionalProperties.put("targetFramework", this.targetFramework); 188 | } 189 | 190 | if (NET35.equals(this.targetFramework)) { 191 | setTargetFrameworkNuget("net35"); 192 | setSupportsAsync(Boolean.FALSE); 193 | if(additionalProperties.containsKey("supportsAsync")){ 194 | additionalProperties.remove("supportsAsync"); 195 | } 196 | additionalProperties.put("validatable", false); 197 | } else if (NETSTANDARD20.equals(this.targetFramework)){ 198 | setTargetFrameworkNuget(NETSTANDARD20); 199 | setSupportsAsync(Boolean.TRUE); 200 | setSupportsUWP(Boolean.FALSE); 201 | setNetStandard(Boolean.TRUE); 202 | additionalProperties.put("supportsAsync", this.supportsAsync); 203 | additionalProperties.put("supportsUWP", this.supportsUWP); 204 | additionalProperties.put("netStandard", this.netStandard); 205 | 206 | //Tests not yet implemented for .NET Standard codegen 207 | //Todo implement it 208 | excludeTests = true; 209 | if(additionalProperties.containsKey(CodegenConstants.EXCLUDE_TESTS)){ 210 | additionalProperties.remove(CodegenConstants.EXCLUDE_TESTS); 211 | } 212 | additionalProperties.put(CodegenConstants.EXCLUDE_TESTS, excludeTests); 213 | } else if (UWP.equals(this.targetFramework)){ 214 | setTargetFrameworkNuget("uwp"); 215 | setSupportsAsync(Boolean.TRUE); 216 | setSupportsUWP(Boolean.TRUE); 217 | additionalProperties.put("supportsAsync", this.supportsUWP); 218 | additionalProperties.put("supportsUWP", this.supportsAsync); 219 | 220 | } else { 221 | setTargetFrameworkNuget("net45"); 222 | setSupportsAsync(Boolean.TRUE); 223 | additionalProperties.put("supportsAsync", this.supportsAsync); 224 | } 225 | 226 | if(additionalProperties.containsKey(CodegenConstants.GENERATE_PROPERTY_CHANGED)) { 227 | if(NET35.equals(targetFramework)) { 228 | LOGGER.warn(CodegenConstants.GENERATE_PROPERTY_CHANGED + " is only supported by generated code for .NET 4+."); 229 | } else if(NETSTANDARD20.equals(targetFramework)) { 230 | LOGGER.warn(CodegenConstants.GENERATE_PROPERTY_CHANGED + " is not supported in .NET Standard generated code."); 231 | } else if(Boolean.TRUE.equals(netCoreProjectFileFlag)) { 232 | LOGGER.warn(CodegenConstants.GENERATE_PROPERTY_CHANGED + " is not supported in .NET Core csproj project format."); 233 | } else { 234 | setGeneratePropertyChanged(Boolean.valueOf(additionalProperties.get(CodegenConstants.GENERATE_PROPERTY_CHANGED).toString())); 235 | } 236 | 237 | if(Boolean.FALSE.equals(this.generatePropertyChanged)) { 238 | additionalProperties.remove(CodegenConstants.GENERATE_PROPERTY_CHANGED); 239 | } 240 | } 241 | 242 | additionalProperties.put("targetFrameworkNuget", this.targetFrameworkNuget); 243 | 244 | if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_PROJECT_FILE)) { 245 | setOptionalProjectFileFlag(Boolean.valueOf( 246 | additionalProperties.get(CodegenConstants.OPTIONAL_PROJECT_FILE).toString())); 247 | } 248 | 249 | if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_PROJECT_GUID)) { 250 | setPackageGuid((String) additionalProperties.get(CodegenConstants.OPTIONAL_PROJECT_GUID)); 251 | } 252 | additionalProperties.put("packageGuid", packageGuid); 253 | 254 | if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_METHOD_ARGUMENT)) { 255 | setOptionalMethodArgumentFlag(Boolean.valueOf(additionalProperties 256 | .get(CodegenConstants.OPTIONAL_METHOD_ARGUMENT).toString())); 257 | } 258 | additionalProperties.put("optionalMethodArgument", optionalMethodArgumentFlag); 259 | 260 | if (additionalProperties.containsKey(CodegenConstants.NON_PUBLIC_API)) { 261 | setNonPublicApi(Boolean.valueOf(additionalProperties.get(CodegenConstants.NON_PUBLIC_API).toString())); 262 | } 263 | 264 | final String testPackageName = testPackageName(); 265 | String packageFolder = sourceFolder + File.separator + packageName; 266 | String sharedFolder = packageFolder + ".Shared"; 267 | String clientPackageDir = sharedFolder + File.separator + clientPackage; 268 | String testPackageFolder = testFolder + File.separator + testPackageName; 269 | 270 | additionalProperties.put("testPackageName", testPackageName); 271 | 272 | //Compute the relative path to the bin directory where the external assemblies live 273 | //This is necessary to properly generate the project file 274 | int packageDepth = packageFolder.length() - packageFolder.replace(File.separator, "").length(); 275 | String binRelativePath = "..\\"; 276 | for (int i = 0; i < packageDepth; i = i + 1) 277 | binRelativePath += "..\\"; 278 | binRelativePath += "vendor"; 279 | additionalProperties.put("binRelativePath", binRelativePath); 280 | 281 | supportingFiles.add(new SupportingFile("ApiClient.mustache", 282 | clientPackageDir, "ApiClient.cs")); 283 | 284 | // Only write out test related files if excludeTests is unset or explicitly set to false (see start of this method) 285 | if(Boolean.FALSE.equals(excludeTests)) { 286 | modelTestTemplateFiles.put("model_test.mustache", ".cs"); 287 | apiTestTemplateFiles.put("api_test.mustache", ".cs"); 288 | } 289 | 290 | supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); 291 | supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")); 292 | supportingFiles.add(new SupportingFile("appveyor.mustache", "", "appveyor.yml")); 293 | // apache v2 license 294 | // UPDATE (20160612) no longer needed as the Apache v2 LICENSE is added globally 295 | //supportingFiles.add(new SupportingFile("LICENSE", "", "LICENSE")); 296 | 297 | if (optionalProjectFileFlag) { 298 | supportingFiles.add(new SupportingFile("Solution.mustache", "", packageName + ".sln")); 299 | supportingFiles.add(new SupportingFile("shared_project.mustache", sharedFolder, packageName + ".shared.shproj")); 300 | supportingFiles.add(new SupportingFile("shared_projitems.mustache", sharedFolder, packageName + ".shared.projitems")); 301 | supportingFiles.add(new SupportingFile("Project.mustache", packageFolder, packageName + ".csproj")); 302 | 303 | 304 | if(Boolean.FALSE.equals(excludeTests)) { 305 | // NOTE: This exists here rather than previous excludeTests block because the test project is considered an optional project file. 306 | supportingFiles.add(new SupportingFile("TestProject.mustache", testPackageFolder, testPackageName + ".csproj")); 307 | } 308 | } 309 | 310 | additionalProperties.put("apiDocPath", apiDocPath); 311 | additionalProperties.put("modelDocPath", modelDocPath); 312 | } 313 | 314 | @Override 315 | public Map postProcessOperations(Map objs) { 316 | super.postProcessOperations(objs); 317 | if (objs != null) { 318 | Map operations = (Map) objs.get("operations"); 319 | if (operations != null) { 320 | List ops = (List) operations.get("operation"); 321 | for (CodegenOperation operation : ops) { 322 | if (operation.returnType != null) { 323 | operation.returnContainer = operation.returnType; 324 | if (this.returnICollection && ( 325 | operation.returnType.startsWith("List") || 326 | operation.returnType.startsWith("Collection"))) { 327 | // NOTE: ICollection works for both List and Collection 328 | int genericStart = operation.returnType.indexOf("<"); 329 | if (genericStart > 0) { 330 | operation.returnType = "ICollection" + operation.returnType.substring(genericStart); 331 | } 332 | } 333 | } 334 | operation.httpMethod = camelize(operation.httpMethod.toLowerCase()); 335 | int i = 0; 336 | } 337 | } 338 | } 339 | 340 | return objs; 341 | } 342 | 343 | @Override 344 | public CodegenType getTag() { 345 | return CodegenType.CLIENT; 346 | } 347 | 348 | @Override 349 | public String getName() { 350 | return "csharprefit"; 351 | } 352 | 353 | @Override 354 | public String getHelp() { 355 | return "Generates a CSharp Refit client library."; 356 | } 357 | 358 | @Override 359 | public CodegenModel fromModel(String name, Model model, Map allDefinitions) { 360 | CodegenModel codegenModel = super.fromModel(name, model, allDefinitions); 361 | if (allDefinitions != null && codegenModel != null && codegenModel.parent != null && codegenModel.hasEnums) { 362 | final Model parentModel = allDefinitions.get(codegenModel.parentSchema); 363 | final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel); 364 | codegenModel = this.reconcileInlineEnums(codegenModel, parentCodegenModel); 365 | } 366 | 367 | return codegenModel; 368 | } 369 | 370 | public void setOptionalProjectFileFlag(boolean flag) { 371 | this.optionalProjectFileFlag = flag; 372 | } 373 | 374 | public void setPackageGuid(String packageGuid) { 375 | this.packageGuid = packageGuid; 376 | } 377 | 378 | @Override 379 | public Map postProcessModels(Map objMap) { 380 | return super.postProcessModels(objMap); 381 | } 382 | 383 | @Override 384 | public void postProcessParameter(CodegenParameter parameter) { 385 | postProcessPattern(parameter.pattern, parameter.vendorExtensions); 386 | super.postProcessParameter(parameter); 387 | } 388 | 389 | @Override 390 | public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { 391 | postProcessPattern(property.pattern, property.vendorExtensions); 392 | super.postProcessModelProperty(model, property); 393 | } 394 | 395 | 396 | /* 397 | * The swagger pattern spec follows the Perl convention and style of modifiers. .NET 398 | * does not support this syntax directly so we need to convert the pattern to a .NET compatible 399 | * format and apply modifiers in a compatible way. 400 | * See https://msdn.microsoft.com/en-us/library/yd1hzczs(v=vs.110).aspx for .NET options. 401 | * See https://github.com/swagger-api/swagger-codegen/pull/2794 for Python's initial implementation from which this is copied. 402 | */ 403 | public void postProcessPattern(String pattern, Map vendorExtensions) { 404 | if(pattern != null) { 405 | int i = pattern.lastIndexOf('/'); 406 | 407 | //Must follow Perl /pattern/modifiers convention 408 | if(pattern.charAt(0) != '/' || i < 2) { 409 | throw new IllegalArgumentException("Pattern must follow the Perl " 410 | + "/pattern/modifiers convention. "+pattern+" is not valid."); 411 | } 412 | 413 | String regex = pattern.substring(1, i).replace("'", "\'"); 414 | List modifiers = new ArrayList(); 415 | 416 | // perl requires an explicit modifier to be culture specific and .NET is the reverse. 417 | modifiers.add("CultureInvariant"); 418 | 419 | for(char c : pattern.substring(i).toCharArray()) { 420 | if(regexModifiers.containsKey(c)) { 421 | String modifier = regexModifiers.get(c); 422 | modifiers.add(modifier); 423 | } else if (c == 'l') { 424 | modifiers.remove("CultureInvariant"); 425 | } 426 | } 427 | 428 | vendorExtensions.put("x-regex", regex); 429 | vendorExtensions.put("x-modifiers", modifiers); 430 | } 431 | } 432 | 433 | public void setTargetFramework(String dotnetFramework) { 434 | if(!frameworks.containsKey(dotnetFramework)){ 435 | LOGGER.warn("Invalid .NET framework version, defaulting to " + this.targetFramework); 436 | } else { 437 | this.targetFramework = dotnetFramework; 438 | } 439 | LOGGER.info("Generating code for .NET Framework " + this.targetFramework); 440 | } 441 | 442 | private CodegenModel reconcileInlineEnums(CodegenModel codegenModel, CodegenModel parentCodegenModel) { 443 | // This generator uses inline classes to define enums, which breaks when 444 | // dealing with models that have subTypes. To clean this up, we will analyze 445 | // the parent and child models, look for enums that match, and remove 446 | // them from the child models and leave them in the parent. 447 | // Because the child models extend the parents, the enums will be available via the parent. 448 | 449 | // Only bother with reconciliation if the parent model has enums. 450 | if (parentCodegenModel.hasEnums) { 451 | 452 | // Get the properties for the parent and child models 453 | final List parentModelCodegenProperties = parentCodegenModel.vars; 454 | List codegenProperties = codegenModel.vars; 455 | 456 | // Iterate over all of the parent model properties 457 | boolean removedChildEnum = false; 458 | for (CodegenProperty parentModelCodegenPropery : parentModelCodegenProperties) { 459 | // Look for enums 460 | if (parentModelCodegenPropery.isEnum) { 461 | // Now that we have found an enum in the parent class, 462 | // and search the child class for the same enum. 463 | Iterator iterator = codegenProperties.iterator(); 464 | while (iterator.hasNext()) { 465 | CodegenProperty codegenProperty = iterator.next(); 466 | if (codegenProperty.isEnum && codegenProperty.equals(parentModelCodegenPropery)) { 467 | // We found an enum in the child class that is 468 | // a duplicate of the one in the parent, so remove it. 469 | iterator.remove(); 470 | removedChildEnum = true; 471 | } 472 | } 473 | } 474 | } 475 | 476 | if(removedChildEnum) { 477 | // If we removed an entry from this model's vars, we need to ensure hasMore is updated 478 | int count = 0, numVars = codegenProperties.size(); 479 | for(CodegenProperty codegenProperty : codegenProperties) { 480 | count += 1; 481 | codegenProperty.hasMore = (count < numVars) ? true : null; 482 | } 483 | codegenModel.vars = codegenProperties; 484 | } 485 | } 486 | 487 | return codegenModel; 488 | } 489 | 490 | @Override 491 | public String toEnumValue(String value, String datatype) { 492 | if ("int?".equalsIgnoreCase(datatype) || "long?".equalsIgnoreCase(datatype) || 493 | "double?".equalsIgnoreCase(datatype) || "float?".equalsIgnoreCase(datatype)) { 494 | return value; 495 | } else { 496 | return "\"" + escapeText(value) + "\""; 497 | } 498 | } 499 | 500 | @Override 501 | public String toEnumVarName(String value, String datatype) { 502 | if (value.length() == 0) { 503 | return "Empty"; 504 | } 505 | 506 | // for symbol, e.g. $, # 507 | if (getSymbolName(value) != null) { 508 | return camelize(getSymbolName(value)); 509 | } 510 | 511 | // number 512 | if ("int?".equals(datatype) || "long?".equals(datatype) || 513 | "double?".equals(datatype) || "float?".equals(datatype)) { 514 | String varName = "NUMBER_" + value; 515 | varName = varName.replaceAll("-", "MINUS_"); 516 | varName = varName.replaceAll("\\+", "PLUS_"); 517 | varName = varName.replaceAll("\\.", "_DOT_"); 518 | return varName; 519 | } 520 | 521 | // string 522 | String var = value.replaceAll("_", " "); 523 | //var = WordUtils.capitalizeFully(var); 524 | var = camelize(var); 525 | var = var.replaceAll("\\W+", ""); 526 | 527 | if (var.matches("\\d.*")) { 528 | return "_" + var; 529 | } else { 530 | return var; 531 | } 532 | } 533 | 534 | 535 | public void setPackageName(String packageName) { 536 | this.packageName = packageName; 537 | } 538 | 539 | public void setPackageVersion(String packageVersion) { 540 | this.packageVersion = packageVersion; 541 | } 542 | 543 | public void setTargetFrameworkNuget(String targetFrameworkNuget) { 544 | this.targetFrameworkNuget = targetFrameworkNuget; 545 | } 546 | 547 | public void setSupportsAsync(Boolean supportsAsync){ 548 | this.supportsAsync = supportsAsync; 549 | } 550 | 551 | public void setSupportsUWP(Boolean supportsUWP){ 552 | this.supportsUWP = supportsUWP; 553 | } 554 | 555 | public void setNetStandard(Boolean netStandard){ 556 | this.netStandard = netStandard; 557 | } 558 | 559 | public void setGeneratePropertyChanged(final Boolean generatePropertyChanged){ 560 | this.generatePropertyChanged = generatePropertyChanged; 561 | } 562 | 563 | public boolean isNonPublicApi() { 564 | return nonPublicApi; 565 | } 566 | 567 | public void setNonPublicApi(final boolean nonPublicApi) { 568 | this.nonPublicApi = nonPublicApi; 569 | } 570 | 571 | @Override 572 | public String toModelDocFilename(String name) { 573 | return toModelFilename(name); 574 | } 575 | 576 | @Override 577 | public String apiDocFileFolder() { 578 | return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar); 579 | } 580 | 581 | @Override 582 | public String modelDocFileFolder() { 583 | return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar); 584 | } 585 | 586 | @Override 587 | public String apiTestFileFolder() { 588 | return outputFolder + File.separator + testFolder + File.separator + testPackageName() + File.separator + apiPackage(); 589 | } 590 | 591 | @Override 592 | public String modelTestFileFolder() { 593 | return outputFolder + File.separator + testFolder + File.separator + testPackageName() + File.separator + modelPackage(); 594 | } 595 | } 596 | -------------------------------------------------------------------------------- /src/main/java/uk/co/itofinity/codegen/CsharprefitcodegenGenerator.java: -------------------------------------------------------------------------------- 1 | package uk.co.itofinity.codegen; 2 | 3 | import io.swagger.codegen.*; 4 | import io.swagger.models.properties.*; 5 | 6 | import java.util.*; 7 | import java.io.File; 8 | 9 | public class CsharprefitcodegenGenerator extends DefaultCodegen implements CodegenConfig { 10 | 11 | // source folder where to write the files 12 | protected String sourceFolder = "src"; 13 | protected String apiVersion = "1.0.0"; 14 | 15 | /** 16 | * Configures the type of generator. 17 | * 18 | * @return the CodegenType for this generator 19 | * @see io.swagger.codegen.CodegenType 20 | */ 21 | public CodegenType getTag() { 22 | return CodegenType.CLIENT; 23 | } 24 | 25 | /** 26 | * Configures a friendly name for the generator. This will be used by the generator 27 | * to select the library with the -l flag. 28 | * 29 | * @return the friendly name for the generator 30 | */ 31 | public String getName() { 32 | return "CSharpRefitCodegen"; 33 | } 34 | 35 | /** 36 | * Returns human-friendly help for the generator. Provide the consumer with help 37 | * tips, parameters here 38 | * 39 | * @return A string value for the help message 40 | */ 41 | public String getHelp() { 42 | return "Generates a CSharpRefitCodegen client library."; 43 | } 44 | 45 | public CsharprefitcodegenGenerator() { 46 | super(); 47 | 48 | // set the output folder here 49 | outputFolder = "generated-code/CSharpRefitCodegen"; 50 | 51 | /** 52 | * Models. You can write model files using the modelTemplateFiles map. 53 | * if you want to create one template for file, you can do so here. 54 | * for multiple files for model, just put another entry in the `modelTemplateFiles` with 55 | * a different extension 56 | */ 57 | modelTemplateFiles.put( 58 | "model.mustache", // the template to use 59 | ".sample"); // the extension for each file to write 60 | 61 | /** 62 | * Api classes. You can write classes for each Api file with the apiTemplateFiles map. 63 | * as with models, add multiple entries with different extensions for multiple files per 64 | * class 65 | */ 66 | apiTemplateFiles.put( 67 | "api.mustache", // the template to use 68 | ".sample"); // the extension for each file to write 69 | 70 | /** 71 | * Template Location. This is the location which templates will be read from. The generator 72 | * will use the resource stream to attempt to read the templates. 73 | */ 74 | templateDir = "CSharpRefitCodegen"; 75 | 76 | /** 77 | * Api Package. Optional, if needed, this can be used in templates 78 | */ 79 | apiPackage = "io.swagger.client.api"; 80 | 81 | /** 82 | * Model Package. Optional, if needed, this can be used in templates 83 | */ 84 | modelPackage = "io.swagger.client.model"; 85 | 86 | /** 87 | * Reserved words. Override this with reserved words specific to your language 88 | */ 89 | reservedWords = new HashSet ( 90 | Arrays.asList( 91 | "sample1", // replace with static values 92 | "sample2") 93 | ); 94 | 95 | /** 96 | * Additional Properties. These values can be passed to the templates and 97 | * are available in models, apis, and supporting files 98 | */ 99 | additionalProperties.put("apiVersion", apiVersion); 100 | 101 | /** 102 | * Supporting Files. You can write single files for the generator with the 103 | * entire object tree available. If the input file has a suffix of `.mustache 104 | * it will be processed by the template engine. Otherwise, it will be copied 105 | */ 106 | supportingFiles.add(new SupportingFile("myFile.mustache", // the input template or file 107 | "", // the destination folder, relative `outputFolder` 108 | "myFile.sample") // the output file 109 | ); 110 | 111 | /** 112 | * Language Specific Primitives. These types will not trigger imports by 113 | * the client generator 114 | */ 115 | languageSpecificPrimitives = new HashSet( 116 | Arrays.asList( 117 | "Type1", // replace these with your types 118 | "Type2") 119 | ); 120 | } 121 | 122 | /** 123 | * Escapes a reserved word as defined in the `reservedWords` array. Handle escaping 124 | * those terms here. This logic is only called if a variable matches the reseved words 125 | * 126 | * @return the escaped term 127 | */ 128 | @Override 129 | public String escapeReservedWord(String name) { 130 | return "_" + name; // add an underscore to the name 131 | } 132 | 133 | /** 134 | * Location to write model files. You can use the modelPackage() as defined when the class is 135 | * instantiated 136 | */ 137 | public String modelFileFolder() { 138 | return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar); 139 | } 140 | 141 | /** 142 | * Location to write api files. You can use the apiPackage() as defined when the class is 143 | * instantiated 144 | */ 145 | @Override 146 | public String apiFileFolder() { 147 | return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar); 148 | } 149 | 150 | /** 151 | * Optional - type declaration. This is a String which is used by the templates to instantiate your 152 | * types. There is typically special handling for different property types 153 | * 154 | * @return a string value used as the `dataType` field for model templates, `returnType` for api templates 155 | */ 156 | @Override 157 | public String getTypeDeclaration(Property p) { 158 | if(p instanceof ArrayProperty) { 159 | ArrayProperty ap = (ArrayProperty) p; 160 | Property inner = ap.getItems(); 161 | return getSwaggerType(p) + "[" + getTypeDeclaration(inner) + "]"; 162 | } 163 | else if (p instanceof MapProperty) { 164 | MapProperty mp = (MapProperty) p; 165 | Property inner = mp.getAdditionalProperties(); 166 | return getSwaggerType(p) + "[String, " + getTypeDeclaration(inner) + "]"; 167 | } 168 | return super.getTypeDeclaration(p); 169 | } 170 | 171 | /** 172 | * Optional - swagger type conversion. This is used to map swagger types in a `Property` into 173 | * either language specific types via `typeMapping` or into complex models if there is not a mapping. 174 | * 175 | * @return a string value of the type or complex model for this property 176 | * @see io.swagger.models.properties.Property 177 | */ 178 | @Override 179 | public String getSwaggerType(Property p) { 180 | String swaggerType = super.getSwaggerType(p); 181 | String type = null; 182 | if(typeMapping.containsKey(swaggerType)) { 183 | type = typeMapping.get(swaggerType); 184 | if(languageSpecificPrimitives.contains(type)) 185 | return toModelName(type); 186 | } 187 | else 188 | type = swaggerType; 189 | return toModelName(type); 190 | } 191 | } -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/io.swagger.codegen.CodegenConfig: -------------------------------------------------------------------------------- 1 | uk.co.itofinity.codegen.CSharpRefitClientCodegen -------------------------------------------------------------------------------- /src/main/resources/csharprefit/ApiClient.mustache: -------------------------------------------------------------------------------- 1 | {{>partial_header}} 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Globalization; 6 | using System.Net.Http; 7 | using System.Net.Http.Headers; 8 | using System.Text.RegularExpressions; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | using System.IO; 12 | {{^netStandard}} 13 | {{^supportsUWP}} 14 | using System.Web; 15 | {{/supportsUWP}} 16 | {{/netStandard}} 17 | using System.Linq; 18 | using System.Net; 19 | using System.Text; 20 | using Newtonsoft.Json; 21 | using Refit; 22 | using {{packageName}}.{{apiPackage}}; 23 | 24 | namespace {{packageName}}.Client 25 | { 26 | /// 27 | /// API client is mainly responsible for making the HTTP call to the API backend. 28 | /// 29 | {{>visibility}} partial class ApiClient 30 | { 31 | public ApiClient(HttpClient client) 32 | { 33 | {{#apiInfo}} 34 | {{#apis}} 35 | {{#operations}} 36 | {{classname}}Client = RestService.For<{{interfacePrefix}}{{classname}}>(client); 37 | 38 | {{/operations}} 39 | {{/apis}} 40 | {{/apiInfo}} 41 | } 42 | 43 | /// 44 | public ApiClient(string url, Func>> getSchemeAndToken) : this(new HttpClient(new AuthenticatedHttpClientHandler(getSchemeAndToken)) 45 | { 46 | BaseAddress = new Uri(url) 47 | }) 48 | { 49 | } 50 | 51 | {{#apiInfo}} 52 | {{#apis}} 53 | {{#operations}} 54 | /// 55 | public {{interfacePrefix}}{{classname}} {{classname}}Client { get; } 56 | 57 | {{/operations}} 58 | {{/apis}} 59 | {{/apiInfo}} 60 | 61 | public string Scheme { get; } 62 | 63 | public string Token { get; } 64 | 65 | private async Task> GetSchemeAndToken() 66 | { 67 | return new Tuple(Scheme, Token); 68 | } 69 | } 70 | 71 | public class AuthenticatedHttpClientHandler : HttpClientHandler 72 | { 73 | private readonly Func>> getSchemeAndToken; 74 | 75 | public AuthenticatedHttpClientHandler(Func>> getSchemeAndToken) 76 | { 77 | this.getSchemeAndToken = getSchemeAndToken; 78 | } 79 | 80 | protected override async Task SendAsync(HttpRequestMessage request, 81 | CancellationToken cancellationToken) 82 | { 83 | // See if the request has an authorize header 84 | var auth = request.Headers.Authorization; 85 | var schemeAndToken = await getSchemeAndToken().ConfigureAwait(false); 86 | 87 | if (schemeAndToken != null) 88 | { 89 | request.Headers.Authorization = new AuthenticationHeaderValue(schemeAndToken.Item1, schemeAndToken.Item2); 90 | } 91 | 92 | 93 | return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/Project.mustache: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | netstandard2.0 18 | true 19 | {{#appName}}{{{appName}}}{{/appName}} 20 | {{#appDescription}}{{{appDescription}}}{{/appDescription}} 21 | {{#version}}OpenAPI spec version: {{{version}}}{{/version}} 22 | {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/README.mustache: -------------------------------------------------------------------------------- 1 | # {{packageName}} - the C# library for the {{appName}} 2 | 3 | {{#appDescription}} 4 | {{{appDescription}}} 5 | {{/appDescription}} 6 | 7 | This C# SDK is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: 8 | 9 | - API version: {{appVersion}} 10 | - SDK version: {{packageVersion}} 11 | {{^hideGenerationTimestamp}} 12 | - Build date: {{generatedDate}} 13 | {{/hideGenerationTimestamp}} 14 | - Build package: {{generatorClass}} 15 | {{#infoUrl}} 16 | For more information, please visit [https://github.com/itofinity/swagger-csharp-refit](https://github.com/itofinity/swagger-csharp-refit) [{{{infoUrl}}}]({{{infoUrl}}}) 17 | {{/infoUrl}} 18 | 19 | 20 | ## Frameworks supported 21 | - .NET Standard >= 2.0 22 | 23 | 24 | ## Dependencies 25 | - [Refit](https://github.com/paulcbetts/refit) - 4.0.0-build.16 or later 26 | - [NUnit](http://nunit.org/) - 3.7.1 or later 27 | 28 | 29 | ## Installation 30 | Generate the DLL using Visual Studio 2017 (15.3.0) 31 | 32 | Then include the DLL (under the `bin` folder) in the C# project, and use the namespaces: 33 | ```csharp 34 | using {{packageName}}.{{apiPackage}}; 35 | using {{packageName}}.Client; 36 | using {{packageName}}.{{modelPackage}}; 37 | ``` 38 | 39 | 40 | ## Getting Started 41 | 42 | ```csharp 43 | using System; 44 | using System.Diagnostics; 45 | using {{packageName}}.{{apiPackage}}; 46 | using {{packageName}}.Client; 47 | using {{packageName}}.{{modelPackage}}; 48 | 49 | namespace Example 50 | { 51 | public class {{operationId}}Example 52 | { 53 | public void main() 54 | { 55 | {{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}}{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}} 56 | // Configure HTTP basic authorization: {{{name}}} 57 | Configuration.Default.Username = "YOUR_USERNAME"; 58 | Configuration.Default.Password = "YOUR_PASSWORD";{{/isBasic}}{{#isApiKey}} 59 | // Configure API key authorization: {{{name}}} 60 | Configuration.Default.ApiKey.Add("{{{keyParamName}}}", "YOUR_API_KEY"); 61 | // Uncomment below to setup prefix (e.g. Bearer) for API key, if needed 62 | // Configuration.Default.ApiKeyPrefix.Add("{{{keyParamName}}}", "Bearer");{{/isApiKey}}{{#isOAuth}} 63 | // Configure OAuth2 access token for authorization: {{{name}}} 64 | Configuration.Default.AccessToken = "YOUR_ACCESS_TOKEN";{{/isOAuth}}{{/authMethods}} 65 | {{/hasAuthMethods}} 66 | 67 | var apiInstance = new {{classname}}(); 68 | {{#allParams}} 69 | {{#isPrimitiveType}} 70 | var {{paramName}} = {{{example}}}; // {{{dataType}}} | {{{description}}}{{^required}} (optional) {{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} 71 | {{/isPrimitiveType}} 72 | {{^isPrimitiveType}} 73 | var {{paramName}} = new {{{dataType}}}(); // {{{dataType}}} | {{{description}}}{{^required}} (optional) {{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} 74 | {{/isPrimitiveType}} 75 | {{/allParams}} 76 | 77 | try 78 | { 79 | {{#summary}} 80 | // {{{.}}} 81 | {{/summary}} 82 | {{#returnType}}{{{.}}} result = {{/returnType}}apiInstance.{{{operationId}}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{#returnType}} 83 | Debug.WriteLine(result);{{/returnType}} 84 | } 85 | catch (Exception e) 86 | { 87 | Debug.Print("Exception when calling {{classname}}.{{operationId}}: " + e.Message ); 88 | } 89 | } 90 | } 91 | }{{/-first}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}} 92 | ``` 93 | 94 | 95 | ## Documentation for API Endpoints 96 | 97 | All URIs are relative to *{{{basePath}}}* 98 | 99 | Class | Method | HTTP request | Description 100 | ------------ | ------------- | ------------- | ------------- 101 | {{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{{summary}}}{{/summary}} 102 | {{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} 103 | 104 | 105 | ## Documentation for Models 106 | 107 | {{#modelPackage}} 108 | {{#models}}{{#model}} - [{{{modelPackage}}}.{{{classname}}}]({{modelDocPath}}{{{classname}}}.md) 109 | {{/model}}{{/models}} 110 | {{/modelPackage}} 111 | {{^modelPackage}} 112 | No model defined in this package 113 | {{/modelPackage}} 114 | 115 | 116 | ## Documentation for Authorization 117 | 118 | {{^authMethods}} 119 | All endpoints do not require authorization. 120 | {{/authMethods}} 121 | {{#authMethods}} 122 | {{#last}} 123 | Authentication schemes defined for the API: 124 | {{/last}} 125 | {{/authMethods}} 126 | {{#authMethods}} 127 | 128 | ### {{name}} 129 | 130 | {{#isApiKey}}- **Type**: API key 131 | - **API key parameter name**: {{keyParamName}} 132 | - **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}} 133 | {{/isApiKey}} 134 | {{#isBasic}}- **Type**: HTTP basic authentication 135 | {{/isBasic}} 136 | {{#isOAuth}}- **Type**: OAuth 137 | - **Flow**: {{flow}} 138 | - **Authorization URL**: {{authorizationUrl}} 139 | - **Scopes**: {{^scopes}}N/A{{/scopes}} 140 | {{#scopes}} - {{scope}}: {{description}} 141 | {{/scopes}} 142 | {{/isOAuth}} 143 | 144 | {{/authMethods}} 145 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/Solution.mustache: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.26621.2 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "{{packageName}}.Shared", "src\{{packageName}}.Shared\{{packageName}}.Shared.shproj", "{E563B1D4-8996-4D29-B045-46D309ABD843}" 6 | EndProject 7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "{{packageName}}", "src\{{packageName}}\{{packageName}}.csproj", "{{packageGuid}}" 8 | EndProject 9 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "{{packageName}}.Test", "src\{{packageName}}.Test\{{packageName}}.Test.csproj", "{D0DF97B2-15CF-4774-8E8D-A0E062F6236A}" 10 | EndProject 11 | Global 12 | GlobalSection(SharedMSBuildProjectFiles) = preSolution 13 | src\{{packageName}}.Shared\{{packageName}}.Shared.projitems*{e563b1d4-8996-4d29-b045-46d309abd843}*SharedItemsImports = 13 14 | EndGlobalSection 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {{packageGuid}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {{packageGuid}}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {{packageGuid}}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {{packageGuid}}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {D0DF97B2-15CF-4774-8E8D-A0E062F6236A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {D0DF97B2-15CF-4774-8E8D-A0E062F6236A}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {D0DF97B2-15CF-4774-8E8D-A0E062F6236A}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {D0DF97B2-15CF-4774-8E8D-A0E062F6236A}.Release|Any CPU.Build.0 = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | GlobalSection(ExtensibilityGlobals) = postSolution 33 | SolutionGuid = {F74B5F85-30FA-4FF8-9049-9F984A391C40} 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/TestProject.mustache: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | netstandard2.0 18 | true 19 | {{#appName}}{{{appName}}}{{/appName}} 20 | {{#appDescription}}{{{appDescription}}}{{/appDescription}} 21 | {{#version}}OpenAPI spec version: {{{version}}}{{/version}} 22 | {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/api.mustache: -------------------------------------------------------------------------------- 1 | {{>partial_header}} 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | using System.Linq; 6 | {{#netStandard}} 7 | // TODO does this work? 8 | using Refit.Portable; 9 | {{/netStandard}} 10 | {{^netStandard}} 11 | using Refit; 12 | {{/netStandard}} 13 | using {{packageName}}.Client; 14 | {{#hasImport}}using {{packageName}}.{{modelPackage}}; 15 | {{/hasImport}} 16 | 17 | namespace {{packageName}}.{{apiPackage}} 18 | { 19 | {{#operations}} 20 | /// 21 | /// Represents a collection of functions to interact with the API endpoints 22 | /// 23 | {{>visibility}} interface {{interfacePrefix}}{{classname}} 24 | { 25 | {{#supportsAsync}} 26 | #region Asynchronous Operations 27 | {{#operation}} 28 | 29 | /// 30 | /// {{summary}} 31 | /// 32 | /// 33 | /// {{notes}} 34 | /// 35 | /// Thrown when fails to make API call 36 | {{#allParams}}/// {{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}} 37 | {{/allParams}}/// Task of {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}} 38 | [{{httpMethod}}("{{#netStandard}}.{{/netStandard}}{{{path}}}")] 39 | {{#returnType}}System.Threading.Tasks.Task<{{#returnTypePackageName}}{{{returnTypePackageName}}}.{{/returnTypePackageName}}{{{returnType}}}>{{/returnType}}{{^returnType}}System.Threading.Tasks.Task{{/returnType}} {{operationId}}([Header("UserAgent")] string userAgent{{#hasParams}}, {{/hasParams}}{{#allParams}}{{#isBodyParam}}[Body]{{/isBodyParam}}{{#isPathParam}}[AliasAs("{{paramName}}")]{{/isPathParam}}{{#isQueryParam}}[AliasAs("{{paramName}}")]{{/isQueryParam}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); 40 | {{/operation}} 41 | #endregion Asynchronous Operations 42 | {{/supportsAsync}} 43 | } 44 | {{/operations}} 45 | } 46 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/api_doc.mustache: -------------------------------------------------------------------------------- 1 | # {{packageName}}.{{apiPackage}}.{{classname}}{{#description}} 2 | {{description}}{{/description}} 3 | 4 | All URIs are relative to *{{{basePath}}}* 5 | 6 | Method | HTTP request | Description 7 | ------------- | ------------- | ------------- 8 | {{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} 9 | {{/operation}}{{/operations}} 10 | 11 | {{#operations}} 12 | {{#operation}} 13 | 14 | # **{{{operationId}}}** 15 | > {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{operationId}} ({{#allParams}}{{{dataType}}} {{paramName}}{{^required}}{{#optionalMethodArgument}} = null{{/optionalMethodArgument}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) 16 | 17 | {{{summary}}}{{#notes}} 18 | 19 | {{{notes}}}{{/notes}} 20 | 21 | ### Example 22 | ```csharp 23 | using System; 24 | using System.Diagnostics; 25 | using {{packageName}}.{{apiPackage}}; 26 | using {{packageName}}.Client; 27 | using {{packageName}}.{{modelPackage}}; 28 | 29 | namespace Example 30 | { 31 | public class {{operationId}}Example 32 | { 33 | public void main() 34 | { 35 | {{#hasAuthMethods}}{{#authMethods}}{{#isBasic}} 36 | // Configure HTTP basic authorization: {{{name}}} 37 | Configuration.Default.Username = "YOUR_USERNAME"; 38 | Configuration.Default.Password = "YOUR_PASSWORD";{{/isBasic}}{{#isApiKey}} 39 | // Configure API key authorization: {{{name}}} 40 | Configuration.Default.ApiKey.Add("{{{keyParamName}}}", "YOUR_API_KEY"); 41 | // Uncomment below to setup prefix (e.g. Bearer) for API key, if needed 42 | // Configuration.Default.ApiKeyPrefix.Add("{{{keyParamName}}}", "Bearer");{{/isApiKey}}{{#isOAuth}} 43 | // Configure OAuth2 access token for authorization: {{{name}}} 44 | Configuration.Default.AccessToken = "YOUR_ACCESS_TOKEN";{{/isOAuth}}{{/authMethods}} 45 | {{/hasAuthMethods}} 46 | 47 | var apiInstance = new {{classname}}(); 48 | {{#allParams}} 49 | {{#isPrimitiveType}} 50 | var {{paramName}} = {{{example}}}; // {{{dataType}}} | {{{description}}}{{^required}} (optional) {{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} 51 | {{/isPrimitiveType}} 52 | {{^isPrimitiveType}} 53 | var {{paramName}} = new {{{dataType}}}(); // {{{dataType}}} | {{{description}}}{{^required}} (optional) {{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} 54 | {{/isPrimitiveType}} 55 | {{/allParams}} 56 | 57 | try 58 | { 59 | {{#summary}} 60 | // {{{.}}} 61 | {{/summary}} 62 | {{#returnType}}{{returnType}} result = {{/returnType}}apiInstance.{{{operationId}}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{#returnType}} 63 | Debug.WriteLine(result);{{/returnType}} 64 | } 65 | catch (Exception e) 66 | { 67 | Debug.Print("Exception when calling {{classname}}.{{operationId}}: " + e.Message ); 68 | } 69 | } 70 | } 71 | } 72 | ``` 73 | 74 | ### Parameters 75 | {{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}} 76 | Name | Type | Description | Notes 77 | ------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}} 78 | {{#allParams}} **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}} 79 | {{/allParams}} 80 | 81 | ### Return type 82 | 83 | {{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{{returnType}}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void (empty response body){{/returnType}} 84 | 85 | ### Authorization 86 | 87 | {{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](../README.md#{{{name}}}){{^-last}}, {{/-last}}{{/authMethods}} 88 | 89 | ### HTTP request headers 90 | 91 | - **Content-Type**: {{#consumes}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} 92 | - **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}} 93 | 94 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 95 | 96 | {{/operation}} 97 | {{/operations}} 98 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/api_test.mustache: -------------------------------------------------------------------------------- 1 | {{>partial_header}} 2 | using System; 3 | using System.IO; 4 | using System.Collections.Generic; 5 | using System.Collections.ObjectModel; 6 | using System.Linq; 7 | using System.Reflection; 8 | using NUnit.Framework; 9 | using Refit; 10 | 11 | using {{packageName}}.Client; 12 | using {{packageName}}.{{apiPackage}}; 13 | {{#hasImport}}using {{packageName}}.{{modelPackage}}; 14 | {{/hasImport}} 15 | 16 | namespace {{packageName}}.Test 17 | { 18 | /// 19 | /// Class for testing {{classname}} 20 | /// 21 | /// 22 | /// This file is automatically generated by Swagger Codegen. 23 | /// Please update the test case below to test the API endpoint. 24 | /// 25 | [TestFixture] 26 | public class {{classname}}Tests 27 | { 28 | private string hostUrl = ""; 29 | private string userAgent = "{{packageName}}.Test.{{classname}}Tests"; 30 | 31 | private {{interfacePrefix}}{{classname}} instance; 32 | 33 | /// 34 | /// Setup before each unit test 35 | /// 36 | [SetUp] 37 | public void Init() 38 | { 39 | instance = RestService.For<{{interfacePrefix}}{{classname}}>(hostUrl); 40 | } 41 | 42 | /// 43 | /// Clean up after each unit test 44 | /// 45 | [TearDown] 46 | public void Cleanup() 47 | { 48 | 49 | } 50 | 51 | /// 52 | /// Test an instance of {{classname}} 53 | /// 54 | [Test] 55 | public void {{operationId}}InstanceTest() 56 | { 57 | // TODO uncomment below to test 'IsInstanceOfType' {{classname}} 58 | //Assert.IsInstanceOfType(typeof({{classname}}), instance, "instance is a {{classname}}"); 59 | } 60 | 61 | {{#operations}}{{#operation}} 62 | /// 63 | /// Test {{operationId}} 64 | /// 65 | [Test] 66 | public async void {{operationId}}Test() 67 | { 68 | // TODO uncomment below to test the method and replace null with proper value 69 | {{#allParams}} 70 | //{{{dataType}}} {{paramName}} = null; 71 | {{/allParams}} 72 | //{{#returnType}}var response = await {{/returnType}}instance.{{operationId}}(userAgent{{#hasParams}}, {{/hasParams}}{{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); 73 | {{#returnType}}//Assert.IsInstanceOf<{{{returnType}}}> (response, "response is {{{returnType}}}");{{/returnType}} 74 | } 75 | {{/operation}}{{/operations}} 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/appveyor.mustache: -------------------------------------------------------------------------------- 1 | version: 0.1.{build} 2 | image: Visual Studio 2017 Preview 3 | before_build: 4 | - ps: >- 5 | .nuget\nuget source add -source https://api.nuget.org/v3/index.json -name v3 6 | 7 | .nuget\nuget.exe restore 8 | build_script: 9 | - ps: >- 10 | dotnet build /p:Version=$Env:APPVEYOR_BUILD_VERSION 11 | test: off 12 | artifacts: 13 | - path: src\{{packageName}}\bin\Debug\*.nupkg 14 | name: Package 15 | #deploy: 16 | #- provider: NuGet 17 | # api_key: 18 | # secure: 12344567890 # your encrypted token from Nuget 19 | # artifact: Package 20 | # on: 21 | # branch: master 22 | # appveyor_repo_tag: true 23 | deploy: 24 | - provider: GitHub 25 | release: {{packageName}}-v$(appveyor_build_version) 26 | description: '{{packageName}} Release' 27 | auth_token: 28 | secure: 12344567890 # your encrypted token from GitHub 29 | artifact: Package # upload all NuGet packages to release assets 30 | draft: false 31 | prerelease: false 32 | on: 33 | branch: master # release from master branch only 34 | appveyor_repo_tag: true -------------------------------------------------------------------------------- /src/main/resources/csharprefit/enumClass.mustache: -------------------------------------------------------------------------------- 1 | /// 2 | /// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{{description}}}{{/description}} 3 | /// {{#description}} 4 | /// {{{description}}}{{/description}} 5 | [JsonConverter(typeof(StringEnumConverter))] 6 | {{>visibility}} enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} 7 | { 8 | {{#allowableValues}}{{#enumVars}} 9 | /// 10 | /// Enum {{name}} for {{{value}}} 11 | /// 12 | [EnumMember(Value = {{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isFloat}}"{{/isFloat}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isFloat}}"{{/isFloat}})] 13 | {{name}}{{#isLong}} = {{{value}}}{{/isLong}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^-last}}, 14 | {{/-last}}{{/enumVars}}{{/allowableValues}} 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/gitignore.mustache: -------------------------------------------------------------------------------- 1 | # Ref: https://gist.github.com/kmorcinek/2710267 2 | # Download this file using PowerShell v3 under Windows with the following comand 3 | # Invoke-WebRequest https://gist.githubusercontent.com/kmorcinek/2710267/raw/ -OutFile .gitignore 4 | 5 | # User-specific files 6 | *.suo 7 | *.user 8 | *.sln.docstates 9 | 10 | # Build results 11 | 12 | [Dd]ebug/ 13 | [Rr]elease/ 14 | x64/ 15 | build/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # NuGet Packages 20 | *.nupkg 21 | # The packages folder can be ignored because of Package Restore 22 | **/packages/* 23 | # except build/, which is used as an MSBuild target. 24 | !**/packages/build/ 25 | # Uncomment if necessary however generally it will be regenerated when needed 26 | #!**/packages/repositories.config 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | *_i.c 33 | *_p.c 34 | *.ilk 35 | *.meta 36 | *.obj 37 | *.pch 38 | *.pdb 39 | *.pgc 40 | *.pgd 41 | *.rsp 42 | *.sbr 43 | *.tlb 44 | *.tli 45 | *.tlh 46 | *.tmp 47 | *.tmp_proj 48 | *.log 49 | *.vspscc 50 | *.vssscc 51 | .builds 52 | *.pidb 53 | *.log 54 | *.scc 55 | 56 | # OS generated files # 57 | .DS_Store* 58 | ehthumbs.db 59 | Icon? 60 | Thumbs.db 61 | 62 | # Visual C++ cache files 63 | ipch/ 64 | *.aps 65 | *.ncb 66 | *.opensdf 67 | *.sdf 68 | *.cachefile 69 | 70 | # Visual Studio profiler 71 | *.psess 72 | *.vsp 73 | *.vspx 74 | 75 | # Guidance Automation Toolkit 76 | *.gpState 77 | 78 | # ReSharper is a .NET coding add-in 79 | _ReSharper*/ 80 | *.[Rr]e[Ss]harper 81 | 82 | # TeamCity is a build add-in 83 | _TeamCity* 84 | 85 | # DotCover is a Code Coverage Tool 86 | *.dotCover 87 | 88 | # NCrunch 89 | *.ncrunch* 90 | .*crunch*.local.xml 91 | 92 | # Installshield output folder 93 | [Ee]xpress/ 94 | 95 | # DocProject is a documentation generator add-in 96 | DocProject/buildhelp/ 97 | DocProject/Help/*.HxT 98 | DocProject/Help/*.HxC 99 | DocProject/Help/*.hhc 100 | DocProject/Help/*.hhk 101 | DocProject/Help/*.hhp 102 | DocProject/Help/Html2 103 | DocProject/Help/html 104 | 105 | # Click-Once directory 106 | publish/ 107 | 108 | # Publish Web Output 109 | *.Publish.xml 110 | 111 | # Windows Azure Build Output 112 | csx 113 | *.build.csdef 114 | 115 | # Windows Store app package directory 116 | AppPackages/ 117 | 118 | # Others 119 | sql/ 120 | *.Cache 121 | ClientBin/ 122 | [Ss]tyle[Cc]op.* 123 | ~$* 124 | *~ 125 | *.dbmdl 126 | *.[Pp]ublish.xml 127 | *.pfx 128 | *.publishsettings 129 | modulesbin/ 130 | tempbin/ 131 | 132 | # EPiServer Site file (VPP) 133 | AppData/ 134 | 135 | # RIA/Silverlight projects 136 | Generated_Code/ 137 | 138 | # Backup & report files from converting an old project file to a newer 139 | # Visual Studio version. Backup files are not needed, because we have git ;-) 140 | _UpgradeReport_Files/ 141 | Backup*/ 142 | UpgradeLog*.XML 143 | UpgradeLog*.htm 144 | 145 | # vim 146 | *.txt~ 147 | *.swp 148 | *.swo 149 | 150 | # svn 151 | .svn 152 | 153 | # SQL Server files 154 | **/App_Data/*.mdf 155 | **/App_Data/*.ldf 156 | **/App_Data/*.sdf 157 | 158 | 159 | #LightSwitch generated files 160 | GeneratedArtifacts/ 161 | _Pvt_Extensions/ 162 | ModelManifest.xml 163 | 164 | # ========================= 165 | # Windows detritus 166 | # ========================= 167 | 168 | # Windows image file caches 169 | Thumbs.db 170 | ehthumbs.db 171 | 172 | # Folder config file 173 | Desktop.ini 174 | 175 | # Recycle Bin used on file shares 176 | $RECYCLE.BIN/ 177 | 178 | # Mac desktop service store files 179 | .DS_Store 180 | 181 | # SASS Compiler cache 182 | .sass-cache 183 | 184 | # Visual Studio 2014 CTP 185 | **/*.sln.ide 186 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/model.mustache: -------------------------------------------------------------------------------- 1 | {{>partial_header}} 2 | using System; 3 | using System.Linq; 4 | using System.IO; 5 | using System.Text; 6 | {{^netStandard}} 7 | using System.Text.RegularExpressions; 8 | {{/netStandard}} 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using System.Collections.ObjectModel; 12 | using System.Runtime.Serialization; 13 | using Newtonsoft.Json; 14 | using Newtonsoft.Json.Converters; 15 | {{^netStandard}} 16 | {{#generatePropertyChanged}} 17 | using PropertyChanged; 18 | using System.ComponentModel; 19 | {{/generatePropertyChanged}} 20 | using System.ComponentModel.DataAnnotations; 21 | {{/netStandard}} 22 | 23 | {{#models}} 24 | {{#model}} 25 | namespace {{packageName}}.{{modelPackage}} 26 | { 27 | {{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{>modelGeneric}}{{/isEnum}} 28 | {{/model}} 29 | {{/models}} 30 | } 31 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/modelEnum.mustache: -------------------------------------------------------------------------------- 1 | /// 2 | /// {{^description}}Defines {{{name}}}{{/description}}{{#description}}{{{description}}}{{/description}} 3 | /// {{#description}} 4 | /// {{{description}}}{{/description}} 5 | [JsonConverter(typeof(StringEnumConverter))] 6 | {{>visibility}} enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} 7 | { 8 | {{#allowableValues}}{{#enumVars}} 9 | /// 10 | /// Enum {{name}} for {{{value}}} 11 | /// 12 | [EnumMember(Value = {{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}})] 13 | {{name}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^-last}}, 14 | {{/-last}}{{/enumVars}}{{/allowableValues}} 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/modelGeneric.mustache: -------------------------------------------------------------------------------- 1 | /// 2 | /// {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} 3 | /// 4 | [DataContract] 5 | {{#generatePropertyChanged}} 6 | [ImplementPropertyChanged] 7 | {{/generatePropertyChanged}} 8 | {{>visibility}} partial class {{classname}} : {{#parent}}{{{parent}}}, {{/parent}} IEquatable<{{classname}}>{{^netStandard}}{{#validatable}}, IValidatableObject{{/validatable}}{{/netStandard}} 9 | { 10 | {{#vars}} 11 | {{#isEnum}} 12 | {{>modelInnerEnum}} 13 | {{/isEnum}} 14 | {{#items.isEnum}} 15 | {{#items}} 16 | {{>modelInnerEnum}} 17 | {{/items}} 18 | {{/items.isEnum}} 19 | {{/vars}} 20 | {{#vars}} 21 | {{#isEnum}} 22 | /// 23 | /// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{{description}}}{{/description}} 24 | /// {{#description}} 25 | /// {{{description}}}{{/description}} 26 | [DataMember(Name="{{baseName}}", EmitDefaultValue={{emitDefaultValue}})] 27 | public {{{datatypeWithEnum}}}{{#isEnum}}{{^isContainer}}?{{/isContainer}}{{/isEnum}} {{name}} { get; set; } 28 | {{/isEnum}} 29 | {{/vars}} 30 | {{#hasRequired}} 31 | {{^hasOnlyReadOnly}} 32 | /// 33 | /// Initializes a new instance of the class. 34 | /// 35 | [JsonConstructorAttribute] 36 | protected {{classname}}() { } 37 | {{/hasOnlyReadOnly}} 38 | {{/hasRequired}} 39 | /// 40 | /// Initializes a new instance of the class. 41 | /// 42 | {{#vars}} 43 | {{^isReadOnly}} 44 | /// {{#description}}{{description}}{{/description}}{{^description}}{{name}}{{/description}}{{#required}} (required){{/required}}{{#defaultValue}} (default to {{defaultValue}}){{/defaultValue}}. 45 | {{/isReadOnly}} 46 | {{/vars}} 47 | {{#hasOnlyReadOnly}} 48 | [JsonConstructorAttribute] 49 | {{/hasOnlyReadOnly}} 50 | public {{classname}}({{#readWriteVars}}{{{datatypeWithEnum}}}{{#isEnum}}{{^isContainer}}?{{/isContainer}}{{/isEnum}} {{name}} = {{#defaultValue}}{{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}default({{{datatypeWithEnum}}}{{#isEnum}}{{^isContainer}}?{{/isContainer}}{{/isEnum}}){{/defaultValue}}{{^-last}}, {{/-last}}{{/readWriteVars}}) 51 | { 52 | {{#vars}} 53 | {{^isReadOnly}} 54 | {{#required}} 55 | // to ensure "{{name}}" is required (not null) 56 | if ({{name}} == null) 57 | { 58 | throw new InvalidDataException("{{name}} is a required property for {{classname}} and cannot be null"); 59 | } 60 | else 61 | { 62 | this.{{name}} = {{name}}; 63 | } 64 | {{/required}} 65 | {{/isReadOnly}} 66 | {{/vars}} 67 | {{#vars}} 68 | {{^isReadOnly}} 69 | {{^required}} 70 | {{#defaultValue}}// use default value if no "{{name}}" provided 71 | if ({{name}} == null) 72 | { 73 | this.{{name}} = {{{defaultValue}}}; 74 | } 75 | else 76 | { 77 | this.{{name}} = {{name}}; 78 | } 79 | {{/defaultValue}} 80 | {{^defaultValue}} 81 | this.{{name}} = {{name}}; 82 | {{/defaultValue}} 83 | {{/required}} 84 | {{/isReadOnly}} 85 | {{/vars}} 86 | } 87 | 88 | {{#vars}} 89 | {{^isEnum}} 90 | /// 91 | /// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}} 92 | /// {{#description}} 93 | /// {{description}}{{/description}} 94 | [DataMember(Name="{{baseName}}", EmitDefaultValue={{emitDefaultValue}})] 95 | public {{{datatype}}} {{name}} { get; {{#isReadOnly}}private {{/isReadOnly}}set; } 96 | {{/isEnum}} 97 | {{/vars}} 98 | /// 99 | /// Returns the string presentation of the object 100 | /// 101 | /// String presentation of the object 102 | public override string ToString() 103 | { 104 | var sb = new StringBuilder(); 105 | sb.Append("class {{classname}} {\n"); 106 | {{#vars}} 107 | sb.Append(" {{name}}: ").Append({{name}}).Append("\n"); 108 | {{/vars}} 109 | sb.Append("}\n"); 110 | return sb.ToString(); 111 | } 112 | 113 | /// 114 | /// Returns the JSON string presentation of the object 115 | /// 116 | /// JSON string presentation of the object 117 | public {{#parent}} new {{/parent}}string ToJson() 118 | { 119 | return JsonConvert.SerializeObject(this, Formatting.Indented); 120 | } 121 | 122 | /// 123 | /// Returns true if objects are equal 124 | /// 125 | /// Object to be compared 126 | /// Boolean 127 | public override bool Equals(object obj) 128 | { 129 | // credit: http://stackoverflow.com/a/10454552/677735 130 | return this.Equals(obj as {{classname}}); 131 | } 132 | 133 | /// 134 | /// Returns true if {{classname}} instances are equal 135 | /// 136 | /// Instance of {{classname}} to be compared 137 | /// Boolean 138 | public bool Equals({{classname}} other) 139 | { 140 | // credit: http://stackoverflow.com/a/10454552/677735 141 | if (other == null) 142 | return false; 143 | 144 | return {{#vars}}{{#isNotContainer}} 145 | ( 146 | this.{{name}} == other.{{name}} || 147 | this.{{name}} != null && 148 | this.{{name}}.Equals(other.{{name}}) 149 | ){{#hasMore}} && {{/hasMore}}{{/isNotContainer}}{{^isNotContainer}} 150 | ( 151 | this.{{name}} == other.{{name}} || 152 | this.{{name}} != null && 153 | this.{{name}}.SequenceEqual(other.{{name}}) 154 | ){{#hasMore}} && {{/hasMore}}{{/isNotContainer}}{{/vars}}{{^vars}}false{{/vars}}; 155 | } 156 | 157 | /// 158 | /// Gets the hash code 159 | /// 160 | /// Hash code 161 | public override int GetHashCode() 162 | { 163 | // credit: http://stackoverflow.com/a/263416/677735 164 | unchecked // Overflow is fine, just wrap 165 | { 166 | int hash = 41; 167 | // Suitable nullity checks etc, of course :) 168 | {{#vars}} 169 | if (this.{{name}} != null) 170 | hash = hash * 59 + this.{{name}}.GetHashCode(); 171 | {{/vars}} 172 | return hash; 173 | } 174 | } 175 | {{^netStandard}} 176 | 177 | {{#generatePropertyChanged}} 178 | /// 179 | /// Property changed event handler 180 | /// 181 | public event PropertyChangedEventHandler PropertyChanged; 182 | 183 | /// 184 | /// Trigger when a property changed 185 | /// 186 | /// Property Name 187 | public virtual void OnPropertyChanged(string propertyName) 188 | { 189 | // NOTE: property changed is handled via "code weaving" using Fody. 190 | // Properties with setters are modified at compile time to notify of changes. 191 | var propertyChanged = PropertyChanged; 192 | if (propertyChanged != null) 193 | { 194 | propertyChanged(this, new PropertyChangedEventArgs(propertyName)); 195 | } 196 | } 197 | 198 | {{/generatePropertyChanged}} 199 | {{#validatable}} 200 | /// 201 | /// To validate all properties of the instance 202 | /// 203 | /// Validation context 204 | /// Validation Result 205 | IEnumerable IValidatableObject.Validate(ValidationContext validationContext) 206 | { 207 | {{#vars}} 208 | {{#hasValidation}} 209 | {{#maxLength}} 210 | // {{{name}}} ({{{datatype}}}) maxLength 211 | if(this.{{{name}}} != null && this.{{{name}}}.Length > {{maxLength}}) 212 | { 213 | yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for {{{name}}}, length must be less than {{maxLength}}.", new [] { "{{{name}}}" }); 214 | } 215 | 216 | {{/maxLength}} 217 | {{#minLength}} 218 | // {{{name}}} ({{{datatype}}}) minLength 219 | if(this.{{{name}}} != null && this.{{{name}}}.Length < {{minLength}}) 220 | { 221 | yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for {{{name}}}, length must be greater than {{minLength}}.", new [] { "{{{name}}}" }); 222 | } 223 | 224 | {{/minLength}} 225 | {{#maximum}} 226 | // {{{name}}} ({{{datatype}}}) maximum 227 | if(this.{{{name}}} > ({{{datatype}}}){{maximum}}) 228 | { 229 | yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for {{{name}}}, must be a value less than or equal to {{maximum}}.", new [] { "{{{name}}}" }); 230 | } 231 | 232 | {{/maximum}} 233 | {{#minimum}} 234 | // {{{name}}} ({{{datatype}}}) minimum 235 | if(this.{{{name}}} < ({{{datatype}}}){{minimum}}) 236 | { 237 | yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for {{{name}}}, must be a value greater than or equal to {{minimum}}.", new [] { "{{{name}}}" }); 238 | } 239 | 240 | {{/minimum}} 241 | {{#pattern}} 242 | // {{{name}}} ({{{datatype}}}) pattern 243 | Regex regex{{{name}}} = new Regex(@"{{{vendorExtensions.x-regex}}}"{{#vendorExtensions.x-modifiers}}{{#-first}}, {{/-first}}RegexOptions.{{{.}}}{{^-last}} | {{/-last}}{{/vendorExtensions.x-modifiers}}); 244 | if (false == regex{{{name}}}.Match(this.{{{name}}}).Success) 245 | { 246 | yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for {{{name}}}, must match a pattern of {{{pattern}}}.", new [] { "{{{name}}}" }); 247 | } 248 | 249 | {{/pattern}} 250 | {{/hasValidation}} 251 | {{/vars}} 252 | yield break; 253 | } 254 | {{/validatable}} 255 | {{/netStandard}} 256 | } 257 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/modelInnerEnum.mustache: -------------------------------------------------------------------------------- 1 | {{^isContainer}} 2 | /// 3 | /// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{{description}}}{{/description}} 4 | /// {{#description}} 5 | /// {{{description}}}{{/description}} 6 | [JsonConverter(typeof(StringEnumConverter))] 7 | {{>visibility}} enum {{#datatypeWithEnum}}{{&.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} 8 | { 9 | {{#allowableValues}}{{#enumVars}} 10 | /// 11 | /// Enum {{name}} for {{{value}}} 12 | /// 13 | [EnumMember(Value = {{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isFloat}}"{{/isFloat}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isFloat}}"{{/isFloat}})] 14 | {{name}}{{#isLong}} = {{{value}}}{{/isLong}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^-last}}, 15 | {{/-last}}{{/enumVars}}{{/allowableValues}} 16 | } 17 | {{/isContainer}} 18 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/model_doc.mustache: -------------------------------------------------------------------------------- 1 | {{#models}} 2 | {{#model}} 3 | # {{{packageName}}}.{{modelPackage}}.{{{classname}}} 4 | ## Properties 5 | 6 | Name | Type | Description | Notes 7 | ------------ | ------------- | ------------- | ------------- 8 | {{#vars}}**{{name}}** | {{#isPrimitiveType}}**{{datatype}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{datatype}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#readOnly}}[readonly] {{/readOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}} 9 | {{/vars}} 10 | 11 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 12 | 13 | {{/model}} 14 | {{/models}} 15 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/model_test.mustache: -------------------------------------------------------------------------------- 1 | {{>partial_header}} 2 | 3 | using NUnit.Framework; 4 | 5 | using System; 6 | using System.Linq; 7 | using System.IO; 8 | using System.Collections.Generic; 9 | using {{packageName}}.{{apiPackage}}; 10 | using {{packageName}}.{{modelPackage}}; 11 | using {{packageName}}.Client; 12 | using System.Reflection; 13 | 14 | {{#models}} 15 | {{#model}} 16 | namespace {{packageName}}.Test 17 | { 18 | /// 19 | /// Class for testing {{classname}} 20 | /// 21 | /// 22 | /// This file is automatically generated by Swagger Codegen. 23 | /// Please update the test case below to test the model. 24 | /// 25 | [TestFixture] 26 | public class {{classname}}Tests 27 | { 28 | // TODO uncomment below to declare an instance variable for {{classname}} 29 | //private {{classname}} instance; 30 | 31 | /// 32 | /// Setup before each test 33 | /// 34 | [SetUp] 35 | public void Init() 36 | { 37 | // TODO uncomment below to create an instance of {{classname}} 38 | //instance = new {{classname}}(); 39 | } 40 | 41 | /// 42 | /// Clean up after each test 43 | /// 44 | [TearDown] 45 | public void Cleanup() 46 | { 47 | 48 | } 49 | 50 | /// 51 | /// Test an instance of {{classname}} 52 | /// 53 | [Test] 54 | public void {{classname}}InstanceTest() 55 | { 56 | // TODO uncomment below to test "IsInstanceOfType" {{classname}} 57 | //Assert.IsInstanceOfType<{{classname}}> (instance, "variable 'instance' is a {{classname}}"); 58 | } 59 | 60 | {{#vars}} 61 | /// 62 | /// Test the property '{{name}}' 63 | /// 64 | [Test] 65 | public void {{name}}Test() 66 | { 67 | // TODO unit test for the property '{{name}}' 68 | } 69 | {{/vars}} 70 | 71 | } 72 | 73 | } 74 | {{/model}} 75 | {{/models}} 76 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/mono_nunit_test.mustache: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Generated by: https://github.com/swagger-api/swagger-codegen.git 4 | # 5 | 6 | wget -nc https://nuget.org/nuget.exe 7 | mozroots --import --sync 8 | 9 | echo "[INFO] remove bin/Debug/SwaggerClientTest.dll" 10 | rm src/{{{packageName}}}.Test/bin/Debug/{{{packageName}}}.Test.dll 2> /dev/null 11 | 12 | echo "[INFO] install NUnit runners via NuGet" 13 | wget -nc https://nuget.org/nuget.exe 14 | mozroots --import --sync 15 | mono nuget.exe install src/{{{packageName}}}.Test/packages.config -o packages 16 | 17 | echo "[INFO] Install NUnit runners via NuGet" 18 | mono nuget.exe install NUnit.Runners -Version 2.6.4 -OutputDirectory packages 19 | 20 | echo "[INFO] Build the solution and run the unit test" 21 | xbuild {{{packageName}}}.sln && \ 22 | mono ./packages/NUnit.Runners.2.6.4/tools/nunit-console.exe src/{{{packageName}}}.Test/bin/Debug/{{{packageName}}}.Test.dll 23 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/partial_header.mustache: -------------------------------------------------------------------------------- 1 | /* 2 | {{#appName}} 3 | * {{{appName}}} 4 | * 5 | {{/appName}} 6 | {{#appDescription}} 7 | * {{{appDescription}}} 8 | * 9 | {{/appDescription}} 10 | * {{#version}}OpenAPI spec version: {{{version}}}{{/version}} 11 | * {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} 12 | * Generated by: https://github.com/swagger-api/swagger-codegen.git 13 | */ 14 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/shared_project.mustache: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | {{packageGuid}} 17 | 14.0 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/shared_projitems.mustache: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 17 | true 18 | {{packageGuid}} 19 | 20 | 21 | {{packageName}} 22 | 23 | 24 | 25 | {{#apiInfo}} 26 | {{#apis}} 27 | 28 | {{/apis}} 29 | {{/apiInfo}} 30 | {{#models}} 31 | {{#model}} 32 | 33 | {{/model}} 34 | {{/models}} 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/main/resources/csharprefit/visibility.mustache: -------------------------------------------------------------------------------- 1 | {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} --------------------------------------------------------------------------------