Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion Sources/OpenAPIKit/Example/Example.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extension OpenAPI {
/// OpenAPI Spec "Example Object"
///
/// See [OpenAPI Example Object](https://spec.openapis.org/oas/v3.2.0.html#example-object).
public struct Example: Equatable, CodableVendorExtendable, Sendable {
public struct Example: HasConditionalWarnings, CodableVendorExtendable, Sendable {
public let summary: String?
public let description: String?

Expand All @@ -27,6 +27,8 @@ extension OpenAPI {
/// where the values are anything codable.
public var vendorExtensions: [String: AnyCodable]

public let conditionalWarnings: [(any Condition, OpenAPI.Warning)]

public var dataValue: AnyCodable? { value?.dataValue }
public var serializedValue: String? { value?.serializedValue }
public var externalValue: URL? { value?.externalValue }
Expand All @@ -49,6 +51,8 @@ extension OpenAPI {
case nil: self.value = nil
}
self.vendorExtensions = vendorExtensions

self.conditionalWarnings = self.value?.conditionalWarnings ?? []
}

public init(
Expand All @@ -65,6 +69,8 @@ extension OpenAPI {
case nil: self.value = nil
}
self.vendorExtensions = vendorExtensions

self.conditionalWarnings = self.value?.conditionalWarnings ?? []
}

public init(
Expand All @@ -77,6 +83,8 @@ extension OpenAPI {
self.description = description
self.value = value
self.vendorExtensions = vendorExtensions

self.conditionalWarnings = self.value?.conditionalWarnings ?? []
}

public init(
Expand All @@ -94,6 +102,8 @@ extension OpenAPI {
self.value = nil
}
self.vendorExtensions = vendorExtensions

self.conditionalWarnings = self.value?.conditionalWarnings ?? []
}

public init(
Expand All @@ -111,14 +121,43 @@ extension OpenAPI {
self.value = nil
}
self.vendorExtensions = vendorExtensions

self.conditionalWarnings = self.value?.conditionalWarnings ?? []
}
}
}

extension OpenAPI.Example: Equatable {
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.summary == rhs.summary
&& lhs.description == rhs.description
&& lhs.value == rhs.value
&& lhs.vendorExtensions == rhs.vendorExtensions
}
}

extension OpenAPI.Example {
public typealias Map = OrderedDictionary<String, Either<OpenAPI.Reference<OpenAPI.Example>, OpenAPI.Example>>
}

extension OpenAPI.Example.Value {
fileprivate var conditionalWarnings: [(any Condition, OpenAPI.Warning)] {
[
nonNilVersionWarning(fieldName: "dataValue", value: dataValue, minimumVersion: .v3_2_0),
nonNilVersionWarning(fieldName: "serializedValue", value: serializedValue, minimumVersion: .v3_2_0)
].compactMap { $0 }
}
}

fileprivate func nonNilVersionWarning<Subject>(fieldName: String, value: Subject?, minimumVersion: OpenAPI.Document.Version) -> (any Condition, OpenAPI.Warning)? {
value.map { _ in
OpenAPI.Document.ConditionalWarnings.version(
lessThan: minimumVersion,
doesNotSupport: "The Example Object \(fieldName) field"
)
}
}

// MARK: - Either Convenience
extension Either where A == OpenAPI.Reference<OpenAPI.Example>, B == OpenAPI.Example {
@available(*, deprecated, message: "This function populates the deprecated 'value' field, use .value(summary:description:dataValue:serializedValue:vendorExtensions:) or .value(summary:description:dataValue:externalValue:vendorExtensions:) instead.")
Expand Down Expand Up @@ -268,6 +307,8 @@ extension OpenAPI.Example: Decodable {
description = try container.decodeIfPresent(String.self, forKey: .description)

vendorExtensions = try Self.extensions(from: decoder)

conditionalWarnings = self.value?.conditionalWarnings ?? []
}
}

Expand Down
26 changes: 20 additions & 6 deletions Tests/OpenAPIKitTests/ExampleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,21 @@ final class ExampleTests: XCTestCase {
XCTAssertEqual(full1.legacyValue, .init(URL(string: "https://google.com")!))
XCTAssertEqual(full1.dataOrLegacyValue, .init(URL(string: "https://google.com")!))
XCTAssertEqual(full1.vendorExtensions["hello"]?.value as? String, "world")
XCTAssertEqual(full1.conditionalWarnings.count, 0)

let full2 = OpenAPI.Example(
summary: "hello",
description: "world",
dataValue: .init("hello"),
vendorExtensions: ["hello": "world"]
)
XCTAssertEqual(full2.summary, "hello")
XCTAssertEqual(full2.description, "world")
XCTAssertEqual(full2.value?.value, .init("hello"))
XCTAssertEqual(full2.dataValue, .init("hello"))
XCTAssertEqual(full2.dataOrLegacyValue, .init("hello"))
XCTAssertEqual(full2.vendorExtensions["hello"]?.value as? String, "world")
XCTAssertEqual(full2.conditionalWarnings.count, 1)

let full3 = OpenAPI.Example(
summary: "hello",
Expand All @@ -43,25 +51,31 @@ final class ExampleTests: XCTestCase {
XCTAssertEqual(full3.description, "world")
XCTAssertEqual(full3.externalValue, URL(string: "https://google.com")!)
XCTAssertEqual(full3.vendorExtensions["hello"]?.value as? String, "world")
XCTAssertEqual(full3.conditionalWarnings.count, 0)

XCTAssertEqual(full2.summary, "hello")
XCTAssertEqual(full2.description, "world")
XCTAssertEqual(full2.value?.value, .init("hello"))
XCTAssertEqual(full2.dataValue, .init("hello"))
XCTAssertEqual(full2.dataOrLegacyValue, .init("hello"))
XCTAssertEqual(full2.vendorExtensions["hello"]?.value as? String, "world")
let dataPlusSerialized = OpenAPI.Example(
summary: "hello",
dataValue: .init("hello"),
serializedValue: "hello"
)
XCTAssertEqual(dataPlusSerialized.summary, "hello")
XCTAssertEqual(dataPlusSerialized.dataValue, .init("hello"))
XCTAssertEqual(dataPlusSerialized.serializedValue, "hello")
XCTAssertEqual(dataPlusSerialized.conditionalWarnings.count, 2)

let small = OpenAPI.Example(serializedValue: "hello")
XCTAssertNil(small.summary)
XCTAssertNil(small.description)
XCTAssertEqual(small.serializedValue, "hello")
XCTAssertEqual(small.vendorExtensions, [:])
XCTAssertEqual(small.conditionalWarnings.count, 1)

let noValue = OpenAPI.Example()
XCTAssertNil(noValue.summary)
XCTAssertNil(noValue.description)
XCTAssertNil(noValue.value)
XCTAssertEqual(noValue.vendorExtensions, [:])
XCTAssertEqual(noValue.conditionalWarnings.count, 0)

let _ = OpenAPI.Example(legacyValue: .b(.init(["hi": "hello"])))
let _ = OpenAPI.Example(legacyValue: .b("<hi>hello</hi>"))
Expand Down