diff --git a/Sources/OpenAPIKit/Schema Object/JSONSchema.swift b/Sources/OpenAPIKit/Schema Object/JSONSchema.swift index bbc6d7ca8..80285a6a0 100644 --- a/Sources/OpenAPIKit/Schema Object/JSONSchema.swift +++ b/Sources/OpenAPIKit/Schema Object/JSONSchema.swift @@ -1971,7 +1971,10 @@ extension JSONSchema: Decodable { schema = schema.nullableSchemaObject() } - self = schema + // Ad-hoc vendor extension support since JSONSchema does coding keys differently. + let extensions = try Self.decodeVenderExtensions(from: decoder) + + self = schema.with(vendorExtensions: extensions) return } @@ -1988,7 +1991,10 @@ extension JSONSchema: Decodable { schema = schema.nullableSchemaObject() } - self = schema + // Ad-hoc vendor extension support since JSONSchema does coding keys differently. + let extensions = try Self.decodeVenderExtensions(from: decoder) + + self = schema.with(vendorExtensions: extensions) return } @@ -2004,7 +2010,10 @@ extension JSONSchema: Decodable { schema = schema.nullableSchemaObject() } - self = schema + // Ad-hoc vendor extension support since JSONSchema does coding keys differently. + let extensions = try Self.decodeVenderExtensions(from: decoder) + + self = schema.with(vendorExtensions: extensions) return } @@ -2016,8 +2025,11 @@ extension JSONSchema: Decodable { core: coreContext ) ) - - self = schema + + // Ad-hoc vendor extension support since JSONSchema does coding keys differently. + let extensions = try Self.decodeVenderExtensions(from: decoder) + + self = schema.with(vendorExtensions: extensions) return } @@ -2132,29 +2144,30 @@ extension JSONSchema: Decodable { self.warnings = _warnings - // Ad-hoc vendor extension support since JSONSchema does coding keys differently. - let extensions: [String: AnyCodable] + // Ad-hoc vendor extension support since JSONSchema does coding keys differently. + let extensions = try Self.decodeVenderExtensions(from: decoder) + self.value = value.with(vendorExtensions: extensions) + } + + private static func decodeVenderExtensions(from decoder: Decoder) throws -> [String: AnyCodable] { guard VendorExtensionsConfiguration.isEnabled else { - self.value = value - return + return [:] } - + let decoded = try AnyCodable(from: decoder).value - + guard (decoded as? [Any]) == nil else { throw VendorExtensionDecodingError.selfIsArrayNotDict } - + guard let decodedAny = decoded as? [String: Any] else { throw VendorExtensionDecodingError.foundNonStringKeys } - - extensions = decodedAny + + return decodedAny .filter { $0.key.lowercased().starts(with: "x-") } .mapValues(AnyCodable.init) - - self.value = value.with(vendorExtensions: extensions) } private static func decodeTypes(from container: KeyedDecodingContainer) throws -> [JSONType] { diff --git a/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift b/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift index b69e4b020..2689b3561 100644 --- a/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift +++ b/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift @@ -1918,6 +1918,57 @@ extension SchemaObjectTests { JSONSchema.fragment(.init(examples: ["hello"])).with(vendorExtensions: ["x-hello": "hello"]) ) } + + func test_decodeAnyOfWithVendorExtension() throws { + let extensionSchema = """ + { + "anyOf" : [ + { "type": "string" }, + { "type": "number" } + ], + "x-hello" : "hello" + } + """.data(using: .utf8)! + + XCTAssertEqual( + try orderUnstableDecode(JSONSchema.self, from: extensionSchema), + JSONSchema.any(of: [JSONSchema.string, JSONSchema.number]).with(vendorExtensions: ["x-hello": "hello"]) + ) + } + + func test_decodeAllOfWithVendorExtension() throws { + let extensionSchema = """ + { + "allOf" : [ + { "type": "string" }, + { "type": "number" } + ], + "x-hello" : "hello" + } + """.data(using: .utf8)! + + XCTAssertEqual( + try orderUnstableDecode(JSONSchema.self, from: extensionSchema), + JSONSchema.all(of: [JSONSchema.string, JSONSchema.number]).with(vendorExtensions: ["x-hello": "hello"]) + ) + } + + func test_decodeOneOfWithVendorExtension() throws { + let extensionSchema = """ + { + "oneOf" : [ + { "type": "string" }, + { "type": "number" } + ], + "x-hello" : "hello" + } + """.data(using: .utf8)! + + XCTAssertEqual( + try orderUnstableDecode(JSONSchema.self, from: extensionSchema), + JSONSchema.one(of: [JSONSchema.string, JSONSchema.number]).with(vendorExtensions: ["x-hello": "hello"]) + ) + } func test_encodeExamplesVendorExtension() throws { let fragment = JSONSchema.fragment(.init(examples: ["hello"])).with(vendorExtensions: ["x-hello": "hello"])