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
6 changes: 2 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ jobs:
fail-fast: false
matrix:
image:
- swift:5.8-focal
- swift:5.8-jammy
- swift:5.9-focal
- swift:5.9-jammy
- swift:5.10-focal
- swift:5.10-jammy
- swift:6.0-focal
Expand All @@ -25,6 +21,8 @@ jobs:
- swift:6.1-focal
- swift:6.1-jammy
- swift:6.1-noble
- swift:6.2-jammy
- swift:6.2-noble
- swiftlang/swift:nightly-focal
- swiftlang/swift:nightly-jammy
container: ${{ matrix.image }}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![sswg:sandbox|94x20](https://img.shields.io/badge/sswg-sandbox-lightgrey.svg)](https://github.com/swift-server/sswg/blob/master/process/incubation.md#sandbox-level) [![Swift 5.8+](http://img.shields.io/badge/Swift-5.8+-blue.svg)](https://swift.org)
[![sswg:sandbox|94x20](https://img.shields.io/badge/sswg-sandbox-lightgrey.svg)](https://github.com/swift-server/sswg/blob/master/process/incubation.md#sandbox-level) [![Swift 5.10+](http://img.shields.io/badge/Swift-5.10+-blue.svg)](https://swift.org)

[![MIT license](http://img.shields.io/badge/license-MIT-lightgrey.svg)](http://opensource.org/licenses/MIT) ![Tests](https://github.com/mattpolzin/OpenAPIKit/workflows/Tests/badge.svg)

Expand Down
89 changes: 84 additions & 5 deletions Sources/OpenAPIKit/Document/Document.swift
Original file line number Diff line number Diff line change
Expand Up @@ -430,23 +430,28 @@ extension OpenAPI.Document {
/// specification releases a new patch version, OpenAPIKit will see a patch version release
/// explicitly supports decoding documents of that new patch version before said version will
/// succesfully decode as the `v3_1_x` case.
public enum Version: RawRepresentable, Equatable, Codable, Sendable {
public enum Version: RawRepresentable, Equatable, Comparable, Codable, Sendable {
case v3_1_0
case v3_1_1
case v3_1_2
case v3_1_x(x: Int)

case v3_2_0
case v3_2_x(x: Int)

public init?(rawValue: String) {
switch rawValue {
case "3.1.0": self = .v3_1_0
case "3.1.1": self = .v3_1_1
case "3.1.2": self = .v3_1_2
case "3.2.0": self = .v3_2_0
default:
let components = rawValue.split(separator: ".")
guard components.count == 3 else {
return nil
}
guard components[0] == "3", components[1] == "1" else {
let minorVersion = components[1]
guard components[0] == "3", (minorVersion == "1" || minorVersion == "2") else {
return nil
}
guard let patchVersion = Int(components[2], radix: 10) else {
Expand All @@ -455,10 +460,17 @@ extension OpenAPI.Document {
// to support newer versions released in the future without a breaking
// change to the enumeration, bump the upper limit here to e.g. 2 or 3
// or 6:
guard patchVersion > 1 && patchVersion <= 2 else {
return nil
if minorVersion == "2" {
guard patchVersion > 0 && patchVersion <= 0 else {
return nil
}
self = .v3_2_x(x: patchVersion)
} else {
guard patchVersion > 2 && patchVersion <= 2 else {
return nil
}
self = .v3_1_x(x: patchVersion)
}
self = .v3_1_x(x: patchVersion)
}
}

Expand All @@ -468,6 +480,73 @@ extension OpenAPI.Document {
case .v3_1_1: return "3.1.1"
case .v3_1_2: return "3.1.2"
case .v3_1_x(x: let x): return "3.1.\(x)"

case .v3_2_0: return "3.2.0"
case .v3_2_x(x: let x): return "3.2.\(x)"
}
}

public static func < (lhs: Self, rhs: Self) -> Bool {
switch lhs {
case .v3_1_0:
switch rhs {
case .v3_1_0: false
case .v3_1_1: true
case .v3_1_2: true
case .v3_1_x(x: let x): 0 < x
case .v3_2_0: true
case .v3_2_x(x: _): true
}

case .v3_1_1:
switch rhs {
case .v3_1_0: false
case .v3_1_1: false
case .v3_1_2: true
case .v3_1_x(x: let y): 1 < y
case .v3_2_0: true
case .v3_2_x(x: _): true
}

case .v3_1_2:
switch rhs {
case .v3_1_0: false
case .v3_1_1: false
case .v3_1_2: false
case .v3_1_x(x: let y): 2 < y
case .v3_2_0: true
case .v3_2_x(x: _): true
}

case .v3_1_x(x: let x):
switch rhs {
case .v3_1_0: x < 0
case .v3_1_1: x < 1
case .v3_1_2: x < 2
case .v3_1_x(x: let y): x < y
case .v3_2_0: true
case .v3_2_x(x: _): true
}

case .v3_2_0:
switch rhs {
case .v3_1_0: false
case .v3_1_1: false
case .v3_1_2: false
case .v3_1_x(x: _): false
case .v3_2_0: false
case .v3_2_x(x: let y): 0 < y
}

case .v3_2_x(x: let x):
switch rhs {
case .v3_1_0: false
case .v3_1_1: false
case .v3_1_2: false
case .v3_1_x(x: _): false
case .v3_2_0: x < 0
case .v3_2_x(x: let y): x < y
}
}
}
}
Expand Down
55 changes: 55 additions & 0 deletions Sources/OpenAPIKit/OpenAPIConditionalWarnings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
public protocol Condition: Equatable, Sendable {
/// Given an entire OpenAPI Document, determine the applicability of the
/// condition.
func applies(to: OpenAPI.Document) -> Bool
}

public protocol HasConditionalWarnings {
/// Warnings that only apply if the paired condition is met.
///
/// Among other things, this allows OpenAPIKit to generate a warning in
/// some nested type that only applies if the OpenAPI Standards version of
/// the document is less than a certain version.
var conditionalWarnings: [(any Condition, OpenAPI.Warning)] { get }
}

extension HasConditionalWarnings {
public func applicableConditionalWarnings(for subject: OpenAPI.Document) -> [OpenAPI.Warning] {
conditionalWarnings.compactMap { (condition, warning) in
guard condition.applies(to: subject) else { return nil }

return warning
}
}
}

internal struct DocumentVersionCondition: Sendable, Condition {
enum Comparator: Sendable {
case lessThan
case equal
case greaterThan
}

let version: OpenAPI.Document.Version
let comparator: Comparator

func applies(to document: OpenAPI.Document) -> Bool {
switch comparator {
case .lessThan: document.openAPIVersion < version

case .equal: document.openAPIVersion == version

case .greaterThan: document.openAPIVersion > version
}
}
}

internal extension OpenAPI.Document {
struct ConditionalWarnings {
static func version(lessThan version: OpenAPI.Document.Version, doesNotSupport subject: String) -> (any Condition, OpenAPI.Warning) {
let warning = OpenAPI.Warning.message("\(subject) is only supported for OpenAPI document versions \(version.rawValue) and later")

return (DocumentVersionCondition(version: version, comparator: .lessThan), warning)
}
}
}
2 changes: 1 addition & 1 deletion Sources/OpenAPIKit/Schema Object/JSONSchemaContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,7 @@ extension JSONSchema.CoreContext: Decodable {
.underlyingError(
GenericError(
subjectName: "OpenAPI Schema",
details: "Found 'nullable' property. This property is not supported by OpenAPI v3.1.x. OpenAPIKit has translated it into 'type: [\"null\", ...]'.",
details: "Found 'nullable' property. This property is not supported by OpenAPI v3.1.x. OpenAPIKit has translated it into 'type: [\"null\", ...]'",
codingPath: container.codingPath
)
)
Expand Down
Loading