-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
11300f1
commit 6b00ecb
Showing
16 changed files
with
1,286 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// | ||
// AnyJSONCaseIterable.swift | ||
// OpenAPI | ||
// | ||
// Created by Mathew Polzin on 6/22/19. | ||
// | ||
|
||
import Foundation | ||
import OpenAPIKit30 | ||
|
||
public protocol AnyRawRepresentable { | ||
/// The `RawValue` type of this type. | ||
static var rawValueType: Any.Type { get } | ||
} | ||
|
||
extension AnyRawRepresentable where Self: RawRepresentable { | ||
/// The default `rawValueType` of a `RawRepresentable` is just the | ||
/// type of `Self.RawValue`. | ||
public static var rawValueType: Any.Type { return Self.RawValue.self } | ||
} | ||
|
||
/// Anything conforming to `AnyJSONCaseIterable` can provide a | ||
/// list of its possible values. | ||
public protocol AnyJSONCaseIterable: AnyRawRepresentable { | ||
static func allCases(using encoder: JSONEncoder) -> [AnyCodable] | ||
} | ||
|
||
extension AnyJSONCaseIterable where Self: RawRepresentable { | ||
/// The default `rawValueType` of a `RawRepresentable` is just the | ||
/// type of `Self.RawValue`. | ||
public static var rawValueType: Any.Type { return Self.RawValue.self } | ||
} | ||
|
||
public extension AnyJSONCaseIterable { | ||
/// Given an array of Codable values, retrieve an array of AnyCodables. | ||
static func allCases<T: Encodable>(from input: [T], using encoder: JSONEncoder) throws -> [AnyCodable] { | ||
return try OpenAPIReflection30.allCases(from: input, using: encoder) | ||
} | ||
} | ||
|
||
public extension AnyJSONCaseIterable where Self: CaseIterable, Self: Codable { | ||
static func caseIterableOpenAPISchemaGuess(using encoder: JSONEncoder) throws -> JSONSchema { | ||
guard let first = allCases.first else { | ||
throw OpenAPI.EncodableError.exampleNotCodable | ||
} | ||
let itemSchema = try OpenAPIReflection30.nestedGenericOpenAPISchemaGuess(for: first, using: encoder) | ||
|
||
return itemSchema.with(allowedValues: allCases.map { AnyCodable($0) }) | ||
} | ||
} | ||
|
||
extension CaseIterable where Self: Encodable { | ||
public static func allCases(using encoder: JSONEncoder) -> [AnyCodable] { | ||
return (try? OpenAPIReflection30.allCases(from: Array(Self.allCases), using: encoder)) ?? [] | ||
} | ||
} | ||
|
||
fileprivate func allCases<T: Encodable>(from input: [T], using encoder: JSONEncoder) throws -> [AnyCodable] { | ||
if let alreadyGoodToGo = input as? [AnyCodable] { | ||
return alreadyGoodToGo | ||
} | ||
|
||
// The following is messy, but it does get us the intended result: | ||
// Given any array of things that can be encoded, we want | ||
// to map to an array of AnyCodable so we can store later. We need to | ||
// muck with JSONSerialization because something like an `enum` may | ||
// very well be encoded as a string, and therefore representable | ||
// by AnyCodable, but AnyCodable wants it to actually BE a String | ||
// upon initialization. | ||
|
||
guard let arrayOfCodables = try JSONSerialization.jsonObject(with: encoder.encode(input), options: []) as? [Any] else { | ||
throw OpenAPI.EncodableError.allCasesArrayNotCodable | ||
} | ||
return arrayOfCodables.map(AnyCodable.init) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// | ||
// Date+OpenAPI.swift | ||
// OpenAPI | ||
// | ||
// Created by Mathew Polzin on 1/24/19. | ||
// | ||
|
||
import Foundation | ||
import OpenAPIKit30 | ||
|
||
extension Date: DateOpenAPISchemaType { | ||
public static func dateOpenAPISchemaGuess(using encoder: JSONEncoder) -> JSONSchema? { | ||
|
||
switch encoder.dateEncodingStrategy { | ||
case .deferredToDate, .custom: | ||
// I don't know if we can say anything about this case without | ||
// encoding the Date and looking at it, which is what `primitiveGuess()` | ||
// does. | ||
return nil | ||
|
||
case .secondsSince1970, | ||
.millisecondsSince1970: | ||
return .number(format: .double) | ||
|
||
case .iso8601: | ||
return .string(format: .dateTime) | ||
|
||
case .formatted(let formatter): | ||
let hasTime = formatter.timeStyle != .none | ||
let format: JSONTypeFormat.StringFormat = hasTime ? .dateTime : .date | ||
|
||
return .string(format: format) | ||
|
||
@unknown default: | ||
return nil | ||
} | ||
} | ||
} | ||
|
||
extension Date: OpenAPIEncodedSchemaType { | ||
public static func openAPISchema(using encoder: JSONEncoder) throws -> JSONSchema { | ||
guard let dateSchema: JSONSchema = try openAPISchemaGuess(for: Date(), using: encoder) else { | ||
throw OpenAPI.TypeError.unknownSchemaType(type(of: self)) | ||
} | ||
|
||
return dateSchema | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// | ||
// OpenAPI+Errors.swift | ||
// | ||
// | ||
// Created by Mathew Polzin on 4/21/20. | ||
// | ||
|
||
import Foundation | ||
import OpenAPIKit30 | ||
|
||
extension OpenAPI { | ||
public enum TypeError: Swift.Error, CustomDebugStringConvertible { | ||
case invalidSchema | ||
case unknownSchemaType(Any.Type) | ||
|
||
public var debugDescription: String { | ||
switch self { | ||
case .invalidSchema: | ||
return "Invalid Schema" | ||
case .unknownSchemaType(let type): | ||
return "Could not determine OpenAPI schema type of \(String(describing: type))" | ||
} | ||
} | ||
} | ||
|
||
public enum EncodableError: Swift.Error, Equatable { | ||
case allCasesArrayNotCodable | ||
case exampleNotCodable | ||
case primitiveGuessFailed | ||
case exampleNotSupported(String) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// | ||
// Optional+ZipWith.swift | ||
// OpenAPIKit | ||
// | ||
// Created by Mathew Polzin on 1/19/19. | ||
// | ||
|
||
/// Zip two optionals together with the given operation performed on | ||
/// the unwrapped contents. If either optional is nil, the zip | ||
/// yields nil. | ||
func zip<X, Y, Z>(_ left: X?, _ right: Y?, with fn: (X, Y) -> Z) -> Z? { | ||
return left.flatMap { lft in right.map { rght in fn(lft, rght) }} | ||
} |
Oops, something went wrong.