-
Notifications
You must be signed in to change notification settings - Fork 37
/
Example.swift
167 lines (144 loc) · 5.13 KB
/
Example.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//
// Example.swift
//
//
// Created by Mathew Polzin on 10/6/19.
//
import OpenAPIKitCore
import Foundation
extension OpenAPI {
/// OpenAPI Spec "Example Object"
///
/// See [OpenAPI Example Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#example-object).
public struct Example: Equatable, CodableVendorExtendable {
public let summary: String?
public let description: String?
/// Represents the OpenAPI `externalValue` as a URL _or_
/// the OpenAPI `value` as `AnyCodable`.
public let value: Either<URL, AnyCodable>
/// Dictionary of vendor extensions.
///
/// These should be of the form:
/// `[ "x-extensionKey": <anything>]`
/// where the values are anything codable.
public let vendorExtensions: [String: AnyCodable]
public init(
summary: String? = nil,
description: String? = nil,
value: Either<URL, AnyCodable>,
vendorExtensions: [String: AnyCodable] = [:]
) {
self.summary = summary
self.description = description
self.value = value
self.vendorExtensions = vendorExtensions
}
}
}
extension OpenAPI.Example {
public typealias Map = OrderedDictionary<String, Either<JSONReference<OpenAPI.Example>, OpenAPI.Example>>
}
// MARK: - Either Convenience
extension Either where A == JSONReference<OpenAPI.Example>, B == OpenAPI.Example {
/// Construct an `Example`.
public static func example(
summary: String? = nil,
description: String? = nil,
value: Either<URL, AnyCodable>,
vendorExtensions: [String: AnyCodable] = [:]
) -> Self {
return .b(
.init(
summary: summary,
description: description,
value: value,
vendorExtensions: vendorExtensions
)
)
}
}
// MARK: - Codable
extension OpenAPI.Example: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(summary, forKey: .summary)
try container.encodeIfPresent(description, forKey: .description)
switch value {
case .a(let url):
try container.encode(url.absoluteURL, forKey: .externalValue)
case .b(let example):
try container.encode(example, forKey: .value)
}
try encodeExtensions(to: &container)
}
}
extension OpenAPI.Example: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
guard !(container.contains(.externalValue) && container.contains(.value)) else {
throw InconsistencyError(
subjectName: "example value",
details: "Found both `value` and `externalValue` keys in an Example. You must specify one or the other.",
codingPath: container.codingPath
)
}
let externalValue = try container.decodeURLAsStringIfPresent(forKey: .externalValue)
summary = try container.decodeIfPresent(String.self, forKey: .summary)
description = try container.decodeIfPresent(String.self, forKey: .description)
value = try externalValue.map(Either.init)
?? .init( container.decode(AnyCodable.self, forKey: .value))
vendorExtensions = try Self.extensions(from: decoder)
}
}
extension OpenAPI.Example {
internal enum CodingKeys: ExtendableCodingKey {
case summary
case description
case value
case externalValue
case extended(String)
static var allBuiltinKeys: [CodingKeys] {
return [.summary, .description, .value, .externalValue]
}
static func extendedKey(for value: String) -> CodingKeys {
return .extended(value)
}
init?(stringValue: String) {
switch stringValue {
case "summary":
self = .summary
case "description":
self = .description
case "value":
self = .value
case "externalValue":
self = .externalValue
default:
self = .extendedKey(for: stringValue)
}
}
var stringValue: String {
switch self {
case .summary:
return "summary"
case .description:
return "description"
case .value:
return "value"
case .externalValue:
return "externalValue"
case .extended(let key):
return key
}
}
}
}
// MARK: - LocallyDereferenceable
extension OpenAPI.Example: LocallyDereferenceable {
/// Examples do not contain any references but for convenience
/// they can be "dereferenced" to themselves.
public func _dereferenced(in components: OpenAPI.Components, following references: Set<AnyHashable>) throws -> OpenAPI.Example {
return self
}
}
extension OpenAPI.Example: Validatable {}