Skip to content

Commit 2a1fb04

Browse files
committed
Lots of breaking changes. Reworking JSONReference to be _a little more_ user friendly.
1 parent eede562 commit 2a1fb04

File tree

7 files changed

+165
-41
lines changed

7 files changed

+165
-41
lines changed

Sources/OpenAPIKit/Content.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ extension OpenAPI.Content {
3838

3939
extension OpenAPI.Content {
4040
public struct Encoding: Codable, Equatable {
41-
public let contentType: String?
41+
public let contentType: OpenAPI.ContentType?
4242
public let headers: OpenAPI.Header.Map?
4343
// public let style: String?
4444
// public let explode: Bool (defaults for this need to be tied to style making style a good candidate for abstraction)
4545
public let allowReserved: Bool
4646

47-
public init(contentType: String? = nil,
47+
public init(contentType: OpenAPI.ContentType? = nil,
4848
headers: OpenAPI.Header.Map? = nil,
4949
allowReserved: Bool = false) {
5050
self.contentType = contentType

Sources/OpenAPIKit/JSON Utility/JSONReference.swift

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,37 @@ public struct RefDict<Root: ReferenceRoot, Name: RefName, RefType: Equatable & C
4242
/// A Reference is the combination of
4343
/// a path to a reference dictionary
4444
/// and a selector that the dictionary is keyed off of.
45-
public enum JSONReference<Root: ReferenceRoot, RefType: Equatable>: Equatable {
45+
public enum JSONReference<Root: ReferenceRoot, RefType: Equatable>: Equatable, CustomStringConvertible {
4646

47-
case node(InternalReference)
48-
case file(FileReference)
47+
case `internal`(Local)
48+
case external(FileReference, Local?)
49+
50+
public static func external(_ ref: FileReference) -> JSONReference {
51+
let parts = ref.split(separator: "#")
52+
53+
return .external(String(parts[0]), parts.count > 1 ? .unsafe("#" + String(parts[1])) : nil)
54+
}
4955

5056
public typealias FileReference = String
5157

52-
public struct InternalReference: Equatable {
58+
public enum Local: Equatable, CustomStringConvertible {
59+
case node(InternalReference)
60+
case unsafe(String)
61+
62+
public var description: String {
63+
switch self {
64+
case .node(let reference):
65+
return reference.description
66+
case .unsafe(let string):
67+
guard string.starts(with: "#") else {
68+
return "#/" + string
69+
}
70+
return string
71+
}
72+
}
73+
}
74+
75+
public struct InternalReference: Equatable, CustomStringConvertible {
5376
public let path: PartialKeyPath<Root>
5477
public let selector: String
5578

@@ -64,6 +87,19 @@ public enum JSONReference<Root: ReferenceRoot, RefType: Equatable>: Equatable {
6487
self.path = type
6588
self.selector = selector
6689
}
90+
91+
public var description: String {
92+
return "#/\(Root.refName)/\(refName)/\(selector)"
93+
}
94+
}
95+
96+
public var description: String {
97+
switch self {
98+
case .external(let file, let path):
99+
return path.map { file + $0.description } ?? file
100+
case .internal(let reference):
101+
return reference.description
102+
}
67103
}
68104
}
69105

@@ -79,16 +115,7 @@ extension JSONReference: Encodable {
79115
public func encode(to encoder: Encoder) throws {
80116
var container = encoder.container(keyedBy: CodingKeys.self)
81117

82-
let referenceString: String = {
83-
switch self {
84-
case .file(let reference):
85-
return reference
86-
case .node(let reference):
87-
return "#/\(Root.refName)/\(reference.refName)/\(reference.selector)"
88-
}
89-
}()
90-
91-
try container.encode(referenceString, forKey: .ref)
118+
try container.encode(description, forKey: .ref)
92119
}
93120
}
94121

@@ -99,10 +126,10 @@ extension JSONReference: Decodable {
99126
let referenceString = try container.decode(String.self, forKey: .ref)
100127

101128
if referenceString.first == "#" {
102-
// TODO: parse local ref
103-
fatalError("not implemented")
129+
// TODO: try to parse ref to components
130+
self = .internal(.unsafe(referenceString))
104131
} else {
105-
self = .file(referenceString)
132+
self = .external(referenceString)
106133
}
107134
}
108135
}

Tests/OpenAPIKitTests/ContentTests.swift

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,54 @@ import OpenAPIKit
1111

1212
final class ContentTests: XCTestCase {
1313
func test_init() {
14-
let _ = OpenAPI.Content(schema: .init(.file("hello.json#/world")))
14+
let _ = OpenAPI.Content(schema: .init(.external("hello.json#/world")))
1515

1616
let _ = OpenAPI.Content(schema: .init(.string))
17+
18+
let _ = OpenAPI.Content(schema: .init(.string),
19+
example: "hello",
20+
encoding: [
21+
"json": .init()
22+
])
23+
24+
let _ = OpenAPI.Content(schema: .init(.string),
25+
example: nil,
26+
encoding: [
27+
"hello": .init(contentType: .json,
28+
headers: [
29+
"world": .init(OpenAPI.Header(schemaOrContent: .init(.init(.string))))
30+
],
31+
allowReserved: true)
32+
])
1733
}
1834

1935
func test_contentMap() {
2036
let _: OpenAPI.Content.Map = [
2137
.json: .init(schema: .init(.string)),
22-
.xml: .init(schema: .init(.file("hello.json#/world"))),
38+
.xml: .init(schema: .init(.external("hello.json#/world"))),
2339
.form: .init(schema: .init(.object(properties: ["hello": .string])))
2440
]
2541
}
42+
43+
func test_encodingInit() {
44+
let _ = OpenAPI.Content.Encoding()
45+
46+
let _ = OpenAPI.Content.Encoding(contentType: .json)
47+
48+
let _ = OpenAPI.Content.Encoding(headers: ["special": .b(.external("hello.yml"))])
49+
50+
let _ = OpenAPI.Content.Encoding(allowReserved: true)
51+
52+
let _ = OpenAPI.Content.Encoding(contentType: .form,
53+
headers: ["special": .b(.external("hello.yml"))], allowReserved: true)
54+
}
2655
}
2756

2857
// MARK: - Codable
2958
@available(OSX 10.13, *)
3059
extension ContentTests {
3160
func test_referenceContent_encode() {
32-
let content = OpenAPI.Content(schema: .init(.file("hello.json#/world")))
61+
let content = OpenAPI.Content(schema: .init(.external("hello.json#/world")))
3362
let encodedContent = try! testStringFromEncoding(of: content)
3463

3564
XCTAssertEqual(encodedContent,
@@ -54,7 +83,7 @@ extension ContentTests {
5483
""".data(using: .utf8)!
5584
let content = try! testDecoder.decode(OpenAPI.Content.self, from: contentData)
5685

57-
XCTAssertEqual(content, OpenAPI.Content(schema: .init(.file("hello.json#/world"))))
86+
XCTAssertEqual(content, OpenAPI.Content(schema: .init(.external("hello.json#/world"))))
5887
}
5988

6089
func test_schemaContent_encode() {
@@ -86,3 +115,9 @@ extension ContentTests {
86115
XCTAssertEqual(content, OpenAPI.Content(schema: .init(.string(required: false))))
87116
}
88117
}
118+
119+
// MARK: Content.Encoding
120+
@available(OSX 10.13, *)
121+
extension ContentTests {
122+
// TODO: write tests
123+
}

Tests/OpenAPIKitTests/JSON Utility/JSONReferenceTests.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,68 @@ import Foundation
99
import XCTest
1010
import OpenAPIKit
1111

12+
fileprivate struct Root: ReferenceRoot {
13+
static var refName: String { return "root" }
14+
15+
struct Thing: ReferenceDict {
16+
typealias Value = JSONSchema
17+
18+
static var refName: String { return "thing" }
19+
}
20+
21+
let thing: Thing
22+
}
23+
24+
// MARK: - JSONReference
1225
final class JSONReferenceTests: XCTestCase {
26+
func test_initialization() {
27+
let _ = JSONReference<Root, JSONSchema>.internal(.unsafe("#/hello"))
28+
29+
let _ = JSONReference<Root, JSONSchema>.internal(.node(.init(type: \.thing, selector: "hello")))
30+
31+
let _ = JSONReference<Root, JSONSchema>.external("hello.yml", nil)
32+
33+
let _ = JSONReference<Root, JSONSchema>.external("hello.yml", .unsafe("#/hello"))
34+
35+
let _ = JSONReference<Root, JSONSchema>.external("hello.yml", .unsafe("hello"))
36+
37+
let _ = JSONReference<Root, JSONSchema>.external("hello.yml", .node(.init(type: \.thing, selector: "hello")))
38+
39+
let ref = JSONReference<Root, JSONSchema>.external("hello.yml#/hello")
40+
41+
XCTAssertEqual(ref, .external("hello.yml", .unsafe("#/hello")))
42+
}
43+
44+
func test_descriptions() {
45+
XCTAssertEqual(JSONReference<Root, JSONSchema>.internal(.unsafe("#/hello")).description, "#/hello")
46+
47+
XCTAssertEqual(JSONReference<Root, JSONSchema>.internal(.unsafe("hello")).description, "#/hello")
48+
49+
XCTAssertEqual(JSONReference<Root, JSONSchema>.internal(.node(.init(type: \.thing, selector: "hello"))).description, "#/root/thing/hello")
50+
51+
XCTAssertEqual(JSONReference<Root, JSONSchema>.external("hello.yml", nil).description, "hello.yml")
52+
53+
XCTAssertEqual(JSONReference<Root, JSONSchema>.external("hello.yml", .unsafe("#/hello")).description, "hello.yml#/hello")
54+
55+
XCTAssertEqual(JSONReference<Root, JSONSchema>.external("hello.yml", .unsafe("hello")).description, "hello.yml#/hello")
56+
57+
XCTAssertEqual(JSONReference<Root, JSONSchema>.external("hello.yml", .node(.init(type: \.thing, selector: "hello"))).description, "hello.yml#/root/thing/hello")
58+
59+
XCTAssertEqual(JSONReference<Root, JSONSchema>.external("hello.yml#/hello").description, "hello.yml#/hello")
60+
}
61+
}
62+
63+
// MARK: Codable
64+
extension JSONReferenceTests {
65+
// TODO: write more tests
66+
}
67+
68+
// MARK: - RefDict
69+
extension JSONReferenceTests {
1370
// TODO: write tests
1471
}
72+
73+
// MARK: Codable
74+
extension JSONReferenceTests {
75+
// TODO: write more tests
76+
}

Tests/OpenAPIKitTests/RequestTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ final class RequestTests: XCTestCase {
3737
])
3838

3939
let _ = OpenAPI.Request(content: [
40-
.json: .init(schema: .init(.file("hello.json#/world")))
40+
.json: .init(schema: .init(.external("hello.json#/world")))
4141
])
4242
}
4343
}
@@ -62,7 +62,7 @@ extension RequestTests {
6262

6363
func test_onlyReferenceContent_encode() {
6464
let request = OpenAPI.Request(content: [
65-
.json: .init(schema: .init(.file("hello.json#/world")))
65+
.json: .init(schema: .init(.external("hello.json#/world")))
6666
])
6767
let encodedString = try! testStringFromEncoding(of: request)
6868

@@ -86,7 +86,7 @@ extension RequestTests {
8686
let request = try! testDecoder.decode(OpenAPI.Request.self, from: requestData)
8787

8888
XCTAssertEqual(request, OpenAPI.Request(content: [
89-
.json : .init(schema: .init(.file("hello.json#/world")))
89+
.json : .init(schema: .init(.external("hello.json#/world")))
9090
]))
9191
}
9292

Tests/OpenAPIKitTests/ResponseTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ final class ResponseTests: XCTestCase {
1717
XCTAssertNil(r1.headers)
1818
XCTAssertEqual(r1.content, [:])
1919

20-
let content = OpenAPI.Content(schema: .init(JSONReference<OpenAPI.Components, JSONSchema>.file("hello.yml")))
20+
let content = OpenAPI.Content(schema: .init(JSONReference<OpenAPI.Components, JSONSchema>.external("hello.yml")))
2121
let header = OpenAPI.Header(schemaOrContent: .init(.init(.string)))
2222
let r2 = OpenAPI.Response(description: "",
2323
headers: ["hello": .init(header)],

0 commit comments

Comments
 (0)