From faf0798a0d645500e060b50d9c9d32b983a36c79 Mon Sep 17 00:00:00 2001 From: ralfeus Date: Thu, 28 Mar 2024 16:06:53 +0100 Subject: [PATCH 1/5] Update DefaultCodegenConfig.snakeCase() Original version doesn't snake_case input but just lowers first letter --- .../v3/generators/DefaultCodegenConfig.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java index b18e9a3e0e..cfae464f06 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java +++ b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java @@ -1183,9 +1183,27 @@ private static String getTypeOfSchema(Schema schema) { */ @SuppressWarnings("static-method") public String snakeCase(String name) { - return (name.length() > 0) ? (Character.toLowerCase(name.charAt(0)) + name.substring(1)) : ""; + if (name.isEmpty()) { + return ""; + } + StringBuilder snakeCase = new StringBuilder(); + boolean previousCharWasUpperCase = false; + + for (int i = 0; i < camelCase.length(); i++) { + char currentChar = camelCase.charAt(i); + + if (Character.isUpperCase(currentChar)) { + if (i > 0 && !previousCharWasUpperCase) { + snakeCase.append('_'); + } + snakeCase.append(Character.toLowerCase(currentChar)); + previousCharWasUpperCase = true; + } else { + snakeCase.append(currentChar); + previousCharWasUpperCase = false; + } + } } - /** * Capitalize the string * From 18d296c6ba5b8a52b641e67acd52e061f96bf50a Mon Sep 17 00:00:00 2001 From: ralfeus Date: Thu, 28 Mar 2024 16:39:52 +0100 Subject: [PATCH 2/5] Update DefaultCodegenConfig.java --- .../codegen/v3/generators/DefaultCodegenConfig.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java index cfae464f06..aea70e0db5 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java +++ b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java @@ -1176,13 +1176,13 @@ private static String getTypeOfSchema(Schema schema) { } /** - * Return the snake-case of the string + * Return the snake_case of the string * - * @param name string to be snake-cased - * @return snake-cased string + * @param name string to be snake_cased + * @return snake_cased string */ @SuppressWarnings("static-method") - public String snakeCase(String name) { + public String snakeCase(String camelCase) { if (name.isEmpty()) { return ""; } From d14a2eb50d25b883318a42ac871aff46ee5c1975 Mon Sep 17 00:00:00 2001 From: Mychajlo Chodorev Date: Sun, 31 Mar 2024 15:24:59 +0200 Subject: [PATCH 3/5] Dart Frog server stub generator --- .../v3/generators/DefaultCodegenConfig.java | 5 +- .../v3/generators/dart/DartFrogGenerator.java | 497 ++++++++++++++++++ .../io.swagger.codegen.v3.CodegenConfig | 1 + .../handlebars/dart-frog/main.dart.mustache | 11 + .../handlebars/dart-frog/model.dart.mustache | 26 + .../handlebars/dart-frog/openapi.mustache | 1 + .../dart-frog/pubspec.yaml.mustache | 13 + .../handlebars/dart-frog/route.dart.mustache | 69 +++ 8 files changed, 621 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/swagger/codegen/v3/generators/dart/DartFrogGenerator.java create mode 100644 src/main/resources/handlebars/dart-frog/main.dart.mustache create mode 100644 src/main/resources/handlebars/dart-frog/model.dart.mustache create mode 100644 src/main/resources/handlebars/dart-frog/openapi.mustache create mode 100644 src/main/resources/handlebars/dart-frog/pubspec.yaml.mustache create mode 100644 src/main/resources/handlebars/dart-frog/route.dart.mustache diff --git a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java index aea70e0db5..3973a49e05 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java +++ b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java @@ -1181,9 +1181,8 @@ private static String getTypeOfSchema(Schema schema) { * @param name string to be snake_cased * @return snake_cased string */ - @SuppressWarnings("static-method") public String snakeCase(String camelCase) { - if (name.isEmpty()) { + if (camelCase.isEmpty()) { return ""; } StringBuilder snakeCase = new StringBuilder(); @@ -1203,7 +1202,9 @@ public String snakeCase(String camelCase) { previousCharWasUpperCase = false; } } + return snakeCase.toString(); } + /** * Capitalize the string * diff --git a/src/main/java/io/swagger/codegen/v3/generators/dart/DartFrogGenerator.java b/src/main/java/io/swagger/codegen/v3/generators/dart/DartFrogGenerator.java new file mode 100644 index 0000000000..7e5862cf04 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/dart/DartFrogGenerator.java @@ -0,0 +1,497 @@ +package io.swagger.codegen.v3.generators.dart; + +import io.swagger.codegen.v3.*; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.responses.ApiResponse; + +import java.util.*; +import com.github.jknack.handlebars.Handlebars; +import com.github.jknack.handlebars.helper.ConditionalHelpers; +import com.github.jknack.handlebars.helper.StringHelpers; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; + +public class DartFrogGenerator extends DefaultCodegenConfig { + // source folder where to write the files + protected String sourceFolder = "lib"; + protected String routesFolder = "routes"; + protected String modelsFolder = "models"; + protected String publicFolder = "public"; + protected String testsFolder = "tests"; + protected String apiVersion = "1.0.0"; + + /** + * Configures the type of generator. + * + * @return the CodegenType for this generator + * @see io.swagger.codegen.CodegenType + */ + public CodegenType getTag() { + return CodegenType.SERVER; + } + + /** + * Configures a friendly name for the generator. This will be used by the + * generator + * to select the library with the -l flag. + * + * @return the friendly name for the generator + */ + public String getName() { + return "dart-frog"; + } + + /** + * Returns human-friendly help for the generator. Provide the consumer with help + * tips, parameters here + * + * @return A string value for the help message + */ + public String getHelp() { + return "Generates a dart-frog server stub."; + } + + public DartFrogGenerator() { + super(); + + // set the output folder here + outputFolder = "generated-code/dart-frog"; + + /** + * Models. You can write model files using the modelTemplateFiles map. + * if you want to create one template for file, you can do so here. + * for multiple files for model, just put another entry in the + * `modelTemplateFiles` with + * a different extension + */ + modelTemplateFiles.put( + "model.dart.mustache", // the template to use + ".dart"); // the extension for each file to write + + /** + * Api classes. You can write classes for each Api file with the + * apiTemplateFiles map. + * as with models, add multiple entries with different extensions for multiple + * files per + * class + */ + apiTemplateFiles.put( + "route.dart.mustache", // the template to use + ".dart"); // the extension for each file to write + + /** + * Template Location. This is the location which templates will be read from. + * The generator + * will use the resource stream to attempt to read the templates. + */ + templateDir = "dart-frog"; + + /** + * Api Package. Optional, if needed, this can be used in templates + */ + apiPackage = "io.swagger.dart_frog.api"; + + /** + * Reserved words. Override this with reserved words specific to your language + */ + reservedWords = new HashSet( + Arrays.asList( + "abstract", "as", "assert", "async", "async*", "await", + "break", "case", "catch", "class", "const", "continue", + "default", "deferred", "do", "dynamic", "else", "enum", + "export", "external", "extends", "factory", "false", "final", + "finally", "for", "get", "if", "implements", "import", "in", + "is", "library", "new", "null", "operator", "part", "rethrow", + "return", "set", "static", "super", "switch", "sync*", "this", + "throw", "true", "try", "typedef", "var", "void", "while", + "with", "yield", "yield*")); + + /** + * Additional Properties. These values can be passed to the templates and + * are available in models, apis, and supporting files + */ + additionalProperties.put("apiVersion", apiVersion); + /// `httpVerbs` are needed for iterating through them in routes template + additionalProperties.put("httpVerbs", new String[] { + "GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS" }); + // additionalProperties.put("appDescription", + // "dart_frog realization of the server stub of the application \"" + + // openAPI.getInfo().getTitle() + + // "\" generated by Swagger Codegen"); + + /** + * Supporting Files. You can write single files for the generator with the + * entire object tree available. If the input file has a suffix of `.mustache + * it will be processed by the template engine. Otherwise, it will be copied + */ + supportingFiles.addAll(Arrays.asList( + new SupportingFile("pubspec.yaml.mustache", "", "pubspec.yaml"), + new SupportingFile("main.dart.mustache", "main.dart"))); + + /** + * Language Specific Primitives. These types will not trigger imports by + * the client generator + */ + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "bool", + "int", + "num", + "double", + "DateTime", + "List", + "Object", + "String")); + + typeMapping = new HashMap() {{ + put("Array", "List"); + put("array", "List"); + put("List", "List"); + put("boolean", "bool"); + put("string", "String"); + put("char", "String"); + put("int", "int"); + put("long", "int"); + put("short", "int"); + put("number", "num"); + put("float", "double"); + put("double", "double"); + put("BigDecimal", "double"); + put("object", "Object"); + put("integer", "int"); + put("Date", "DateTime"); + put("date", "DateTime"); + put("File", "MultipartFile"); + put("UUID", "String"); + put("GUID", "String"); + }}; + } + + /** + * Escapes a reserved word as defined in the `reservedWords` array. Handle + * escaping + * those terms here. This logic is only called if a variable matches the + * reserved words + * + * @return the escaped term + */ + @Override + public String escapeReservedWord(String name) { + return "_" + name; // add an underscore to the name + } + + /** + * Location to write model files. You can use the modelPackage() as defined when + * the class is + * instantiated + */ + public String modelFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + modelsFolder; + } + + /** + * Location to write API files. + * For Dart Frog it's %PROJECT_ROOT%/routes + */ + @Override + public String apiFileFolder() { + return outputFolder + "/" + routesFolder; + } + + /** + * Returns file name of the API tag. For Dart Frog tag is used to identify + * the path. So each path is represented with it's own file. + * The folder structure of all files matches structure of paths. + * So the list of paths: + * + * /a + * /a/b + * /a/b/c + * /b + * /b/d + * + * will end up with file structure: + * /a + * /index.dart + * /b + * /index.dart + * /c.dart + * /b + * /index.dart + * /d.dart + */ + @Override + public String toApiFilename(String name) { + if (name.substring(name.length() - 1).equals("/")) { + name = name + "index"; + } + return name + .substring(1) + .replace('{', '[') + .replace('}', ']'); + } + + /** + * Dart file naming convention is snake case + * https://dart.dev/effective-dart/style#do-name-packages-and-file-system-entities-using-lowercase-with-underscores + * @param name - Class name, for which need to get file name + */ + @Override + public String toModelFilename(String name) { + return snakeCase(name); + } + + /** + * Original method doesn't really make a snake_case + */ + @Override + public String snakeCase(String camelCase) { + StringBuilder snakeCase = new StringBuilder(); + boolean previousCharWasUpperCase = false; + + for (int i = 0; i < camelCase.length(); i++) { + char currentChar = camelCase.charAt(i); + + if (Character.isUpperCase(currentChar)) { + if (i > 0 && !previousCharWasUpperCase) { + snakeCase.append('_'); + } + snakeCase.append(Character.toLowerCase(currentChar)); + previousCharWasUpperCase = true; + } else { + snakeCase.append(currentChar); + previousCharWasUpperCase = false; + } + } + + return snakeCase.toString(); +} + + /** + * @param name - Class name to be imported + */ + @Override + public String toModelImport(String name) { + return "package:" + openAPI.getInfo().getTitle() + "/" + modelsFolder + + "/" + toModelFilename(name) + ".dart"; + } + + @Override + protected String getTemplateDir() { + return templateDir; + } + + @Override + public String getDefaultTemplateDir() { + return templateDir; + } + + /** + * Customize a standard operation adding process by setting the path as a + * tag with trailing slash if the path isn't the finite for whole set of + * paths. + * It is needed to group all operations by paths because for Dart Frog each + * path is implemented in its own route file + */ + @Override + public void addOperationToGroup(String tag, String resourcePath, + Operation operation, CodegenOperation co, + Map> operations) { + super.addOperationToGroup( + addTrailingSlash(resourcePath), resourcePath, operation, co, operations); + } + + private String addTrailingSlash(String resourcePath) { + Set paths = openAPI.getPaths().keySet(); + String slash = ""; + for (String path : paths) { + if (resourcePath.equals(path)) { + continue; + } + if (path.startsWith(resourcePath)) { + slash = "/"; + break; + } + } + return resourcePath + slash; + } + + /** + * Registers additional helpers for Handlebars template engine + * Needed here in order to enable `eq` and `lower` helpers, which is part + * of Java's realization of Handlebars but isn't registered by default. + */ + @Override + public void addHandlebarHelpers(Handlebars handlebars) { + super.addHandlebarHelpers(handlebars); + handlebars.registerHelpers(ConditionalHelpers.class); + handlebars.registerHelpers(StringHelpers.class); + } + + /** + * Parameters handler of DefaultCodegen gets parameters from single operations + * and ignores path level parameters. + * Therefore, this preprocessor creates parameters list for all operations of + * path, that has path level parameters + */ + @Override + public void preprocessOpenAPI(OpenAPI openAPI) { + super.preprocessOpenAPI(openAPI); + Paths paths = openAPI.getPaths(); + for (String pathStr : paths.keySet()) { + PathItem path = paths.get(pathStr); + if (path.getParameters() != null && !path.getParameters().isEmpty()) { + initParametersList(path.getGet()); + initParametersList(path.getPost()); + initParametersList(path.getPut()); + initParametersList(path.getPatch()); + initParametersList(path.getOptions()); + initParametersList(path.getDelete()); + initParametersList(path.getHead()); + } + } + saveSpec(inputURL); + } + + private void initParametersList(Operation op) { + if (op != null && op.getParameters() == null) { + op.setParameters(new ArrayList()); + } + } + + /** + * Gets input OpenAPI specification either from local file or URL and adds + * a property so the `openapi.ext` will be saved in public folder + * @param pathOrUrl + */ + private void saveSpec(String pathOrUrl) { + try { + if (pathOrUrl.startsWith("http://") || pathOrUrl.startsWith("https://")) { + // Read from URL + additionalProperties.put("openApiSpec", readFromUrl(pathOrUrl)); + } else { + // Read from local file + additionalProperties.put("openApiSpec", readFromFile(pathOrUrl)); + } + String suffix = pathOrUrl.substring(pathOrUrl.lastIndexOf(".")); + supportingFiles.add(new SupportingFile("openapi.mustache", + publicFolder, "openapi" + suffix)); + } catch (IOException e) { + LOGGER.error("Couldn't get OpenAPI specification", e); + } + } + + private String readFromUrl(String urlString) throws IOException { + StringBuilder content = new StringBuilder(); + URL url = new URL(urlString); + + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(url.openStream()))) { + String line; + while ((line = reader.readLine()) != null) { + content.append(line).append("\n"); + } + } + + return content.toString(); + } + + private String readFromFile(String filePath) throws IOException { + return new String(Files.readAllBytes(java.nio.file.Paths.get(filePath)), + StandardCharsets.UTF_8); + } + + /** + * Replace `dataType` with Dart type + */ + @Override + public CodegenModel fromModel(String name, Schema schema, Map allDefinitions) { + CodegenModel model = super.fromModel(name, schema, allDefinitions); + model.setDataType(typeMapping().get(model.getDataType())); + return model; + } + + /** + * Imports of DefaultGenerator use baseType instead of dataType + * Therefore, need to set baseType of response to dataType + * @param responseCode + * @param response + * @return CodegenResponse with baseType updated + */ + @Override + public CodegenResponse fromResponse(String responseCode, ApiResponse response) { + CodegenResponse resp = super.fromResponse(responseCode, response); + if (resp.containerType == null) { + resp.baseType = resp.dataType; + } + return resp; + } + + /** + * Complex properties whose type is defined right in property definitnion + * are marked as `object` but of complex type so it's not recognized as + * built-in `Object` of Dart. + * So, such properties are defined as non-complex and, if their type belongs + * to Dart built-in types marked as of primitive type + */ + @Override + public CodegenProperty fromProperty(String name, Schema propertySchema) { + CodegenProperty property = super.fromProperty(name, propertySchema); + boolean isPrimitive = languageSpecificPrimitives.contains(property.getDatatype()); + property.getVendorExtensions().put( + CodegenConstants.IS_PRIMITIVE_TYPE_EXT_NAME, isPrimitive); + if (isPrimitive) { + property.complexType = null; + } + return property; + } + + @Override + public String getSchemaType(Schema schema) { + String type = super.getSchemaType(schema); + String[] typeComponents = type.split("/properties/"); + if (typeComponents.length < 2) { + return type; + } + Schema refSchema = openAPI.getComponents().getSchemas() + .get(typeComponents[0]); + if (refSchema == null) { + return type; + } + Schema prop = (Schema)refSchema.getProperties().get(typeComponents[1]); + return prop.getType(); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input; + } + + @Override + public String escapeQuotationMark(String input) { + return input.replace("\'", "\\\'"); + } + + /** + * Default needToImport uses types from OpenAPI schema + * Language-specific ones should be used instead + */ + @Override + protected boolean needToImport(String type) { + return super.needToImport(typeMapping().keySet().contains(type) + ? typeMapping().get(type) + : type); + } + +} \ No newline at end of file diff --git a/src/main/resources/META-INF/services/io.swagger.codegen.v3.CodegenConfig b/src/main/resources/META-INF/services/io.swagger.codegen.v3.CodegenConfig index 2adb275cf1..0569685697 100644 --- a/src/main/resources/META-INF/services/io.swagger.codegen.v3.CodegenConfig +++ b/src/main/resources/META-INF/services/io.swagger.codegen.v3.CodegenConfig @@ -1,4 +1,5 @@ io.swagger.codegen.v3.generators.dart.DartClientCodegen +io.swagger.codegen.v3.generators.dart.DartFrogGenerator io.swagger.codegen.v3.generators.dotnet.AspNetCoreServerCodegen io.swagger.codegen.v3.generators.dotnet.CSharpClientCodegen io.swagger.codegen.v3.generators.dotnet.CsharpDotNet2ClientCodegen diff --git a/src/main/resources/handlebars/dart-frog/main.dart.mustache b/src/main/resources/handlebars/dart-frog/main.dart.mustache new file mode 100644 index 0000000000..226b181a15 --- /dev/null +++ b/src/main/resources/handlebars/dart-frog/main.dart.mustache @@ -0,0 +1,11 @@ +import 'dart:io'; + +import 'package:dart_frog/dart_frog.dart'; + +/// Runs initialization of the server +void init(InternetAddress ip, int port) {} + +/// Initializes server every time it reloads +Future run(Handler handler, InternetAddress ip, int port) { + return serve(handler, ip, port); +} diff --git a/src/main/resources/handlebars/dart-frog/model.dart.mustache b/src/main/resources/handlebars/dart-frog/model.dart.mustache new file mode 100644 index 0000000000..6f72150506 --- /dev/null +++ b/src/main/resources/handlebars/dart-frog/model.dart.mustache @@ -0,0 +1,26 @@ +{{#if imports}} +// Import models used by this model + {{#each imports}} +import '{{import}}'; + {{/each}} + +{{/if}} +{{#each models}} + {{#with model}} + {{#eq dataType "Object"}} +class {{classname}} { + {{#each vars}} + {{datatype}}{{#unless required}}?{{/unless}} {{name}}; + {{/each}} + + {{classname}}({ + {{#each vars}} + {{#if required}}required {{/if}}this.{{name}}{{#unless @last}},{{/unless}} + {{/each}} + }); +} + {{else}} +typedef {{classname}} = {{dataType}}; + {{/eq}} + {{/with}} +{{/each}} \ No newline at end of file diff --git a/src/main/resources/handlebars/dart-frog/openapi.mustache b/src/main/resources/handlebars/dart-frog/openapi.mustache new file mode 100644 index 0000000000..e1908760c8 --- /dev/null +++ b/src/main/resources/handlebars/dart-frog/openapi.mustache @@ -0,0 +1 @@ +{{{openApiSpec}}} \ No newline at end of file diff --git a/src/main/resources/handlebars/dart-frog/pubspec.yaml.mustache b/src/main/resources/handlebars/dart-frog/pubspec.yaml.mustache new file mode 100644 index 0000000000..9c7a0397ea --- /dev/null +++ b/src/main/resources/handlebars/dart-frog/pubspec.yaml.mustache @@ -0,0 +1,13 @@ +name: {{appName}} +description: {{appDescription}} +version: {{version}} +publish_to: none + +environment: + sdk: ">=3.0.0 <4.0.0" + +dependencies: + dart_frog: ^1.0.0 + +dev_dependencies: + test: ^1.19.2 \ No newline at end of file diff --git a/src/main/resources/handlebars/dart-frog/route.dart.mustache b/src/main/resources/handlebars/dart-frog/route.dart.mustache new file mode 100644 index 0000000000..fc6502a2f8 --- /dev/null +++ b/src/main/resources/handlebars/dart-frog/route.dart.mustache @@ -0,0 +1,69 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:dart_frog/dart_frog.dart'; + +// Import models used by operations +{{#each imports}} +import '{{import}}'; +{{/each}} + +Future onRequest(RequestContext context{{#with operations.operation.[0]}}{{#each pathParams}}, {{dataType}} {{paramName}}{{/each}}{{/with}}) async { + final request = context.request; + + /// Call appropriate HTTP method + switch (request.method) { +{{#each httpVerbs}} + {{#each operations.operation}} + {{#eq httpMethod ../this}} + case HttpMethod.{{lower httpMethod}}: + {{#if queryParams}} + /// Define query parameters + {{#each queryParams}} + {{#eq dataType 'int'}} + final {{paramName}} = int.tryParse(request.uri.queryParameters['{{paramName}}'] ?? '{{maximum}}'); + {{/eq}} + {{#eq dataType 'String'}} + final {{paramName}} = request.uri.queryParameters['{{paramName}}']; + {{/eq}} + {{/each}} + {{/if}} + {{#if bodyParams}} + /// Define body parameters + {{#each bodyParams}} + final {{paramName}} = await request.json() as Map; + {{/each}} + {{/if}} + {{#if headerParams}} + /// Define header parameters + {{/if}} + {{#if cookieParams}} + /// Define cookie parameters + {{/if}} + {{#if formParams}} + /// Define form parameters + {{/if}} + return _{{lower httpMethod}}({{#each allParams}}{{#if @index}}, {{/if}}{{paramName}}{{/each}}); + {{/eq}} + {{/each}} +{{/each}} + // ignore: no_default_cases + default: + return Response( + statusCode: 405, + body: 'Method ${request.method} is not allowed', + ); + } +} + +{{#each httpVerbs}} + {{#each operations.operation}} + {{#eq httpMethod ../this}} +Future _{{lower httpMethod}}({{#each allParams}}{{#if @index}}, {{/if}}{{dataType}} {{paramName}}{{/each}}) async { + throw UnimplementedError( + "This is a stub generated by Swagger Codegen. " + "You must implement this method"); +} + {{/eq}} + {{/each}} +{{/each}} \ No newline at end of file From d9ec98b21c99eaf6c28fc4b5f8f1609587b77446 Mon Sep 17 00:00:00 2001 From: Mychajlo Chodorev Date: Sun, 31 Mar 2024 15:40:07 +0200 Subject: [PATCH 4/5] fix snakeCase --- .../codegen/v3/generators/DefaultCodegenConfig.java | 3 +++ .../codegen/v3/generators/DefaultCodegenConfigTest.java | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java index 3973a49e05..989908bdc5 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java +++ b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java @@ -1194,6 +1194,9 @@ public String snakeCase(String camelCase) { if (Character.isUpperCase(currentChar)) { if (i > 0 && !previousCharWasUpperCase) { snakeCase.append('_'); + } else if (previousCharWasUpperCase && i + 1 < camelCase.length() && + Character.isLowerCase(camelCase.charAt(i + 1))) { + snakeCase.append('_'); } snakeCase.append(Character.toLowerCase(currentChar)); previousCharWasUpperCase = true; diff --git a/src/test/java/io/swagger/codegen/v3/generators/DefaultCodegenConfigTest.java b/src/test/java/io/swagger/codegen/v3/generators/DefaultCodegenConfigTest.java index 0a9fdf4ba0..ce5d48e40c 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/DefaultCodegenConfigTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/DefaultCodegenConfigTest.java @@ -312,6 +312,15 @@ public void testFromResponse_referenceHeaders() { Assert.assertEquals(headerProperty.example, referencedHeader.getSchema().getExample()); } + @Test + public void testSnakeCase() { + final P_DefaultCodegenConfig codegen = new P_DefaultCodegenConfig(); + Assert.assertEquals(codegen.snakeCase("TestTest"), + "test_test"); + Assert.assertEquals(codegen.snakeCase("TEST"), "test"); + Assert.assertEquals(codegen.snakeCase("TESTTest"), "test_test"); + } + @Test(dataProvider = "testCommonPrefixProvider") public void testCommonPrefix(List vars, String expectedPrefix) { DefaultCodegenConfig codegen = new P_DefaultCodegenConfig(); From 114c153662f58cdd64152d4cf0d016598d587649 Mon Sep 17 00:00:00 2001 From: Mychajlo Chodorev Date: Thu, 11 Apr 2024 08:59:11 +0200 Subject: [PATCH 5/5] fix template path --- .../swagger/codegen/v3/generators/dart/DartFrogGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/swagger/codegen/v3/generators/dart/DartFrogGenerator.java b/src/main/java/io/swagger/codegen/v3/generators/dart/DartFrogGenerator.java index 7e5862cf04..919b0fb4b5 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/dart/DartFrogGenerator.java +++ b/src/main/java/io/swagger/codegen/v3/generators/dart/DartFrogGenerator.java @@ -95,7 +95,7 @@ public DartFrogGenerator() { * The generator * will use the resource stream to attempt to read the templates. */ - templateDir = "dart-frog"; + templateDir = "handlebars/dart-frog"; /** * Api Package. Optional, if needed, this can be used in templates