-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDocumentCodeGen.swift
152 lines (132 loc) · 5.7 KB
/
DocumentCodeGen.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import Foundation
protocol DocumentationGeneratable {
var documentationMarkup: String? { get }
}
extension DocumentationGeneratable {
/// For a doc string such as `"wow\nthis is documentation"` this will produce:
/// `"\(indentation)/// wow\n\(indentation)/// this is documentation\n"`.
/// Note the terminating newline.
///
/// Returns empty string `""` for `nil` `documentationMarkup`; no terminating newline.
func genDocumentationWithNewline(indentation: String) -> String {
let documentation = self.documentationMarkup.toDocCommentOrEmpty(indentation: indentation)
return documentation == "" ? "" : documentation + "\n"
}
}
// TODO: This is a bit too specific. Should maybe instead operate over arrays of possible
// doc strings.
protocol Deprecatable: DocumentationGeneratable {
var isDeprecated: Bool { get }
var deprecationReason: String? { get }
var description: String? { get }
}
extension Deprecatable {
var documentationMarkup: String? {
if !self.isDeprecated {
return self.description
}
switch (self.deprecationReason, self.description) {
case (nil, nil): return nil
case (.some(let deprecationReason), nil): return "DEPRECATED: \(deprecationReason)"
case (nil, let description): return description
case (.some(let deprecationReason), .some(let description)):
return "DEPRECATED: \(deprecationReason)\n\(description)"
}
}
}
extension AllTypes {
public func generateFileNameAndImports(configuration: Configuration.SchemaConfiguration) -> (fileName: String, fileText: String) {
let fileName = configuration.outputSchemaName + ".swift"
let imports =
"""
import Foundation
import AutoGraphQL
import JSONValueRX
"""
let fileText = imports + (
configuration.additionalImports.count > 0
? configuration.additionalImports.map { "import \($0)" }.joined(separator: "\n") + "\n"
: ""
)
return (fileName, fileText)
}
public func generateFragmentsStructs(indentation: String) throws -> String? {
guard self.fragmentIRs.count > 0 else {
return nil
}
let orderedFragmentDefinitions = self.fragmentIRs.sorted { left, right in left.key.value < right.key.value }
let fragmentDefinitionsCode = try orderedFragmentDefinitions.map {
try $0.value.generateCode(outputSchemaName: self.outputSchemaName, indentation: indentation)
}
.joined(separator: "\n\n")
return fragmentDefinitionsCode
}
public func generateOperationsStructs(indentation: String) throws -> String {
let orderedOperationDefinitions = self.operationIRs
.sorted { left, right in left.key.value < right.key.value }
.map { _, operation in operation }
let operationDefinitionsCode = try orderedOperationDefinitions.map {
try $0.generateCode(outputSchemaName: self.outputSchemaName, indentation: "")
}
.joined(separator: "\n\n")
return operationDefinitionsCode
}
public func generateEnumDeclarations(indentation: String) -> String? {
guard self.usedEnumTypes.count > 0 else {
return nil
}
let orderedEnums = self.usedEnumTypes
.sorted { left, right in left.key.value < right.key.value }
.map { _, `enum` in `enum` }
let enumCode = orderedEnums.map { $0.generateEnumDeclaration(indentation: indentation) }.joined(separator: "\n\n")
return enumCode
}
public func generateInputObjectStructDeclarations(indentation: String) -> String? {
guard self.usedInputObjectTypes.count > 0 else {
return nil
}
let orderedInputObjects = self.usedInputObjectTypes
.sorted { left, right in left.key.value < right.key.value }
.map { _, inputObject in inputObject }
let inputObjectCode = orderedInputObjects.map { $0.generateCode(indentation: indentation) }.joined(separator: "\n\n")
return inputObjectCode
}
}
public struct RequestProtocolGenerator {
public var AutoGraphQLRequest: String {
return "AutoGraphQLRequest"
}
public var protocolsCode: String {
return """
public protocol \(self.AutoGraphQLRequest): AutoGraphQL.Request {
associatedtype QueryDocument = AutoGraphQL.Document
var operation: AutoGraphQL.Operation { get }
var fragments: [FragmentDefinition] { get }
var data: SerializedObject? { get set }
}
public extension \(self.AutoGraphQLRequest) {
var queryDocument: AutoGraphQL.Document {
let operation = self.operation
let fragments = self.fragments
return AutoGraphQL.Document(operations: [operation], fragments: fragments)
}
var operationName: String {
return self.operation.name
}
var rootKeyPath: String { return "data" }
func willSend() throws { }
func didFinishRequest(response: HTTPURLResponse?, json: JSONValue) throws { }
func didFinish(result: AutoGraphResult<SerializedObject>) throws { }
}
public struct EnumConversionError: LocalizedError {
let type: Any.Type
init(type: Any.Type) {
self.type = type
}
public var errorDescription: String? {
return "Failed to convert JSON to \\(self.type)"
}
}
"""
}
}