Skip to content
This repository has been archived by the owner on Feb 15, 2024. It is now read-only.

Commit

Permalink
feat: update Models templates to always be public
Browse files Browse the repository at this point in the history
When using the 'nonPublicApi' flag in OpenAPI generator, all clients
and models are made internal by default. However, we wish to have
the clients made internal but the models public, to get the most out
of the generated code, while keeping the interface consistent,
allowing to expose only the method we see fit through ImmutableX
instead of relying on devs using the clients directly.
  • Loading branch information
CassiusPacheco committed Nov 8, 2022
1 parent 38d81bc commit 890545d
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 0 deletions.
143 changes: 143 additions & 0 deletions .openapi-generator/templates/swift5/Models.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Models.swift
//
// Generated by openapi-generator
// https://openapi-generator.tech
//

import Foundation{{#useAlamofire}}
import Alamofire{{/useAlamofire}}

protocol JSONEncodable {
func encodeToJSON() -> Any
}

/// An enum where the last case value can be used as a default catch-all.
protocol CaseIterableDefaultsLast: Decodable & CaseIterable & RawRepresentable
where RawValue: Decodable, AllCases: BidirectionalCollection {}

extension CaseIterableDefaultsLast {
/// Initializes an enum such that if a known raw value is found, then it is decoded.
/// Otherwise the last case is used.
/// - Parameter decoder: A decoder.
public init(from decoder: Decoder) throws {
if let value = try Self(rawValue: decoder.singleValueContainer().decode(RawValue.self)) {
self = value
} else if let lastValue = Self.allCases.last {
self = lastValue
} else {
throw DecodingError.valueNotFound(
Self.Type.self,
.init(codingPath: decoder.codingPath, debugDescription: "CaseIterableDefaultsLast")
)
}
}
}

/// A flexible type that can be encoded (`.encodeNull` or `.encodeValue`)
/// or not encoded (`.encodeNothing`). Intended for request payloads.
public enum NullEncodable<Wrapped: Hashable>: Hashable {
case encodeNothing
case encodeNull
case encodeValue(Wrapped)
}

extension NullEncodable: Codable where Wrapped: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let value = try? container.decode(Wrapped.self) {
self = .encodeValue(value)
} else if container.decodeNil() {
self = .encodeNull
} else {
self = .encodeNothing
}
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .encodeNothing: return
case .encodeNull: try container.encodeNil()
case .encodeValue(let wrapped): try container.encode(wrapped)
}
}
}

public enum ErrorResponse: Error {
case error(Int, Data?, URLResponse?, Error)
}

public enum DownloadException: Error {
case responseDataMissing
case responseFailed
case requestMissing
case requestMissingPath
case requestMissingURL
}

public enum DecodableRequestBuilderError: Error {
case emptyDataResponse
case nilHTTPResponse
case unsuccessfulHTTPStatusCode
case jsonDecoding(DecodingError)
case generalError(Error)
}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class Response<T> {
public let statusCode: Int
public let header: [String: String]
public let body: T
public init(statusCode: Int, header: [String: String], body: T) {
self.statusCode = statusCode
self.header = header
self.body = body
}

public convenience init(response: HTTPURLResponse, body: T) {
let rawHeader = response.allHeaderFields
var header = [String: String]()
for (key, value) in rawHeader {
if let key = key.base as? String, let value = value as? String {
header[key] = value
}
}
self.init(statusCode: response.statusCode, header: header, body: body)
}
}

