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
18 changes: 9 additions & 9 deletions Sources/OpenAPIKit/Schema Object/DereferencedJSONSchema.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public enum DereferencedJSONSchema: Equatable, JSONSchemaContext {
public typealias IntegerContext = JSONSchema.IntegerContext
public typealias StringContext = JSONSchema.StringContext

case null
case null(CoreContext<JSONTypeFormat.AnyFormat>)
case boolean(CoreContext<JSONTypeFormat.BooleanFormat>)
case number(CoreContext<JSONTypeFormat.NumberFormat>, NumericContext)
case integer(CoreContext<JSONTypeFormat.IntegerFormat>, IntegerContext)
Expand All @@ -43,8 +43,8 @@ public enum DereferencedJSONSchema: Equatable, JSONSchemaContext {
/// not true.
public var jsonSchema: JSONSchema {
switch self {
case .null:
return .null
case .null(let coreContext):
return .null(coreContext)
case .boolean(let context):
return .boolean(context)
case .object(let coreContext, let objectContext):
Expand Down Expand Up @@ -72,8 +72,8 @@ public enum DereferencedJSONSchema: Equatable, JSONSchemaContext {

func optionalSchemaObject() -> DereferencedJSONSchema {
switch self {
case .null:
return .null
case .null(let coreContext):
return .null(coreContext.optionalContext())
case .boolean(let context):
return .boolean(context.optionalContext())
case .object(let contextA, let contextB):
Expand Down Expand Up @@ -146,8 +146,8 @@ public enum DereferencedJSONSchema: Equatable, JSONSchemaContext {
/// Returns a version of this `DereferencedJSONSchema` that has the given description.
public func with(description: String) -> DereferencedJSONSchema {
switch self {
case .null:
return .null
case .null(let coreContext):
return .null(coreContext.with(description: description))
case .boolean(let context):
return .boolean(context.with(description: description))
case .object(let coreContext, let objectContext):
Expand Down Expand Up @@ -391,8 +391,8 @@ extension JSONSchema: LocallyDereferenceable {
dereferencedFromComponentNamed name: String?
) throws -> DereferencedJSONSchema {
switch value {
case .null:
return .null
case .null(let coreContext):
return .null(coreContext)
case .reference(let reference, let context):
var dereferenced = try reference._dereferenced(in: components, following: references, dereferencedFromComponentNamed: nil)
if !context.required {
Expand Down
8 changes: 4 additions & 4 deletions Sources/OpenAPIKit/Schema Object/JSONSchema+Combining.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ internal struct FragmentCombiner {
} else {
// the only case where starting with a fragment breaks down is when you actually
// should end up with plain old `.null`
guard fragment != .null else {
self.combinedFragment = .null
if case let .null(coreContext) = fragment.value {
self.combinedFragment = .null(coreContext)
return
}
// combination can turn `required: false` into `required: true`
Expand Down Expand Up @@ -154,8 +154,8 @@ internal struct FragmentCombiner {
}
try combine(component)

case (.null, .null):
self.combinedFragment = .null
case (.null(let leftCoreContext), .null(let rightCoreContext)):
self.combinedFragment = .null(try leftCoreContext.combined(with: rightCoreContext))

case (.fragment(let leftCoreContext), .fragment(let rightCoreContext)):
self.combinedFragment = .fragment(try leftCoreContext.combined(with: rightCoreContext))
Expand Down
149 changes: 73 additions & 76 deletions Sources/OpenAPIKit/Schema Object/JSONSchema.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ public struct JSONSchema: JSONSchemaContext, HasWarnings, VendorExtendable {

/// The null type, which replaces the functionality of the `nullable` property from
/// previous versions of the OpenAPI specification.
public static let null: Self = .init(schema: .null)
public static func null(_ core: CoreContext<JSONTypeFormat.AnyFormat> = .init(nullable: true)) -> Self {
.init(schema: .null(core.nullableContext()))
}
public static func boolean(_ core: CoreContext<JSONTypeFormat.BooleanFormat>) -> Self {
.init(schema: .boolean(core))
}
Expand Down Expand Up @@ -79,7 +81,7 @@ public struct JSONSchema: JSONSchemaContext, HasWarnings, VendorExtendable {
public enum Schema: Equatable {
/// The null type, which replaces the functionality of the `nullable` property from
/// previous versions of the OpenAPI specification.
case null
case null(CoreContext<JSONTypeFormat.AnyFormat>)
case boolean(CoreContext<JSONTypeFormat.BooleanFormat>)
case number(CoreContext<JSONTypeFormat.NumberFormat>, NumericContext)
case integer(CoreContext<JSONTypeFormat.IntegerFormat>, IntegerContext)
Expand Down Expand Up @@ -160,53 +162,19 @@ public struct JSONSchema: JSONSchemaContext, HasWarnings, VendorExtendable {

// See `JSONSchemaContext`
public var required: Bool {
switch value {
case .null:
#warning("TODO: not sure about this -- maybe null type should get a context still")
return false
case .boolean(let context as JSONSchemaContext),
.object(let context as JSONSchemaContext, _),
.array(let context as JSONSchemaContext, _),
.number(let context as JSONSchemaContext, _),
.integer(let context as JSONSchemaContext, _),
.string(let context as JSONSchemaContext, _),
.fragment(let context as JSONSchemaContext),
.all(of: _, core: let context as JSONSchemaContext),
.one(of: _, core: let context as JSONSchemaContext),
.any(of: _, core: let context as JSONSchemaContext),
.not(_, core: let context as JSONSchemaContext):
return context.required
case .reference(_, let context):
return context.required
}
return coreContext?.required ?? true
}

// See `JSONSchemaContext`
public var description: String? {
switch value {
case .boolean(let context as JSONSchemaContext),
.object(let context as JSONSchemaContext, _),
.array(let context as JSONSchemaContext, _),
.number(let context as JSONSchemaContext, _),
.integer(let context as JSONSchemaContext, _),
.string(let context as JSONSchemaContext, _),
.fragment(let context as JSONSchemaContext),
.all(of: _, core: let context as JSONSchemaContext),
.one(of: _, core: let context as JSONSchemaContext),
.any(of: _, core: let context as JSONSchemaContext),
.not(_, core: let context as JSONSchemaContext):
return context.description
case .reference(_, let referenceContext):
return referenceContext.description
case .null:
return nil
}
return coreContext?.description
}

// See `JSONSchemaContext`
public var discriminator: OpenAPI.Discriminator? {
switch value {
case .boolean(let context as JSONSchemaContext),
case .null(let context as JSONSchemaContext),
.boolean(let context as JSONSchemaContext),
.object(let context as JSONSchemaContext, _),
.array(let context as JSONSchemaContext, _),
.number(let context as JSONSchemaContext, _),
Expand All @@ -218,14 +186,13 @@ public struct JSONSchema: JSONSchemaContext, HasWarnings, VendorExtendable {
.any(of: _, core: let context as JSONSchemaContext),
.not(_, core: let context as JSONSchemaContext):
return context.discriminator
case .reference, .null:
case .reference:
return nil
}
}

// See `JSONSchemaContext`
public var nullable: Bool {
guard self != .null else { return true }
return coreContext?.nullable ?? false
}

Expand Down Expand Up @@ -365,7 +332,8 @@ extension JSONSchema {
///
public var coreContext: JSONSchemaContext? {
switch value {
case .boolean(let context as JSONSchemaContext),
case .null(let context as JSONSchemaContext),
.boolean(let context as JSONSchemaContext),
.object(let context as JSONSchemaContext, _),
.array(let context as JSONSchemaContext, _),
.number(let context as JSONSchemaContext, _),
Expand All @@ -375,12 +343,9 @@ extension JSONSchema {
.all(of: _, core: let context as JSONSchemaContext),
.one(of: _, core: let context as JSONSchemaContext),
.any(of: _, core: let context as JSONSchemaContext),
.not(_, core: let context as JSONSchemaContext):
return context
case .reference(_, let context as JSONSchemaContext):
.not(_, core: let context as JSONSchemaContext),
.reference(_, let context as JSONSchemaContext):
return context
case .null:
return nil
}
}

Expand Down Expand Up @@ -516,8 +481,12 @@ extension JSONSchema {
schema: .reference(reference, context.optionalContext()),
vendorExtensions: vendorExtensions
)
case .null:
return self
case .null(let context):
return .init(
warnings: warnings,
schema: .null(context.optionalContext()),
vendorExtensions: vendorExtensions
)
}
}

Expand Down Expand Up @@ -596,8 +565,12 @@ extension JSONSchema {
schema: .reference(reference, context.requiredContext()),
vendorExtensions: vendorExtensions
)
case .null:
return self
case .null(let context):
return .init(
warnings: warnings,
schema: .null(context.requiredContext()),
vendorExtensions: vendorExtensions
)
}
}

Expand Down Expand Up @@ -745,8 +718,18 @@ extension JSONSchema {
schema: .not(schema, core: core.with(allowedValues: allowedValues)),
vendorExtensions: vendorExtensions
)
case .reference, .null:
return self
case .reference(let schema, let core):
return .init(
warnings: warnings,
schema: .reference(schema, core.with(allowedValues: allowedValues)),
vendorExtensions: vendorExtensions
)
case .null(let core):
return .init(
warnings: warnings,
schema: .null(core.with(allowedValues: allowedValues)),
vendorExtensions: vendorExtensions
)
}
}

Expand Down Expand Up @@ -819,8 +802,18 @@ extension JSONSchema {
schema: .not(schema, core: core.with(defaultValue: defaultValue)),
vendorExtensions: vendorExtensions
)
case .reference, .null:
return self
case .reference(let schema, let core):
return .init(
warnings: warnings,
schema: .reference(schema, core.with(defaultValue: defaultValue)),
vendorExtensions: vendorExtensions
)
case .null(let core):
return .init(
warnings: warnings,
schema: .null(core.with(defaultValue: defaultValue)),
vendorExtensions: vendorExtensions
)
}
}

Expand Down Expand Up @@ -900,8 +893,18 @@ extension JSONSchema {
schema: .not(schema, core: core.with(examples: examples)),
vendorExtensions: vendorExtensions
)
case .reference, .null:
throw Self.Error.exampleNotSupported
case .reference(let schema, let core):
return .init(
warnings: warnings,
schema: .reference(schema, core.with(examples: examples)),
vendorExtensions: vendorExtensions
)
case .null(let core):
return .init(
warnings: warnings,
schema: .null(core.with(examples: examples)),
vendorExtensions: vendorExtensions
)
}
}

Expand Down Expand Up @@ -1054,21 +1057,12 @@ extension JSONSchema {
schema: .reference(ref, referenceContext.with(description: description)),
vendorExtensions: vendorExtensions
)
case .null:
return self
}
}
}

extension JSONSchema {
internal enum Error: Swift.Error, CustomStringConvertible, Equatable {
case exampleNotSupported

public var description: String {
switch self {
case .exampleNotSupported:
return "examples not supported for `.allOf`, `.oneOf`, `.anyOf`, `.not`, `.null` or for JSON references ($ref)."
}
case .null(let referenceContext):
return .init(
warnings: warnings,
schema: .null(referenceContext.with(description: description)),
vendorExtensions: vendorExtensions
)
}
}
}
Expand Down Expand Up @@ -1703,9 +1697,10 @@ extension JSONSchema {
public static func reference(
_ reference: JSONReference<JSONSchema>,
required: Bool = true,
title: String? = nil,
description: String? = nil
) -> JSONSchema {
return .reference(reference, .init(required: required, description: description))
return .reference(reference, .init(required: required, title: title, description: description))
}
}

Expand Down Expand Up @@ -1758,9 +1753,10 @@ extension JSONSchema: Encodable {

public func encode(to encoder: Encoder) throws {
switch value {
case .null:
case .null(let coreContext):
var container = encoder.container(keyedBy: NullCodingKeys.self)
try container.encode(JSONType.null.rawValue, forKey: .type)
try coreContext.encode(to: encoder)

case .boolean(let context):
try context.encode(to: encoder)
Expand Down Expand Up @@ -1925,7 +1921,8 @@ extension JSONSchema: Decodable {
}

if typeHint == .null {
value = .null
let coreContext = try CoreContext<JSONTypeFormat.AnyFormat>(from: decoder)
value = .null(coreContext)

} else if typeHint == .integer || typeHint == .number || (typeHint == nil && !numericOrIntegerContainer.allKeys.isEmpty) {
if typeHint == .integer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ final class DereferencedSchemaObjectTests: XCTestCase {
XCTAssertEqual(t20, .all(of: [.string(.init(), .init())], core: .init(discriminator: .init(propertyName: "test"))))
XCTAssertEqual(t20?.discriminator, .init(propertyName: "test"))

let t21 = JSONSchema.null.dereferenced()
XCTAssertEqual(t21, .null)
let t21 = JSONSchema.null().dereferenced()
XCTAssertEqual(t21, .null(.init(nullable: true)))

// bonus tests around simplifying:
let t22 = try JSONSchema.all(of: []).dereferenced()?.simplified()
Expand Down Expand Up @@ -259,8 +259,8 @@ final class DereferencedSchemaObjectTests: XCTestCase {
XCTAssertEqual(t23, .string(.init(discriminator: .init(propertyName: "test")), .init()))
XCTAssertEqual(t23.discriminator, .init(propertyName: "test"))

let t24 = try JSONSchema.null.dereferenced(in: components)
XCTAssertEqual(t24, .null)
let t24 = try JSONSchema.null().dereferenced(in: components)
XCTAssertEqual(t24, .null(.init(nullable: true)))
}

func test_optionalReferenceMissing() {
Expand Down Expand Up @@ -514,7 +514,7 @@ final class DereferencedSchemaObjectTests: XCTestCase {
}

func test_withDescription() throws {
let null = JSONSchema.null.dereferenced()!.with(description: "test")
let null = JSONSchema.null().dereferenced()!.with(description: "test")
let object = JSONSchema.object.dereferenced()!.with(description: "test")
let array = JSONSchema.array.dereferenced()!.with(description: "test")

Expand Down Expand Up @@ -542,7 +542,7 @@ final class DereferencedSchemaObjectTests: XCTestCase {
XCTAssertEqual(any.description, "test")
XCTAssertEqual(not.description, "test")

XCTAssertNil(null.description)
XCTAssertEqual(null.description, "test")
}

}
Loading