Skip to content

Commit

Permalink
[swift5] Add support for oneOfs (#8714)
Browse files Browse the repository at this point in the history
* [swift5] Add support for oneOfs

* Generate a sample Swift project with oneOfs

* Update Swift Samples
  • Loading branch information
allezxandre authored May 24, 2021
1 parent 4e48dae commit 6c40192
Show file tree
Hide file tree
Showing 33 changed files with 1,827 additions and 2 deletions.
10 changes: 10 additions & 0 deletions bin/configs/swift5-oneOf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
generatorName: swift5
outputDir: samples/client/petstore/swift5/oneOf
inputSpec: modules/openapi-generator/src/test/resources/3_0/oneOf.yaml
templateDir: modules/openapi-generator/src/main/resources/swift5
generateAliasAsModel: true
additionalProperties:
podAuthors: ""
podSummary: PetstoreClient
projectName: PetstoreClient
podHomepage: https://github.com/openapitools/openapi-generator
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
*/
public Swift5ClientCodegen() {
super();
this.useOneOfInterfaces = true;

generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
.stability(Stability.BETA)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import AnyCodable
{{#description}}

/** {{description}} */{{/description}}{{#isDeprecated}}
@available(*, deprecated, message: "This schema is deprecated."){{/isDeprecated}}{{#isArray}}
@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}}{{/model}}{{/models}}
{{> modelObject}}{{/isEnum}}{{/isArray}}{{/vendorExtensions.x-is-one-of-interface}}{{/model}}{{/models}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
public enum {{classname}}: Codable {
{{#oneOf}}
case type{{.}}({{.}})
{{/oneOf}}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
{{#oneOf}}
case .type{{.}}(let value):
try container.encode(value)
{{/oneOf}}
}
}

public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
{{#oneOf}}
{{#-first}}
if let value = try? container.decode({{.}}.self) {
{{/-first}}
{{^-first}}
} else if let value = try? container.decode({{.}}.self) {
{{/-first}}
self = .type{{.}}(value)
{{/oneOf}}
} else {
throw DecodingError.typeMismatch(Self.Type.self, .init(codingPath: decoder.codingPath, debugDescription: "Unable to decode instance of {{classname}}"))
}
}
}
63 changes: 63 additions & 0 deletions samples/client/petstore/swift5/oneOf/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## Build generated
build/
DerivedData

## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata

## Other
*.xccheckout
*.moved-aside
*.xcuserstate
*.xcscmblueprint

## Obj-C/Swift specific
*.hmap
*.ipa

## Playgrounds
timeline.xctimeline
playground.xcworkspace

# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
.build/

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/

# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md

fastlane/report.xml
fastlane/screenshots
23 changes: 23 additions & 0 deletions samples/client/petstore/swift5/oneOf/.openapi-generator-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
26 changes: 26 additions & 0 deletions samples/client/petstore/swift5/oneOf/.openapi-generator/FILES
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.gitignore
Cartfile
Package.swift
PetstoreClient.podspec
PetstoreClient/Classes/OpenAPIs/APIHelper.swift
PetstoreClient/Classes/OpenAPIs/APIs.swift
PetstoreClient/Classes/OpenAPIs/APIs/DefaultAPI.swift
PetstoreClient/Classes/OpenAPIs/CodableHelper.swift
PetstoreClient/Classes/OpenAPIs/Configuration.swift
PetstoreClient/Classes/OpenAPIs/Extensions.swift
PetstoreClient/Classes/OpenAPIs/JSONDataEncoding.swift
PetstoreClient/Classes/OpenAPIs/JSONEncodingHelper.swift
PetstoreClient/Classes/OpenAPIs/Models.swift
PetstoreClient/Classes/OpenAPIs/Models/Apple.swift
PetstoreClient/Classes/OpenAPIs/Models/Banana.swift
PetstoreClient/Classes/OpenAPIs/Models/Fruit.swift
PetstoreClient/Classes/OpenAPIs/OpenISO8601DateFormatter.swift
PetstoreClient/Classes/OpenAPIs/SynchronizedDictionary.swift
PetstoreClient/Classes/OpenAPIs/URLSessionImplementations.swift
README.md
docs/Apple.md
docs/Banana.md
docs/DefaultAPI.md
docs/Fruit.md
git_push.sh
project.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5.2.0-SNAPSHOT
2 changes: 2 additions & 0 deletions samples/client/petstore/swift5/oneOf/Cartfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

github "Flight-School/AnyCodable" ~> 0.4.0
33 changes: 33 additions & 0 deletions samples/client/petstore/swift5/oneOf/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// swift-tools-version:5.1

import PackageDescription

let package = Package(
name: "PetstoreClient",
platforms: [
.iOS(.v9),
.macOS(.v10_11),
.tvOS(.v9),
.watchOS(.v3),
],
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "PetstoreClient",
targets: ["PetstoreClient"]
),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/Flight-School/AnyCodable", .exact("0.4.0")),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "PetstoreClient",
dependencies: ["AnyCodable", ],
path: "PetstoreClient/Classes"
),
]
)
15 changes: 15 additions & 0 deletions samples/client/petstore/swift5/oneOf/PetstoreClient.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Pod::Spec.new do |s|
s.name = 'PetstoreClient'
s.ios.deployment_target = '9.0'
s.osx.deployment_target = '10.11'
s.tvos.deployment_target = '9.0'
s.watchos.deployment_target = '3.0'
s.version = '0.0.1'
s.source = { :git => '[email protected]:OpenAPITools/openapi-generator.git', :tag => 'v0.0.1' }
s.authors = ''
s.license = 'Proprietary'
s.homepage = 'https://github.com/openapitools/openapi-generator'
s.summary = 'PetstoreClient'
s.source_files = 'PetstoreClient/Classes/**/*.swift'
s.dependency 'AnyCodable-FlightSchool', '~> 0.4.0'
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// APIHelper.swift
//
// Generated by openapi-generator
// https://openapi-generator.tech
//

import Foundation

public struct APIHelper {
public static func rejectNil(_ source: [String: Any?]) -> [String: Any]? {
let destination = source.reduce(into: [String: Any]()) { result, item in
if let value = item.value {
result[item.key] = value
}
}

if destination.isEmpty {
return nil
}
return destination
}

public static func rejectNilHeaders(_ source: [String: Any?]) -> [String: String] {
return source.reduce(into: [String: String]()) { result, item in
if let collection = item.value as? [Any?] {
result[item.key] = collection.filter { $0 != nil }.map { "\($0!)" }.joined(separator: ",")
} else if let value: Any = item.value {
result[item.key] = "\(value)"
}
}
}

public static func convertBoolToString(_ source: [String: Any]?) -> [String: Any]? {
guard let source = source else {
return nil
}

return source.reduce(into: [String: Any]()) { result, item in
switch item.value {
case let x as Bool:
result[item.key] = x.description
default:
result[item.key] = item.value
}
}
}

public static func mapValueToPathItem(_ source: Any) -> Any {
if let collection = source as? [Any?] {
return collection.filter { $0 != nil }.map { "\($0!)" }.joined(separator: ",")
}
return source
}

public static func mapValuesToQueryItems(_ source: [String: Any?]) -> [URLQueryItem]? {
let destination = source.filter { $0.value != nil }.reduce(into: [URLQueryItem]()) { result, item in
if let collection = item.value as? [Any?] {
collection.filter { $0 != nil }.map { "\($0!)" }.forEach { value in
result.append(URLQueryItem(name: item.key, value: value))
}
} else if let value = item.value {
result.append(URLQueryItem(name: item.key, value: "\(value)"))
}
}

if destination.isEmpty {
return nil
}
return destination
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// APIs.swift
//
// Generated by openapi-generator
// https://openapi-generator.tech
//

import Foundation

open class PetstoreClientAPI {
public static var basePath = "http://localhost"
public static var credential: URLCredential?
public static var customHeaders: [String: String] = [:]
public static var requestBuilderFactory: RequestBuilderFactory = URLSessionRequestBuilderFactory()
public static var apiResponseQueue: DispatchQueue = .main
}

open class RequestBuilder<T> {
var credential: URLCredential?
var headers: [String: String]
public let parameters: [String: Any]?
public let method: String
public let URLString: String

/// Optional block to obtain a reference to the request's progress instance when available.
/// With the URLSession http client the request's progress only works on iOS 11.0, macOS 10.13, macCatalyst 13.0, tvOS 11.0, watchOS 4.0.
/// If you need to get the request's progress in older OS versions, please use Alamofire http client.
public var onProgressReady: ((Progress) -> Void)?

required public init(method: String, URLString: String, parameters: [String: Any]?, headers: [String: String] = [:]) {
self.method = method
self.URLString = URLString
self.parameters = parameters
self.headers = headers

addHeaders(PetstoreClientAPI.customHeaders)
}

open func addHeaders(_ aHeaders: [String: String]) {
for (header, value) in aHeaders {
headers[header] = value
}
}

open func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (_ result: Swift.Result<Response<T>, Error>) -> Void) { }

public func addHeader(name: String, value: String) -> Self {
if !value.isEmpty {
headers[name] = value
}
return self
}

open func addCredential() -> Self {
credential = PetstoreClientAPI.credential
return self
}
}

public protocol RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type
}
Loading

0 comments on commit 6c40192

Please sign in to comment.