public final class RequestTask{{#useAsyncAwait}}: @unchecked Sendable{{/useAsyncAwait}} {
private var lock = NSRecursiveLock()
{{#useAlamofire}}
private var request: Request?

internal func set(request: Request) {
lock.lock()
defer { lock.unlock() }
self.request = request
}

public func cancel() {
lock.lock()
defer { lock.unlock() }
request?.cancel()
request = nil
}
{{/useAlamofire}}
{{^useAlamofire}}
private var task: URLSessionTask?

internal func set(task: URLSessionTask) {
lock.lock()
defer { lock.unlock() }
self.task = task
}

public func cancel() {
lock.lock()
defer { lock.unlock() }
task?.cancel()
task = nil
}
{{/useAlamofire}}
}
30 changes: 30 additions & 0 deletions .openapi-generator/templates/swift5/model.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{{#models}}{{#model}}//
// {{classname}}.swift
//
// Generated by openapi-generator
// https://openapi-generator.tech
//

import Foundation
#if canImport(AnyCodable)
import AnyCodable
#endif{{#useVapor}}
import Vapor{{/useVapor}}
{{#swiftUseApiNamespace}}

@available(*, deprecated, renamed: "{{projectName}}API.{{classname}}")
public typealias {{classname}} = {{projectName}}API.{{classname}}

extension {{projectName}}API {
{{/swiftUseApiNamespace}}
{{#description}}

/** {{.}} */{{/description}}{{#isDeprecated}}
@available(*, deprecated, message: "This schema is deprecated."){{/isDeprecated}}{{#vendorExtensions.x-is-one-of-interface}}
{{> modelOneOf}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{#isArray}}
{{> modelArray}}{{/isArray}}{{^isArray}}{{#isEnum}}
{{> modelEnum}}{{/isEnum}}{{^isEnum}}
{{> modelObject}}{{/isEnum}}{{/isArray}}{{/vendorExtensions.x-is-one-of-interface}}{{/model}}{{/models}}
{{#swiftUseApiNamespace}}
}
{{/swiftUseApiNamespace}}
1 change: 1 addition & 0 deletions .openapi-generator/templates/swift5/modelArray.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
public typealias {{classname}} = {{parent}}
7 changes: 7 additions & 0 deletions .openapi-generator/templates/swift5/modelEnum.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
public enum {{classname}}: {{dataType}}, {{#useVapor}}Content, Hashable{{/useVapor}}{{^useVapor}}Codable{{^isString}}{{^isInteger}}{{^isFloat}}{{^isDouble}}, JSONEncodable{{/isDouble}}{{/isFloat}}{{/isInteger}}{{/isString}}{{/useVapor}}, CaseIterable{{#enumUnknownDefaultCase}}{{#isInteger}}, CaseIterableDefaultsLast{{/isInteger}}{{#isFloat}}, CaseIterableDefaultsLast{{/isFloat}}{{#isDouble}}, CaseIterableDefaultsLast{{/isDouble}}{{#isString}}, CaseIterableDefaultsLast{{/isString}}{{/enumUnknownDefaultCase}} {
{{#allowableValues}}
{{#enumVars}}
case {{{name}}} = {{{value}}}
{{/enumVars}}
{{/allowableValues}}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
public enum {{enumName}}: {{^isContainer}}{{dataType}}{{/isContainer}}{{#isContainer}}String{{/isContainer}}, {{#useVapor}}Content, Hashable{{/useVapor}}{{^useVapor}}Codable{{^isContainer}}{{^isString}}{{^isInteger}}{{^isFloat}}{{^isDouble}}, JSONEncodable{{/isDouble}}{{/isFloat}}{{/isInteger}}{{/isString}}{{/isContainer}}{{/useVapor}}, CaseIterable{{#enumUnknownDefaultCase}}{{#isInteger}}, CaseIterableDefaultsLast{{/isInteger}}{{#isFloat}}, CaseIterableDefaultsLast{{/isFloat}}{{#isDouble}}, CaseIterableDefaultsLast{{/isDouble}}{{#isString}}, CaseIterableDefaultsLast{{/isString}}{{#isContainer}}, CaseIterableDefaultsLast{{/isContainer}}{{/enumUnknownDefaultCase}} {
{{#allowableValues}}
{{#enumVars}}
case {{{name}}} = {{{value}}}
{{/enumVars}}
{{/allowableValues}}
}
122 changes: 122 additions & 0 deletions .openapi-generator/templates/swift5/modelObject.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
{{^objcCompatible}}public {{#useClasses}}final class{{/useClasses}}{{^useClasses}}struct{{/useClasses}} {{{classname}}}: {{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{#useJsonEncodable}}, JSONEncodable{{/useJsonEncodable}}{{/useVapor}}{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}} {
{{/objcCompatible}}{{#objcCompatible}}@objc public class {{classname}}: NSObject, Codable{{#useJsonEncodable}}, JSONEncodable{{/useJsonEncodable}} {
{{/objcCompatible}}

{{#allVars}}
{{#isEnum}}
{{> modelInlineEnumDeclaration}}
{{/isEnum}}
{{/allVars}}
{{#allVars}}
{{#isEnum}}
{{#description}}/** {{{.}}} */
{{/description}}{{#deprecated}}@available(*, deprecated, message: "This property is deprecated.")
{{/deprecated}}public {{#readonlyProperties}}private(set) {{/readonlyProperties}}var {{{name}}}: {{#vendorExtensions.x-null-encodable}}NullEncodable<{{{datatypeWithEnum}}}>{{/vendorExtensions.x-null-encodable}}{{^vendorExtensions.x-null-encodable}}{{{datatypeWithEnum}}}{{#required}}{{#isNullable}}?{{/isNullable}}{{/required}}{{^required}}?{{/required}}{{/vendorExtensions.x-null-encodable}}{{#defaultValue}} = {{#vendorExtensions.x-null-encodable}}{{{vendorExtensions.x-null-encodable-default-value}}}{{/vendorExtensions.x-null-encodable}}{{^vendorExtensions.x-null-encodable}}{{{.}}}{{/vendorExtensions.x-null-encodable}}{{/defaultValue}}
{{/isEnum}}
{{^isEnum}}
{{#description}}/** {{{.}}} */
{{/description}}{{#deprecated}}@available(*, deprecated, message: "This property is deprecated.")
{{/deprecated}}public {{#readonlyProperties}}private(set) {{/readonlyProperties}}var {{{name}}}: {{#vendorExtensions.x-null-encodable}}NullEncodable<{{{datatype}}}>{{/vendorExtensions.x-null-encodable}}{{^vendorExtensions.x-null-encodable}}{{{datatype}}}{{#required}}{{#isNullable}}?{{/isNullable}}{{/required}}{{^required}}?{{/required}}{{/vendorExtensions.x-null-encodable}}{{#defaultValue}} = {{#vendorExtensions.x-null-encodable}}{{{vendorExtensions.x-null-encodable-default-value}}}{{/vendorExtensions.x-null-encodable}}{{^vendorExtensions.x-null-encodable}}{{{.}}}{{/vendorExtensions.x-null-encodable}}{{/defaultValue}}
{{#objcCompatible}}
{{#vendorExtensions.x-swift-optional-scalar}}
public var {{{name}}}Num: NSNumber? {
get {
{{^vendorExtensions.x-null-encodable}}
return {{{name}}} as NSNumber?
{{/vendorExtensions.x-null-encodable}}
{{#vendorExtensions.x-null-encodable}}
if case .encodeValue(let value) = {{name}} {
return value as NSNumber?
} else {
return nil
}
{{/vendorExtensions.x-null-encodable}}
}
}
{{/vendorExtensions.x-swift-optional-scalar}}
{{/objcCompatible}}
{{/isEnum}}
{{/allVars}}
{{#hasVars}}

public init({{#allVars}}{{{name}}}: {{#vendorExtensions.x-null-encodable}}NullEncodable<{{{datatypeWithEnum}}}>{{/vendorExtensions.x-null-encodable}}{{^vendorExtensions.x-null-encodable}}{{{datatypeWithEnum}}}{{#required}}{{#isNullable}}?{{/isNullable}}{{/required}}{{^required}}?{{/required}}{{/vendorExtensions.x-null-encodable}}{{#defaultValue}} = {{#vendorExtensions.x-null-encodable}}{{{vendorExtensions.x-null-encodable-default-value}}}{{/vendorExtensions.x-null-encodable}}{{^vendorExtensions.x-null-encodable}}{{{.}}}{{/vendorExtensions.x-null-encodable}}{{/defaultValue}}{{^defaultValue}}{{^required}} = {{#vendorExtensions.x-null-encodable}}.encodeNull{{/vendorExtensions.x-null-encodable}}{{^vendorExtensions.x-null-encodable}}nil{{/vendorExtensions.x-null-encodable}}{{/required}}{{/defaultValue}}{{^-last}}, {{/-last}}{{/allVars}}) {
{{#allVars}}
self.{{{name}}} = {{{name}}}
{{/allVars}}
}
{{/hasVars}}

public enum CodingKeys: {{#hasVars}}String, {{/hasVars}}CodingKey, CaseIterable {
{{#allVars}}
case {{{name}}}{{#vendorExtensions.x-codegen-escaped-property-name}} = "{{{baseName}}}"{{/vendorExtensions.x-codegen-escaped-property-name}}
{{/allVars}}
}{{#generateModelAdditionalProperties}}{{#additionalPropertiesType}}

public {{#readonlyProperties}}private(set) {{/readonlyProperties}}var additionalProperties: [String: {{{additionalPropertiesType}}}] = [:]

public subscript(key: String) -> {{{additionalPropertiesType}}}? {
get {
if let value = additionalProperties[key] {
return value
}
return nil
}

set {
additionalProperties[key] = newValue
}
}{{/additionalPropertiesType}}{{/generateModelAdditionalProperties}}

// Encodable protocol methods

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
{{#allVars}}
{{#vendorExtensions.x-null-encodable}}
switch {{{name}}} {
case .encodeNothing: break
case .encodeNull, .encodeValue: try container.encode({{{name}}}, forKey: .{{{name}}})
}
{{/vendorExtensions.x-null-encodable}}
{{^vendorExtensions.x-null-encodable}}
try container.encode{{^required}}IfPresent{{/required}}({{{name}}}, forKey: .{{{name}}})
{{/vendorExtensions.x-null-encodable}}
{{/allVars}}
{{#generateModelAdditionalProperties}}
{{#additionalPropertiesType}}
var additionalPropertiesContainer = encoder.container(keyedBy: String.self)
try additionalPropertiesContainer.encodeMap(additionalProperties)
{{/additionalPropertiesType}}
{{/generateModelAdditionalProperties}}
}{{#generateModelAdditionalProperties}}{{#additionalPropertiesType}}

// Decodable protocol methods

public{{#objcCompatible}} required{{/objcCompatible}} init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
{{#allVars}}
{{{name}}} = try container.decode{{#required}}{{#isNullable}}IfPresent{{/isNullable}}{{/required}}{{^required}}IfPresent{{/required}}({{{datatypeWithEnum}}}.self, forKey: .{{{name}}})
{{/allVars}}
var nonAdditionalPropertyKeys = Set<String>()
{{#allVars}}
nonAdditionalPropertyKeys.insert("{{{baseName}}}")
{{/allVars}}
let additionalPropertiesContainer = try decoder.container(keyedBy: String.self)
additionalProperties = try additionalPropertiesContainer.decodeMap({{{additionalPropertiesType}}}.self, excludedKeys: nonAdditionalPropertyKeys)
}{{/additionalPropertiesType}}{{/generateModelAdditionalProperties}}{{^objcCompatible}}{{#useClasses}}{{#vendorExtensions.x-swift-hashable}}

public static func == (lhs: {{classname}}, rhs: {{classname}}) -> Bool {
{{#allVars}}
lhs.{{{name}}} == rhs.{{{name}}}{{^-last}} &&{{/-last}}
{{/allVars}}
{{#generateModelAdditionalProperties}}{{#additionalPropertiesType}}{{#hasVars}}&& {{/hasVars}}lhs.additionalProperties == rhs.additionalProperties{{/additionalPropertiesType}}{{/generateModelAdditionalProperties}}
}

public func hash(into hasher: inout Hasher) {
{{#allVars}}
hasher.combine({{{name}}}{{^vendorExtensions.x-null-encodable}}{{^required}}?{{/required}}{{/vendorExtensions.x-null-encodable}}.hashValue)
{{/allVars}}
{{#generateModelAdditionalProperties}}{{#additionalPropertiesType}}hasher.combine(additionalProperties.hashValue){{/additionalPropertiesType}}{{/generateModelAdditionalProperties}}
}{{/vendorExtensions.x-swift-hashable}}{{/useClasses}}{{/objcCompatible}}
}

0 comments on commit 890545d

Please sign in to comment.