Skip to content

Commit

Permalink
Merge pull request #333 from mattpolzin/feature/331/meta-type-and-enc…
Browse files Browse the repository at this point in the history
…oding

Media Type and Encoding on JSONSchema
  • Loading branch information
mattpolzin authored Oct 31, 2023
2 parents 5a937cb + a05fd35 commit 437c26a
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 61 deletions.
82 changes: 82 additions & 0 deletions Sources/OpenAPIKit/Schema Object/JSONSchemaContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,54 @@ extension JSONSchema {
self._minProperties = minProperties
}
}

/// The context that only applies to `.string` schemas.
public struct StringContext: Equatable {
public let maxLength: Int?
let _minLength: Int?

public let contentMediaType: OpenAPI.ContentType?
public let contentEncoding: OpenAPI.ContentEncoding?

public var minLength: Int {
return _minLength ?? 0
}

/// Regular expression
public let pattern: String?

public init(
maxLength: Int? = nil,
minLength: Int? = nil,
pattern: String? = nil,
contentMediaType: OpenAPI.ContentType? = nil,
contentEncoding: OpenAPI.ContentEncoding? = nil
) {
self.maxLength = maxLength
self._minLength = minLength
self.pattern = pattern
self.contentMediaType = contentMediaType
self.contentEncoding = contentEncoding
}

// we make the following a static function so it doesn't muddy the namespace while auto-completing on a value.
public static func _minLength(_ context: StringContext) -> Int? {
return context._minLength
}
}
}

extension OpenAPI {
/// An encoding, as specified in RFC 2054, part 6.1 and RFC 4648.
public enum ContentEncoding: String, Codable {
case _7bit = "7bit"
case _8bit = "8bit"
case binary
case quoted_printable = "quoted-printable"
case base16
case base32
case base64
}
}

// MARK: - Codable
Expand Down Expand Up @@ -1068,3 +1116,37 @@ extension JSONSchema.ObjectContext: Decodable {
return properties
}
}

extension JSONSchema.StringContext {
public enum CodingKeys: String, CodingKey {
case maxLength
case minLength
case pattern
case contentMediaType
case contentEncoding
}
}

extension JSONSchema.StringContext: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encodeIfPresent(maxLength, forKey: .maxLength)
try container.encodeIfPresent(_minLength, forKey: .minLength)
try container.encodeIfPresent(pattern, forKey: .pattern)
try container.encodeIfPresent(contentMediaType, forKey: .contentMediaType)
try container.encodeIfPresent(contentEncoding, forKey: .contentEncoding)
}
}

extension JSONSchema.StringContext: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

maxLength = try container.decodeIfPresent(Int.self, forKey: .maxLength)
_minLength = try container.decodeIfPresent(Int.self, forKey: .minLength)
pattern = try container.decodeIfPresent(String.self, forKey: .pattern)
contentMediaType = try container.decodeIfPresent(OpenAPI.ContentType.self, forKey: .contentMediaType)
contentEncoding = try container.decodeIfPresent(OpenAPI.ContentEncoding.self, forKey: .contentEncoding)
}
}
1 change: 0 additions & 1 deletion Sources/OpenAPIKit/_CoreReExport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public extension OpenAPI.Response {

public extension JSONSchema {
typealias Permissions = OpenAPIKitCore.Shared.JSONSchemaPermissions
typealias StringContext = OpenAPIKitCore.Shared.StringContext
typealias ReferenceContext = OpenAPIKitCore.Shared.ReferenceContext
}

Expand Down
56 changes: 56 additions & 0 deletions Sources/OpenAPIKit30/Schema Object/JSONSchemaContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,34 @@ extension JSONSchema {
self._minProperties = minProperties
}
}

/// The context that only applies to `.string` schemas.
public struct StringContext: Equatable {
public let maxLength: Int?
let _minLength: Int?

public var minLength: Int {
return _minLength ?? 0
}

/// Regular expression
public let pattern: String?

public init(
maxLength: Int? = nil,
minLength: Int? = nil,
pattern: String? = nil
) {
self.maxLength = maxLength
self._minLength = minLength
self.pattern = pattern
}

// we make the following a static function so it doesn't muddy the namespace while auto-completing on a value.
public static func _minLength(_ context: StringContext) -> Int? {
return context._minLength
}
}
}

// MARK: - Codable
Expand Down Expand Up @@ -930,3 +958,31 @@ extension JSONSchema.ObjectContext: Decodable {
return properties
}
}

extension JSONSchema.StringContext {
public enum CodingKeys: String, CodingKey {
case maxLength
case minLength
case pattern
}
}

extension JSONSchema.StringContext: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encodeIfPresent(maxLength, forKey: .maxLength)
try container.encodeIfPresent(_minLength, forKey: .minLength)
try container.encodeIfPresent(pattern, forKey: .pattern)
}
}

extension JSONSchema.StringContext: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

