diff --git a/src/main/java/ru/touchin/codegen/TINetowrkingCodegenConstants.java b/src/main/java/ru/touchin/codegen/TINetowrkingCodegenConstants.java new file mode 100644 index 0000000..aa253a5 --- /dev/null +++ b/src/main/java/ru/touchin/codegen/TINetowrkingCodegenConstants.java @@ -0,0 +1,7 @@ +package ru.touchin.codegen; + +public class TINetowrkingCodegenConstants { + public static final String DATE_FORMAT = "x-custom-date-format"; + public static final String DATE_FORMAT_NAME = "x-codegen-date-format-name"; + public static final String IS_ISO8601_DATE = "x-codegen-is-iso8601-date"; +} diff --git a/src/main/java/ru/touchin/codegen/TINetworkingCodegen.java b/src/main/java/ru/touchin/codegen/TINetworkingCodegen.java index c0c5ad9..258f6c0 100644 --- a/src/main/java/ru/touchin/codegen/TINetworkingCodegen.java +++ b/src/main/java/ru/touchin/codegen/TINetworkingCodegen.java @@ -32,6 +32,8 @@ public class TINetworkingCodegen extends DefaultCodegenConfig { private String[] responseAs = new String[0]; protected String sourceFolder = "Classes" + File.separator + "Swaggers"; + private Map allCustomDateFormats = new HashMap<>(); + @Override public CodegenType getTag() { return CodegenType.CLIENT; @@ -223,6 +225,10 @@ public class TINetworkingCodegen extends DefaultCodegenConfig { sourceFolder, projectName + "+Servers.swift")); + supportingFiles.add(new SupportingFile("APIDateFormat.mustache", + sourceFolder, + "APIDateFormat.swift")); + copyFistAllOfProperties = true; } @@ -479,9 +485,58 @@ public class TINetworkingCodegen extends DefaultCodegenConfig { } } + for (CodegenProperty property : codegenModel.allVars) { + Map vendorExtensions = property.getVendorExtensions(); + + boolean containsCustomDateFormat = vendorExtensions.containsKey(TINetowrkingCodegenConstants.DATE_FORMAT); + + if (property.getIsDate() + || property.getIsDateTime() + && !containsCustomDateFormat) { + vendorExtensions.put(TINetowrkingCodegenConstants.IS_ISO8601_DATE, true); + } else if (containsCustomDateFormat) { + String customDateFormat = (String) vendorExtensions.get(TINetowrkingCodegenConstants.DATE_FORMAT); + String dateFormatName = customDateFormat.replace(".", "_") + .replaceAll("[^A-Za-z0-9_]", ""); + vendorExtensions.put(TINetowrkingCodegenConstants.DATE_FORMAT_NAME, dateFormatName); + } + } + return codegenModel; } + @Override + public Map postProcessAllModels(Map processedModels) { + for (Object processedModel : processedModels.values()) { + Map modelMap = (Map) processedModel; + List> modelsMap = (List>) modelMap.get("models"); + for (Map modelModelsMap : modelsMap) { + CodegenModel codegenModel = (CodegenModel) modelModelsMap.get("model"); + for (CodegenProperty modelProperty : codegenModel.getAllVars()) { + String customDateFormat = (String) modelProperty.getVendorExtensions() + .get(TINetowrkingCodegenConstants.DATE_FORMAT); + + if (customDateFormat != null) { + String dateFormatName = (String) modelProperty.getVendorExtensions() + .get(TINetowrkingCodegenConstants.DATE_FORMAT_NAME); + + allCustomDateFormats.put(dateFormatName, customDateFormat); + } + } + } + + } + + return super.postProcessAllModels(processedModels); + } + + @Override + public Map postProcessSupportingFileData(Map objs) { + Map supportingFileData = super.postProcessSupportingFileData(objs); + supportingFileData.put("apiDateFormats", allCustomDateFormats); + return supportingFileData; + } + protected void updateCodegenModelEnumVars(CodegenModel codegenModel) { super.updateCodegenModelEnumVars(codegenModel); for (CodegenProperty var : codegenModel.allVars) { @@ -502,12 +557,7 @@ public class TINetworkingCodegen extends DefaultCodegenConfig { ArrayList contentStatusCodes = new ArrayList<>(); for (CodegenResponse codegenResponse : codegenOperation.responses) { - Schema schema = (Schema) codegenResponse.getSchema(); - String responseContentType = (String) schema.getExtensions().get("x-content-type"); - - if (Objects.equals(responseContentType, content.getContentType())) { - contentStatusCodes.add(codegenResponse.code); - } + contentStatusCodes.add(codegenResponse.code); } content.getContentExtensions() diff --git a/src/main/resources/handlebars/TINetworking/APIDateFormat.mustache b/src/main/resources/handlebars/TINetworking/APIDateFormat.mustache new file mode 100644 index 0000000..ce0c694 --- /dev/null +++ b/src/main/resources/handlebars/TINetworking/APIDateFormat.mustache @@ -0,0 +1,8 @@ +import TIFoundationUtils +import Foundation + +enum APIDateFormat: String, DateFormat { + {{#each apiDateFormats as |value key|}} + case {{key}} = "{{{value}}}" + {{/each}} +} diff --git a/src/main/resources/handlebars/TINetworking/api.mustache b/src/main/resources/handlebars/TINetworking/api.mustache index 55f3764..1797925 100644 --- a/src/main/resources/handlebars/TINetworking/api.mustache +++ b/src/main/resources/handlebars/TINetworking/api.mustache @@ -36,10 +36,10 @@ public extension EndpointRequest { - parameter {{paramName}}: {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} {{/parameters}} */ - static func {{operationId}}({{#parameters}}{{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}{{#hasParams}}, {{/hasParams}}server: Server = .default) -> EndpointRequest<{{#parameters}}{{{dataType}}}{{/parameters}}, {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> { + static func {{operationId}}({{#parameters}}{{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}{{#hasParams}}, {{/hasParams}}server: Server = .default) -> EndpointRequest<{{#parameters}}{{#isBodyParam}}{{{dataType}}}{{/isBodyParam}}{{/parameters}}{{^hasBodyParam}}EmptyBody{{/hasBodyParam}}, {{{returnType}}}> { .init(templatePath: "{{{path}}}", method: .init(rawValue: "{{httpMethod}}"), - body: body, + body: {{#hasBodyParam}}body{{/hasBodyParam}}{{^hasBodyParam}}EmptyBody(){{/hasBodyParam}}, acceptableStatusCodes: [{{contentExtensions.x-codegen-acceptable-status-codes}}], server: server) } diff --git a/src/main/resources/handlebars/TINetworking/modelObject.mustache b/src/main/resources/handlebars/TINetworking/modelObject.mustache index 6a16f6f..5a08bed 100644 --- a/src/main/resources/handlebars/TINetworking/modelObject.mustache +++ b/src/main/resources/handlebars/TINetworking/modelObject.mustache @@ -20,11 +20,44 @@ public {{#useModelClasses}}class{{/useModelClasses}}{{^useModelClasses}}struct{{ {{/allVars}} {{#hasVars}} + private enum CodingKeys: String, CodingKey { + {{#allVars}} + case {{name}} + {{/allVars}} + } + public init({{#allVars}}{{name}}: {{{datatypeWithEnum}}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/allVars}}) { {{#allVars}} self.{{name}} = {{name}} {{/allVars}} } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + {{#allVars}} + {{#if vendorExtensions.x-codegen-is-iso8601-date}} + {{name}} = try container.decodeDate(forKey: .{{name}}, using: try decoder.userInfo.iso8601DateFormatter(for: .{{#isDate}}withFullDate{{/isDate}}{{#isDateTime}}withInternetDateTime{{/isDateTime}}){{^required}}, required: false{{/required}}) + {{else if vendorExtensions.x-custom-date-format}} + {{name}} = try container.decodeDate(forKey: .{{name}}, using: try decoder.userInfo.dateFormatter(for: APIDateFormat.{{vendorExtensions.x-codegen-date-format-name}}){{^required}}, required: false{{/required}}) + {{else}} + {{name}} = try container.decode({{{datatypeWithEnum}}}{{^required}}?{{/required}}.self, forKey: .{{name}}{{^required}}, required: false{{/required}}) + {{/if}} + {{/allVars}} + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + {{#allVars}} + {{#if vendorExtensions.x-codegen-is-iso8601-date}} + try container.encode(date: {{name}}, forKey: .{{name}}, using: try encoder.userInfo.iso8601DateFormatter(for: .{{#isDate}}withFullDate{{/isDate}}{{#isDateTime}}withInternetDateTime{{/isDateTime}}){{^required}}, required: false{{/required}}) + {{else if vendorExtensions.x-custom-date-format}} + try container.encode(date: {{name}}, forKey: .{{name}}, using: try encoder.userInfo.dateFormatter(for: APIDateFormat.{{vendorExtensions.x-codegen-date-format-name}}){{^required}}, required: false{{/required}}) + {{else}} + try container.encode({{name}}, forKey: .{{name}}{{^required}}, required: false{{/required}}) + {{/if}} + {{/allVars}} + } {{/hasVars}} {{#additionalPropertiesType}} public var additionalProperties: [String:{{{additionalPropertiesType}}}] = [:]