From 49b46c7b1397fe178d14a05a0315b750478ee9a6 Mon Sep 17 00:00:00 2001 From: Alberto Lagos Date: Mon, 11 Sep 2023 20:28:56 -0300 Subject: [PATCH 01/10] #294: Add `LocallyDereferenceable` conformance for `OrderedDictionary` --- ...eredDictionry+LocallyDereferenceable.swift | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Sources/OpenAPIKit/Utility/OrderedDictionry+LocallyDereferenceable.swift diff --git a/Sources/OpenAPIKit/Utility/OrderedDictionry+LocallyDereferenceable.swift b/Sources/OpenAPIKit/Utility/OrderedDictionry+LocallyDereferenceable.swift new file mode 100644 index 000000000..4846ced2c --- /dev/null +++ b/Sources/OpenAPIKit/Utility/OrderedDictionry+LocallyDereferenceable.swift @@ -0,0 +1,35 @@ +// +// OrderedDictionry+LocallyDereferenceable.swift +// +// +// Created by Alberto Lagos on 11-09-23. +// + +import OpenAPIKitCore +import Foundation + +/// A Swift extension for dereferencing an `OrderedDictionary` conforming to the `LocallyDereferenceable` protocol. +/// +/// - Parameters: +/// - components: The OpenAPI components containing definitions. +/// - references: A set of references to track dereferenced items. +/// - name: The name of the component from which the dereferencing is initiated. +/// +/// - Returns: A dereferenced `OrderedDictionary` containing keys and values of dereferenced types. +/// +/// - Throws: An error if dereferencing fails for any element. +extension OrderedDictionary: LocallyDereferenceable where Key: LocallyDereferenceable, Key.DereferencedSelf: Hashable, Value: LocallyDereferenceable { + + public func _dereferenced(in components: OpenAPI.Components, + following references: Set, + dereferencedFromComponentNamed name: String?) throws -> OpenAPIKitCore.OrderedDictionary { + + try reduce(into: OrderedDictionary()) { result, element in + let key = try element.key._dereferenced(in: components, following: references, dereferencedFromComponentNamed: name) + + let value = try element.value._dereferenced(in: components, following: references, dereferencedFromComponentNamed: name) + result[key] = value + } + + } +} From 929d5a133c3b348c517219b0d6e5a22a00d32c81 Mon Sep 17 00:00:00 2001 From: Alberto Lagos Date: Mon, 11 Sep 2023 20:31:43 -0300 Subject: [PATCH 02/10] #294: Add `DereferencedCallbacks` & `DereferencedCallbacksMap` --- Sources/OpenAPIKit/Callbacks.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/OpenAPIKit/Callbacks.swift b/Sources/OpenAPIKit/Callbacks.swift index 079f3c74b..989c29966 100644 --- a/Sources/OpenAPIKit/Callbacks.swift +++ b/Sources/OpenAPIKit/Callbacks.swift @@ -19,4 +19,11 @@ extension OpenAPI { /// A map of named collections of Callback Objects (`OpenAPI.Callbacks`). public typealias CallbacksMap = OrderedDictionary, Callbacks>> + + /// A dictionary of Dereferenced of callbacks. + public typealias DereferencedCallbacks = OrderedDictionary + + /// A dictionary of Dereferenced map of callbacks. + public typealias DereferencedCallbacksMap = OrderedDictionary +} } From 5947eed022e05e04e99ce569643285a217b51c2a Mon Sep 17 00:00:00 2001 From: Alberto Lagos Date: Mon, 11 Sep 2023 20:32:25 -0300 Subject: [PATCH 03/10] #294: Add `LocallyDereferenceable` conformance for `OpenAPI.CallbackURL` --- Sources/OpenAPIKit/Callbacks.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/OpenAPIKit/Callbacks.swift b/Sources/OpenAPIKit/Callbacks.swift index 989c29966..3d1edf793 100644 --- a/Sources/OpenAPIKit/Callbacks.swift +++ b/Sources/OpenAPIKit/Callbacks.swift @@ -26,4 +26,14 @@ extension OpenAPI { /// A dictionary of Dereferenced map of callbacks. public typealias DereferencedCallbacksMap = OrderedDictionary } + +extension OpenAPI.CallbackURL: LocallyDereferenceable { + public func _dereferenced( + in components: OpenAPI.Components, + following references: Set, + dereferencedFromComponentNamed name: String? + ) throws -> OpenAPI.CallbackURL { + self + } } + From b8fc2777c2a2875903aa7d815db706b40b17eea4 Mon Sep 17 00:00:00 2001 From: Alberto Lagos Date: Mon, 11 Sep 2023 20:32:53 -0300 Subject: [PATCH 04/10] #294: Add Callbacks when dereference. --- Sources/OpenAPIKit/Operation/DereferencedOperation.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Sources/OpenAPIKit/Operation/DereferencedOperation.swift b/Sources/OpenAPIKit/Operation/DereferencedOperation.swift index b125374e1..da2a06050 100644 --- a/Sources/OpenAPIKit/Operation/DereferencedOperation.swift +++ b/Sources/OpenAPIKit/Operation/DereferencedOperation.swift @@ -20,6 +20,9 @@ public struct DereferencedOperation: Equatable { public let requestBody: DereferencedRequest? /// A dereferenced map of responses. public let responses: DereferencedResponse.Map + /// A dereferenced map of callbacks. + public let callbacks: OpenAPI.DereferencedCallbacksMap + /// An array of dereferenced security requirements. /// /// If defined, overrides the security requirements in the @@ -71,6 +74,12 @@ public struct DereferencedOperation: Equatable { ) } + self.callbacks = try operation.callbacks.mapValues { callback in + try callback._dereferenced(in: components, + following: references, + dereferencedFromComponentNamed: nil) + } + self.underlyingOperation = operation } } From 238d517b47cf1b72dc0f80601c874aec40248d8e Mon Sep 17 00:00:00 2001 From: Alberto Lagos Date: Mon, 11 Sep 2023 20:32:59 -0300 Subject: [PATCH 05/10] #294: Add UTs. --- .../DereferencedOperationTests.swift | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Tests/OpenAPIKitTests/Operation/DereferencedOperationTests.swift b/Tests/OpenAPIKitTests/Operation/DereferencedOperationTests.swift index 83e4d33d2..611528269 100644 --- a/Tests/OpenAPIKitTests/Operation/DereferencedOperationTests.swift +++ b/Tests/OpenAPIKitTests/Operation/DereferencedOperationTests.swift @@ -164,4 +164,41 @@ final class DereferencedOperationTests: XCTestCase { ).dereferenced(in: .noComponents) ) } + + func test_dereferencedCallback() throws { + let components = OpenAPI.Components( + callbacks: [ + "callback": [ + OpenAPI.CallbackURL(rawValue: "{$url}")!: .pathItem( + .init( + description: "Example of pathItem", + post: .init(tags: "op callback", responses: [:]) + ) + ) + ] + ] + ) + + let t1 = try OpenAPI.Operation( + responses: [:], + callbacks: [ + "callback": .reference(.component(named: "callback")) + ] + ).dereferenced(in: components) + XCTAssertEqual(t1.callbacks.count, 1) + XCTAssertEqual(t1.callbacks["callback"]?.keys[0], OpenAPI.CallbackURL(rawValue: "{$url}")) + XCTAssertEqual(t1.callbacks["callback"]?.values[0].description, "Example of pathItem") + XCTAssertEqual(t1.callbacks["callback"]?.values[0][.post]?.tags, ["op callback"]) + } + + func test_callbackReferenceMissing() throws { + XCTAssertThrowsError( + try OpenAPI.Operation( + responses: [:], + callbacks: [ + "callback": .reference(.component(named: "callback")) + ] + ).dereferenced(in: .noComponents) + ) + } } From a2d5480b6a98d4fed9fa190ff54111f230483cfa Mon Sep 17 00:00:00 2001 From: Alberto Lagos Date: Mon, 11 Sep 2023 20:34:34 -0300 Subject: [PATCH 06/10] #294: Add `LocallyDereferenceable` conformance for `OpenAPI.CallbackURL` (OpenAPIKit30) --- Sources/OpenAPIKit30/Callbacks.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Sources/OpenAPIKit30/Callbacks.swift b/Sources/OpenAPIKit30/Callbacks.swift index 6309e7713..f0504fa25 100644 --- a/Sources/OpenAPIKit30/Callbacks.swift +++ b/Sources/OpenAPIKit30/Callbacks.swift @@ -18,4 +18,20 @@ extension OpenAPI { /// A map of named collections of Callback Objects (`OpenAPI.Callbacks`). public typealias CallbacksMap = OrderedDictionary, Callbacks>> + + /// A dictionary of Dereferenced of callbacks. + public typealias DereferencedCallbacks = OrderedDictionary + + /// A dictionary of Dereferenced map of callbacks. + public typealias DereferencedCallbacksMap = OrderedDictionary +} + +extension OpenAPI.CallbackURL: LocallyDereferenceable { + public func _dereferenced( + in components: OpenAPI.Components, + following references: Set, + dereferencedFromComponentNamed name: String? + ) throws -> OpenAPI.CallbackURL { + self + } } From bc6c5864de26656321e010ba0f45f159698eae15 Mon Sep 17 00:00:00 2001 From: Alberto Lagos Date: Mon, 11 Sep 2023 20:38:59 -0300 Subject: [PATCH 07/10] #294: Add `LocallyDereferenceable` conformance for `OrderedDictionary` (OpenAPIKit30) --- ...eredDictionry+LocallyDereferenceable.swift | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Sources/OpenAPIKit30/Utility/OrderedDictionry+LocallyDereferenceable.swift diff --git a/Sources/OpenAPIKit30/Utility/OrderedDictionry+LocallyDereferenceable.swift b/Sources/OpenAPIKit30/Utility/OrderedDictionry+LocallyDereferenceable.swift new file mode 100644 index 000000000..4846ced2c --- /dev/null +++ b/Sources/OpenAPIKit30/Utility/OrderedDictionry+LocallyDereferenceable.swift @@ -0,0 +1,35 @@ +// +// OrderedDictionry+LocallyDereferenceable.swift +// +// +// Created by Alberto Lagos on 11-09-23. +// + +import OpenAPIKitCore +import Foundation + +/// A Swift extension for dereferencing an `OrderedDictionary` conforming to the `LocallyDereferenceable` protocol. +/// +/// - Parameters: +/// - components: The OpenAPI components containing definitions. +/// - references: A set of references to track dereferenced items. +/// - name: The name of the component from which the dereferencing is initiated. +/// +/// - Returns: A dereferenced `OrderedDictionary` containing keys and values of dereferenced types. +/// +/// - Throws: An error if dereferencing fails for any element. +extension OrderedDictionary: LocallyDereferenceable where Key: LocallyDereferenceable, Key.DereferencedSelf: Hashable, Value: LocallyDereferenceable { + + public func _dereferenced(in components: OpenAPI.Components, + following references: Set, + dereferencedFromComponentNamed name: String?) throws -> OpenAPIKitCore.OrderedDictionary { + + try reduce(into: OrderedDictionary()) { result, element in + let key = try element.key._dereferenced(in: components, following: references, dereferencedFromComponentNamed: name) + + let value = try element.value._dereferenced(in: components, following: references, dereferencedFromComponentNamed: name) + result[key] = value + } + + } +} From a87d5f65aaeb83c3ccd9515abc3927382351f82f Mon Sep 17 00:00:00 2001 From: Alberto Lagos Date: Mon, 11 Sep 2023 20:39:26 -0300 Subject: [PATCH 08/10] #294: Add Callbacks when dereference. --- .../OpenAPIKit30/Operation/DereferencedOperation.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Sources/OpenAPIKit30/Operation/DereferencedOperation.swift b/Sources/OpenAPIKit30/Operation/DereferencedOperation.swift index b125374e1..05ef9dd37 100644 --- a/Sources/OpenAPIKit30/Operation/DereferencedOperation.swift +++ b/Sources/OpenAPIKit30/Operation/DereferencedOperation.swift @@ -20,6 +20,9 @@ public struct DereferencedOperation: Equatable { public let requestBody: DereferencedRequest? /// A dereferenced map of responses. public let responses: DereferencedResponse.Map + /// A dereferenced map of callbacks. + public let callbacks: OpenAPI.DereferencedCallbacksMap + /// An array of dereferenced security requirements. /// /// If defined, overrides the security requirements in the @@ -71,6 +74,12 @@ public struct DereferencedOperation: Equatable { ) } + self.callbacks = try operation.callbacks.mapValues { callback in + try callback._dereferenced(in: components, + following: references, + dereferencedFromComponentNamed: nil) + } + self.underlyingOperation = operation } } From 5c43e3162b4804c98581633221e9b32ad1df0033 Mon Sep 17 00:00:00 2001 From: Alberto Lagos Date: Mon, 11 Sep 2023 20:46:35 -0300 Subject: [PATCH 09/10] #294: Add UTs. (OpenAPIKit30) --- .../DereferencedOperationTests.swift | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Tests/OpenAPIKit30Tests/Operation/DereferencedOperationTests.swift b/Tests/OpenAPIKit30Tests/Operation/DereferencedOperationTests.swift index ae73c422e..594d13f4a 100644 --- a/Tests/OpenAPIKit30Tests/Operation/DereferencedOperationTests.swift +++ b/Tests/OpenAPIKit30Tests/Operation/DereferencedOperationTests.swift @@ -164,4 +164,39 @@ final class DereferencedOperationTests: XCTestCase { ).dereferenced(in: .noComponents) ) } + + func test_dereferencedCallback() throws { + let components = OpenAPI.Components( + callbacks: [ + "callback": [ + OpenAPI.CallbackURL(rawValue: "{$url}")!: .init( + description: "Example of pathItem", + post: .init(tags: "op callback", responses: [:]) + ) + ] + ] + ) + + let t1 = try OpenAPI.Operation( + responses: [:], + callbacks: [ + "callback": .reference(.component(named: "callback")) + ] + ).dereferenced(in: components) + XCTAssertEqual(t1.callbacks.count, 1) + XCTAssertEqual(t1.callbacks["callback"]?.keys[0], OpenAPI.CallbackURL(rawValue: "{$url}")) + XCTAssertEqual(t1.callbacks["callback"]?.values[0].description, "Example of pathItem") + XCTAssertEqual(t1.callbacks["callback"]?.values[0][.post]?.tags, ["op callback"]) + } + + func test_callbackReferenceMissing() throws { + XCTAssertThrowsError( + try OpenAPI.Operation( + responses: [:], + callbacks: [ + "callback": .reference(.component(named: "callback")) + ] + ).dereferenced(in: .noComponents) + ) + } } From f9a8e8dc7c5c6e05aece452fcac0c373f79ef60f Mon Sep 17 00:00:00 2001 From: Alberto Lagos Date: Tue, 12 Sep 2023 08:31:04 -0300 Subject: [PATCH 10/10] #294: Passing nil to `dereferencedFromComponentNamed` instead. (OpenAPIKit30/OpenAPIKit) --- .../Utility/OrderedDictionry+LocallyDereferenceable.swift | 4 ++-- .../Utility/OrderedDictionry+LocallyDereferenceable.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/OpenAPIKit/Utility/OrderedDictionry+LocallyDereferenceable.swift b/Sources/OpenAPIKit/Utility/OrderedDictionry+LocallyDereferenceable.swift index 4846ced2c..95b114b50 100644 --- a/Sources/OpenAPIKit/Utility/OrderedDictionry+LocallyDereferenceable.swift +++ b/Sources/OpenAPIKit/Utility/OrderedDictionry+LocallyDereferenceable.swift @@ -25,9 +25,9 @@ extension OrderedDictionary: LocallyDereferenceable where Key: LocallyDereferenc dereferencedFromComponentNamed name: String?) throws -> OpenAPIKitCore.OrderedDictionary { try reduce(into: OrderedDictionary()) { result, element in - let key = try element.key._dereferenced(in: components, following: references, dereferencedFromComponentNamed: name) + let key = try element.key._dereferenced(in: components, following: references, dereferencedFromComponentNamed: nil) - let value = try element.value._dereferenced(in: components, following: references, dereferencedFromComponentNamed: name) + let value = try element.value._dereferenced(in: components, following: references, dereferencedFromComponentNamed: nil) result[key] = value } diff --git a/Sources/OpenAPIKit30/Utility/OrderedDictionry+LocallyDereferenceable.swift b/Sources/OpenAPIKit30/Utility/OrderedDictionry+LocallyDereferenceable.swift index 4846ced2c..95b114b50 100644 --- a/Sources/OpenAPIKit30/Utility/OrderedDictionry+LocallyDereferenceable.swift +++ b/Sources/OpenAPIKit30/Utility/OrderedDictionry+LocallyDereferenceable.swift @@ -25,9 +25,9 @@ extension OrderedDictionary: LocallyDereferenceable where Key: LocallyDereferenc dereferencedFromComponentNamed name: String?) throws -> OpenAPIKitCore.OrderedDictionary { try reduce(into: OrderedDictionary()) { result, element in - let key = try element.key._dereferenced(in: components, following: references, dereferencedFromComponentNamed: name) + let key = try element.key._dereferenced(in: components, following: references, dereferencedFromComponentNamed: nil) - let value = try element.value._dereferenced(in: components, following: references, dereferencedFromComponentNamed: name) + let value = try element.value._dereferenced(in: components, following: references, dereferencedFromComponentNamed: nil) result[key] = value }