maxLength = try container.decodeIfPresent(Int.self, forKey: .maxLength)
_minLength = try container.decodeIfPresent(Int.self, forKey: .minLength)
pattern = try container.decodeIfPresent(String.self, forKey: .pattern)
}
}
1 change: 0 additions & 1 deletion Sources/OpenAPIKit30/_CoreReExport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public extension OpenAPI.Response {

public extension JSONSchema {
typealias Permissions = OpenAPIKitCore.Shared.JSONSchemaPermissions
typealias StringContext = OpenAPIKitCore.Shared.StringContext
typealias ReferenceContext = OpenAPIKitCore.Shared.ReferenceContext
}

Expand Down
12 changes: 11 additions & 1 deletion Sources/OpenAPIKitCompat/Compat30To31.swift
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,16 @@ extension OpenAPIKit30.JSONSchema.ObjectContext: To31 {
}
}

extension OpenAPIKit30.JSONSchema.StringContext: To31 {
fileprivate func to31() -> OpenAPIKit.JSONSchema.StringContext {
OpenAPIKit.JSONSchema.StringContext(
maxLength: maxLength,
minLength: OpenAPIKit30.JSONSchema.StringContext._minLength(self),
pattern: pattern
)
}
}

extension OpenAPIKit30.JSONSchema: To31 {
fileprivate func to31() -> OpenAPIKit.JSONSchema {
let schema: OpenAPIKit.JSONSchema.Schema
Expand All @@ -563,7 +573,7 @@ extension OpenAPIKit30.JSONSchema: To31 {
case .integer(let core, let integral):
schema = .integer(core.to31(), integral.to31())
case .string(let core, let stringy):
schema = .string(core.to31(), stringy)
schema = .string(core.to31(), stringy.to31())
case .object(let core, let objective):
schema = .object(core.to31(), objective.to31())
case .array(let core, let listy):
Expand Down
57 changes: 0 additions & 57 deletions Sources/OpenAPIKitCore/Shared/JSONSchemaSimpleContexts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,6 @@
//

extension Shared {
/// The context that only applies to `.string` schemas.
public struct StringContext: Equatable {
public let maxLength: Int?
let _minLength: Int?

public var minLength: Int {
return _minLength ?? 0
}

/// Regular expression
public let pattern: String?

public init(
maxLength: Int? = nil,
minLength: Int? = nil,
pattern: String? = nil
) {
self.maxLength = maxLength
self._minLength = minLength
self.pattern = pattern
}

// we make the following a static function so it doesn't muddy the namespace while auto-completing on a value.
public static func _minLength(_ context: StringContext) -> Int? {
return context._minLength
}
}


/// The context that only applies to `.reference` schemas.
public struct ReferenceContext: Equatable {
public let required: Bool
Expand All @@ -52,31 +23,3 @@ extension Shared {
}
}
}

extension Shared.StringContext {
public enum CodingKeys: String, CodingKey {
case maxLength
case minLength
case pattern
}
}

extension Shared.StringContext: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encodeIfPresent(maxLength, forKey: .maxLength)
try container.encodeIfPresent(_minLength, forKey: .minLength)
try container.encodeIfPresent(pattern, forKey: .pattern)
}
}

extension Shared.StringContext: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

maxLength = try container.decodeIfPresent(Int.self, forKey: .maxLength)
_minLength = try container.decodeIfPresent(Int.self, forKey: .minLength)
pattern = try container.decodeIfPresent(String.self, forKey: .pattern)
}
}
11 changes: 10 additions & 1 deletion Tests/OpenAPIKitCompatTests/DocumentConversionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,7 @@ fileprivate func assertEqualNewToOld(_ newSchema: OpenAPIKit.JSONSchema, _ oldSc

case .string(let coreContext, let stringContext):
let newStringContext = try XCTUnwrap(newSchema.stringContext)
// TODO: compare string contexts
assertEqualNewToOld(newStringContext, stringContext)
try assertEqualNewToOld(newCoreContext, coreContext)

case .object(let coreContext, let objectContext):
Expand Down Expand Up @@ -1142,6 +1142,15 @@ fileprivate func assertEqualNewToOld(_ newCoreContext: OpenAPIKit.JSONSchemaCont
XCTAssertEqual(newCoreContext.deprecated, oldCoreContext.deprecated)
}

fileprivate func assertEqualNewToOld(_ newStringContext: OpenAPIKit.JSONSchema.StringContext, _ oldStringContext: OpenAPIKit30.JSONSchema.StringContext) {
XCTAssertEqual(newStringContext.pattern, oldStringContext.pattern)
XCTAssertEqual(newStringContext.maxLength, oldStringContext.maxLength)
XCTAssertEqual(newStringContext.minLength, oldStringContext.minLength)
XCTAssertEqual(OpenAPIKit.JSONSchema.StringContext._minLength(newStringContext), OpenAPIKit30.JSONSchema.StringContext._minLength(oldStringContext))
XCTAssertNil(newStringContext.contentEncoding)
XCTAssertNil(newStringContext.contentMediaType)
}

fileprivate func assertEqualNewToOld(_ newExample: OpenAPIKit.OpenAPI.Example, _ oldExample: OpenAPIKit30.OpenAPI.Example) {
XCTAssertEqual(newExample.summary, oldExample.summary)
XCTAssertEqual(newExample.description, oldExample.description)
Expand Down
Loading

0 comments on commit 437c26a

Please sign in to comment.