openapi_kit-codegen 0.1.0.pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +385 -0
- data/exe/openapi_kit +6 -0
- data/lib/openapi_kit/codegen/cli.rb +72 -0
- data/lib/openapi_kit/codegen/config.rb +114 -0
- data/lib/openapi_kit/codegen/emit/buffer.rb +92 -0
- data/lib/openapi_kit/codegen/emit/codecs.rb +221 -0
- data/lib/openapi_kit/codegen/emit/controllers.rb +263 -0
- data/lib/openapi_kit/codegen/emit/decode.rb +43 -0
- data/lib/openapi_kit/codegen/emit/defaults.rb +42 -0
- data/lib/openapi_kit/codegen/emit/emitter.rb +17 -0
- data/lib/openapi_kit/codegen/emit/forms.rb +56 -0
- data/lib/openapi_kit/codegen/emit/handlers.rb +65 -0
- data/lib/openapi_kit/codegen/emit/literal.rb +28 -0
- data/lib/openapi_kit/codegen/emit/operations.rb +277 -0
- data/lib/openapi_kit/codegen/emit/registry.rb +101 -0
- data/lib/openapi_kit/codegen/emit/routes.rb +77 -0
- data/lib/openapi_kit/codegen/emit/security.rb +183 -0
- data/lib/openapi_kit/codegen/emit/source_file.rb +30 -0
- data/lib/openapi_kit/codegen/emit/types.rb +153 -0
- data/lib/openapi_kit/codegen/generator.rb +48 -0
- data/lib/openapi_kit/codegen/loader.rb +730 -0
- data/lib/openapi_kit/codegen/model/document.rb +302 -0
- data/lib/openapi_kit/codegen/model/schema.rb +110 -0
- data/lib/openapi_kit/codegen/model/type_def.rb +89 -0
- data/lib/openapi_kit/codegen/naming.rb +78 -0
- data/lib/openapi_kit/codegen/ruby_type.rb +48 -0
- data/lib/openapi_kit/codegen/type_registry.rb +325 -0
- data/lib/openapi_kit/codegen/writer.rb +92 -0
- data/lib/openapi_kit/codegen.rb +37 -0
- data/lib/openapi_kit-codegen.rb +4 -0
- metadata +118 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module OpenAPIKit
|
|
5
|
+
module Codegen
|
|
6
|
+
module Model
|
|
7
|
+
class HttpMethod < T::Enum
|
|
8
|
+
enums do
|
|
9
|
+
Get = new("get")
|
|
10
|
+
Put = new("put")
|
|
11
|
+
Post = new("post")
|
|
12
|
+
Delete = new("delete")
|
|
13
|
+
Options = new("options")
|
|
14
|
+
Head = new("head")
|
|
15
|
+
Patch = new("patch")
|
|
16
|
+
Trace = new("trace")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class PathStyle < T::Enum
|
|
21
|
+
enums do
|
|
22
|
+
Simple = new("simple")
|
|
23
|
+
Label = new("label")
|
|
24
|
+
Matrix = new("matrix")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class QueryStyle < T::Enum
|
|
29
|
+
enums do
|
|
30
|
+
Form = new("form")
|
|
31
|
+
SpaceDelimited = new("spaceDelimited")
|
|
32
|
+
PipeDelimited = new("pipeDelimited")
|
|
33
|
+
DeepObject = new("deepObject")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class ParameterInfo < T::Struct
|
|
38
|
+
const :name, String
|
|
39
|
+
const :identifier, Symbol
|
|
40
|
+
const :schema, Schema
|
|
41
|
+
const :description, T.nilable(String), default: nil
|
|
42
|
+
const :deprecated, T::Boolean, default: false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module Parameter
|
|
46
|
+
extend T::Sig
|
|
47
|
+
extend T::Helpers
|
|
48
|
+
include Kernel
|
|
49
|
+
sealed!
|
|
50
|
+
|
|
51
|
+
sig { params(parameter: Parameter).returns(ParameterInfo) }
|
|
52
|
+
def self.info(parameter)
|
|
53
|
+
case parameter
|
|
54
|
+
when PathParameter, QueryParameter, HeaderParameter, CookieParameter then parameter.info
|
|
55
|
+
else T.absurd(parameter)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
sig { params(parameter: Parameter).returns(T::Boolean) }
|
|
60
|
+
def self.required?(parameter)
|
|
61
|
+
case parameter
|
|
62
|
+
when PathParameter then true
|
|
63
|
+
when QueryParameter, HeaderParameter, CookieParameter then parameter.required
|
|
64
|
+
else T.absurd(parameter)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
class PathParameter < T::Struct
|
|
70
|
+
include Parameter
|
|
71
|
+
const :info, ParameterInfo
|
|
72
|
+
const :style, PathStyle, default: PathStyle::Simple
|
|
73
|
+
const :explode, T::Boolean, default: false
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class QueryParameter < T::Struct
|
|
77
|
+
include Parameter
|
|
78
|
+
const :info, ParameterInfo
|
|
79
|
+
const :required, T::Boolean, default: false
|
|
80
|
+
const :style, QueryStyle, default: QueryStyle::Form
|
|
81
|
+
const :explode, T::Boolean, default: true
|
|
82
|
+
const :allow_reserved, T::Boolean, default: false
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class HeaderParameter < T::Struct
|
|
86
|
+
include Parameter
|
|
87
|
+
const :info, ParameterInfo
|
|
88
|
+
const :required, T::Boolean, default: false
|
|
89
|
+
const :explode, T::Boolean, default: false
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class CookieParameter < T::Struct
|
|
93
|
+
include Parameter
|
|
94
|
+
const :info, ParameterInfo
|
|
95
|
+
const :required, T::Boolean, default: false
|
|
96
|
+
const :explode, T::Boolean, default: true
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class Content < T::Struct
|
|
100
|
+
extend T::Sig
|
|
101
|
+
|
|
102
|
+
const :media_type, String
|
|
103
|
+
const :schema, T.nilable(Schema), default: nil
|
|
104
|
+
|
|
105
|
+
sig { params(media_type: String).returns(T::Boolean) }
|
|
106
|
+
def self.multipart?(media_type)
|
|
107
|
+
T.must(media_type.split(";").first).strip.downcase == "multipart/form-data"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
sig { returns(T::Boolean) }
|
|
111
|
+
def multipart? = Content.multipart?(media_type)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
class RequestBody < T::Struct
|
|
115
|
+
const :contents, T::Array[Content]
|
|
116
|
+
const :required, T::Boolean, default: false
|
|
117
|
+
const :description, T.nilable(String), default: nil
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
class Header < T::Struct
|
|
121
|
+
const :name, String
|
|
122
|
+
const :identifier, Symbol
|
|
123
|
+
const :schema, Schema
|
|
124
|
+
const :required, T::Boolean, default: false
|
|
125
|
+
const :description, T.nilable(String), default: nil
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
module Status
|
|
129
|
+
extend T::Sig
|
|
130
|
+
extend T::Helpers
|
|
131
|
+
include Kernel
|
|
132
|
+
sealed!
|
|
133
|
+
|
|
134
|
+
NAMES = T.let(
|
|
135
|
+
{
|
|
136
|
+
200 => "Ok", 201 => "Created", 202 => "Accepted", 203 => "NonAuthoritativeInformation",
|
|
137
|
+
204 => "NoContent", 205 => "ResetContent", 206 => "PartialContent",
|
|
138
|
+
301 => "MovedPermanently", 302 => "Found", 303 => "SeeOther", 304 => "NotModified",
|
|
139
|
+
307 => "TemporaryRedirect", 308 => "PermanentRedirect",
|
|
140
|
+
400 => "BadRequest", 401 => "Unauthorized", 402 => "PaymentRequired", 403 => "Forbidden",
|
|
141
|
+
404 => "NotFound", 405 => "MethodNotAllowed", 406 => "NotAcceptable", 409 => "Conflict",
|
|
142
|
+
410 => "Gone", 412 => "PreconditionFailed", 413 => "ContentTooLarge",
|
|
143
|
+
415 => "UnsupportedMediaType", 418 => "ImATeapot", 422 => "UnprocessableContent",
|
|
144
|
+
425 => "TooEarly", 428 => "PreconditionRequired", 429 => "TooManyRequests",
|
|
145
|
+
500 => "InternalServerError", 501 => "NotImplemented", 502 => "BadGateway",
|
|
146
|
+
503 => "ServiceUnavailable", 504 => "GatewayTimeout"
|
|
147
|
+
}.freeze,
|
|
148
|
+
T::Hash[Integer, String]
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
sig { params(status: Status).returns(String) }
|
|
152
|
+
def self.constant(status)
|
|
153
|
+
case status
|
|
154
|
+
when StatusCode then NAMES[status.code] || "Status#{status.code}"
|
|
155
|
+
when StatusRange then "Status#{status.hundreds}xx"
|
|
156
|
+
when DefaultStatus then "Default"
|
|
157
|
+
else T.absurd(status)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
sig { params(raw: String).returns(Status) }
|
|
162
|
+
def self.parse(raw)
|
|
163
|
+
return DefaultStatus.new if raw == "default"
|
|
164
|
+
return StatusRange.new(hundreds: T.must(raw[0]).to_i) if raw.match?(/\A[1-5]XX\z/i)
|
|
165
|
+
return StatusCode.new(code: raw.to_i) if raw.match?(/\A[1-5]\d\d\z/)
|
|
166
|
+
|
|
167
|
+
raise SchemaError,
|
|
168
|
+
"#{raw.inspect} is not a valid response status. Use a three-digit code " \
|
|
169
|
+
"(200), a range (4XX) or `default`."
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
module SecurityScheme
|
|
174
|
+
extend T::Sig
|
|
175
|
+
extend T::Helpers
|
|
176
|
+
include Kernel
|
|
177
|
+
sealed!
|
|
178
|
+
|
|
179
|
+
sig { params(scheme: SecurityScheme).returns(String) }
|
|
180
|
+
def self.name_of(scheme)
|
|
181
|
+
case scheme
|
|
182
|
+
when ApiKeyScheme, HttpScheme, OAuth2Scheme, OpenIDConnectScheme then scheme.name
|
|
183
|
+
else T.absurd(scheme)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
sig { params(scheme: SecurityScheme).returns(T::Hash[String, T.untyped]) }
|
|
188
|
+
def self.extensions_of(scheme)
|
|
189
|
+
case scheme
|
|
190
|
+
when ApiKeyScheme, HttpScheme, OAuth2Scheme, OpenIDConnectScheme then scheme.extensions
|
|
191
|
+
else T.absurd(scheme)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
class StatusCode < T::Struct
|
|
197
|
+
include Status
|
|
198
|
+
const :code, Integer
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
class StatusRange < T::Struct
|
|
202
|
+
include Status
|
|
203
|
+
const :hundreds, Integer
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
class DefaultStatus < T::Struct
|
|
207
|
+
include Status
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
class Response < T::Struct
|
|
211
|
+
const :status, Status
|
|
212
|
+
const :contents, T::Array[Content]
|
|
213
|
+
const :headers, T::Array[Header], default: []
|
|
214
|
+
const :description, T.nilable(String), default: nil
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
class SecurityRequirement < T::Struct
|
|
218
|
+
extend T::Sig
|
|
219
|
+
const :schemes, T::Hash[String, T::Array[String]]
|
|
220
|
+
|
|
221
|
+
sig { returns(T::Boolean) }
|
|
222
|
+
def anonymous? = schemes.empty?
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
class ApiKeyLocation < T::Enum
|
|
226
|
+
enums do
|
|
227
|
+
Query = new("query")
|
|
228
|
+
Header = new("header")
|
|
229
|
+
Cookie = new("cookie")
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
class ApiKeyScheme < T::Struct
|
|
234
|
+
include SecurityScheme
|
|
235
|
+
const :name, String
|
|
236
|
+
const :location, ApiKeyLocation
|
|
237
|
+
const :parameter_name, String
|
|
238
|
+
const :description, T.nilable(String), default: nil
|
|
239
|
+
const :extensions, T::Hash[String, T.untyped], default: {}
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
class HttpScheme < T::Struct
|
|
243
|
+
include SecurityScheme
|
|
244
|
+
const :name, String
|
|
245
|
+
const :scheme, String
|
|
246
|
+
const :bearer_format, T.nilable(String), default: nil
|
|
247
|
+
const :description, T.nilable(String), default: nil
|
|
248
|
+
const :extensions, T::Hash[String, T.untyped], default: {}
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
class OAuth2Scheme < T::Struct
|
|
252
|
+
include SecurityScheme
|
|
253
|
+
const :name, String
|
|
254
|
+
const :scopes, T::Hash[String, String], default: {}
|
|
255
|
+
const :description, T.nilable(String), default: nil
|
|
256
|
+
const :extensions, T::Hash[String, T.untyped], default: {}
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
class OpenIDConnectScheme < T::Struct
|
|
260
|
+
include SecurityScheme
|
|
261
|
+
const :name, String
|
|
262
|
+
const :url, String
|
|
263
|
+
const :description, T.nilable(String), default: nil
|
|
264
|
+
const :extensions, T::Hash[String, T.untyped], default: {}
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
class Operation < T::Struct
|
|
268
|
+
extend T::Sig
|
|
269
|
+
const :id, String
|
|
270
|
+
const :http_method, HttpMethod
|
|
271
|
+
const :path, String
|
|
272
|
+
const :tag, String
|
|
273
|
+
const :parameters, T::Array[Parameter], default: []
|
|
274
|
+
const :request_body, T.nilable(RequestBody), default: nil
|
|
275
|
+
const :responses, T::Array[Response], default: []
|
|
276
|
+
const :security, T.nilable(T::Array[SecurityRequirement]), default: nil
|
|
277
|
+
const :summary, T.nilable(String), default: nil
|
|
278
|
+
const :description, T.nilable(String), default: nil
|
|
279
|
+
const :deprecated, T::Boolean, default: false
|
|
280
|
+
const :extensions, T::Hash[String, T.untyped], default: {}
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
class Document < T::Struct
|
|
284
|
+
extend T::Sig
|
|
285
|
+
const :title, String
|
|
286
|
+
const :version, String
|
|
287
|
+
const :types, T::Array[TypeDef], default: []
|
|
288
|
+
const :operations, T::Array[Operation], default: []
|
|
289
|
+
const :security_schemes, T::Array[SecurityScheme], default: []
|
|
290
|
+
const :security, T::Array[SecurityRequirement], default: []
|
|
291
|
+
|
|
292
|
+
# An operation that declares no security inherits the document's.
|
|
293
|
+
sig { params(operation: Operation).returns(T::Array[SecurityRequirement]) }
|
|
294
|
+
def security_for(operation) = operation.security || security
|
|
295
|
+
const :raw, T::Hash[String, T.untyped], default: {}
|
|
296
|
+
|
|
297
|
+
sig { returns(T::Array[String]) }
|
|
298
|
+
def tags = operations.map(&:tag).uniq
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module OpenAPIKit
|
|
5
|
+
module Codegen
|
|
6
|
+
module Model
|
|
7
|
+
class Default < T::Struct
|
|
8
|
+
const :value, T.untyped
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Meta < T::Struct
|
|
12
|
+
const :description, T.nilable(String), default: nil
|
|
13
|
+
const :nullable, T::Boolean, default: false
|
|
14
|
+
const :deprecated, T::Boolean, default: false
|
|
15
|
+
const :default, T.nilable(Default), default: nil
|
|
16
|
+
const :read_only, T::Boolean, default: false
|
|
17
|
+
const :write_only, T::Boolean, default: false
|
|
18
|
+
const :extensions, T::Hash[String, T.untyped], default: {}
|
|
19
|
+
const :ruby_type, T.nilable(RubyType), default: nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module Schema
|
|
23
|
+
extend T::Sig
|
|
24
|
+
extend T::Helpers
|
|
25
|
+
include Kernel
|
|
26
|
+
sealed!
|
|
27
|
+
|
|
28
|
+
sig { params(schema: Schema).returns(Meta) }
|
|
29
|
+
def self.meta(schema)
|
|
30
|
+
case schema
|
|
31
|
+
when Ref, StringSchema, IntegerSchema, NumberSchema, BooleanSchema, List, Freeform, Untyped
|
|
32
|
+
schema.meta
|
|
33
|
+
else T.absurd(schema)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
sig { params(schema: Schema).returns(T::Boolean) }
|
|
38
|
+
def self.file?(schema)
|
|
39
|
+
return false unless schema.is_a?(StringSchema) && schema.format == "binary"
|
|
40
|
+
|
|
41
|
+
meta(schema).ruby_type.nil?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Ref < T::Struct
|
|
46
|
+
include Schema
|
|
47
|
+
const :name, String
|
|
48
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class StringSchema < T::Struct
|
|
52
|
+
include Schema
|
|
53
|
+
const :format, T.nilable(String), default: nil
|
|
54
|
+
const :min_length, T.nilable(Integer), default: nil
|
|
55
|
+
const :max_length, T.nilable(Integer), default: nil
|
|
56
|
+
const :pattern, T.nilable(String), default: nil
|
|
57
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class IntegerSchema < T::Struct
|
|
61
|
+
include Schema
|
|
62
|
+
const :format, T.nilable(String), default: nil
|
|
63
|
+
const :minimum, T.nilable(Integer), default: nil
|
|
64
|
+
const :maximum, T.nilable(Integer), default: nil
|
|
65
|
+
const :exclusive_minimum, T::Boolean, default: false
|
|
66
|
+
const :exclusive_maximum, T::Boolean, default: false
|
|
67
|
+
const :multiple_of, T.nilable(Numeric), default: nil
|
|
68
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class NumberSchema < T::Struct
|
|
72
|
+
include Schema
|
|
73
|
+
const :format, T.nilable(String), default: nil
|
|
74
|
+
const :minimum, T.nilable(Numeric), default: nil
|
|
75
|
+
const :maximum, T.nilable(Numeric), default: nil
|
|
76
|
+
const :exclusive_minimum, T::Boolean, default: false
|
|
77
|
+
const :exclusive_maximum, T::Boolean, default: false
|
|
78
|
+
const :multiple_of, T.nilable(Numeric), default: nil
|
|
79
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class BooleanSchema < T::Struct
|
|
83
|
+
include Schema
|
|
84
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class List < T::Struct
|
|
88
|
+
include Schema
|
|
89
|
+
const :items, Schema
|
|
90
|
+
const :min_items, T.nilable(Integer), default: nil
|
|
91
|
+
const :max_items, T.nilable(Integer), default: nil
|
|
92
|
+
const :unique_items, T::Boolean, default: false
|
|
93
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
class Freeform < T::Struct
|
|
97
|
+
include Schema
|
|
98
|
+
const :values, T.nilable(Schema), default: nil
|
|
99
|
+
const :min_properties, T.nilable(Integer), default: nil
|
|
100
|
+
const :max_properties, T.nilable(Integer), default: nil
|
|
101
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
class Untyped < T::Struct
|
|
105
|
+
include Schema
|
|
106
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module OpenAPIKit
|
|
5
|
+
module Codegen
|
|
6
|
+
module Model
|
|
7
|
+
class Property < T::Struct
|
|
8
|
+
const :name, String
|
|
9
|
+
const :identifier, Symbol
|
|
10
|
+
const :schema, Schema
|
|
11
|
+
const :required, T::Boolean, default: false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module UnionTag
|
|
15
|
+
extend T::Helpers
|
|
16
|
+
include Kernel
|
|
17
|
+
sealed!
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Tagged < T::Struct
|
|
21
|
+
include UnionTag
|
|
22
|
+
const :property_name, String
|
|
23
|
+
const :mapping, T::Hash[String, String]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class Untagged < T::Struct
|
|
27
|
+
include UnionTag
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module TypeDef
|
|
31
|
+
extend T::Sig
|
|
32
|
+
extend T::Helpers
|
|
33
|
+
include Kernel
|
|
34
|
+
sealed!
|
|
35
|
+
|
|
36
|
+
sig { params(type_def: TypeDef).returns(String) }
|
|
37
|
+
def self.name_of(type_def)
|
|
38
|
+
case type_def
|
|
39
|
+
when ObjectDef, FormDef, EnumDef, UnionDef, AliasDef then type_def.name
|
|
40
|
+
else T.absurd(type_def)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class ObjectDef < T::Struct
|
|
46
|
+
include TypeDef
|
|
47
|
+
const :name, String
|
|
48
|
+
const :properties, T::Array[Property]
|
|
49
|
+
const :additional_properties, T.nilable(Schema), default: nil
|
|
50
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class FormDef < T::Struct
|
|
54
|
+
include TypeDef
|
|
55
|
+
const :name, String
|
|
56
|
+
const :properties, T::Array[Property]
|
|
57
|
+
const :additional_properties, T.nilable(Schema), default: nil
|
|
58
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class EnumMember < T::Struct
|
|
62
|
+
const :constant, String
|
|
63
|
+
const :value, T.any(String, Integer)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
class EnumDef < T::Struct
|
|
67
|
+
include TypeDef
|
|
68
|
+
const :name, String
|
|
69
|
+
const :members, T::Array[EnumMember]
|
|
70
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class UnionDef < T::Struct
|
|
74
|
+
include TypeDef
|
|
75
|
+
const :name, String
|
|
76
|
+
const :members, T::Array[Schema]
|
|
77
|
+
const :tag, UnionTag
|
|
78
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class AliasDef < T::Struct
|
|
82
|
+
include TypeDef
|
|
83
|
+
const :name, String
|
|
84
|
+
const :target, Schema
|
|
85
|
+
const :meta, Meta, factory: -> { Meta.new }
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module OpenAPIKit
|
|
5
|
+
module Codegen
|
|
6
|
+
module Naming
|
|
7
|
+
extend T::Sig
|
|
8
|
+
|
|
9
|
+
RESERVED = T.let(
|
|
10
|
+
%w[
|
|
11
|
+
BEGIN END alias and begin break case class def defined? do else elsif end ensure
|
|
12
|
+
false for if in module next nil not or redo rescue retry return self super then
|
|
13
|
+
true undef unless until when while yield __FILE__ __LINE__ __ENCODING__
|
|
14
|
+
].freeze,
|
|
15
|
+
T::Array[String]
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
sig { params(string: String).returns(T::Array[String]) }
|
|
19
|
+
def self.words(string)
|
|
20
|
+
string
|
|
21
|
+
.to_s
|
|
22
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1 \2') # HTTPSConnection -> HTTPS Connection
|
|
23
|
+
.gsub(/([a-z\d])([A-Z])/, '\1 \2') # gameDomain -> game Domain
|
|
24
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
25
|
+
.reject(&:empty?)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
sig { params(string: String).returns(String) }
|
|
29
|
+
def self.snake(string) = words(string).map(&:downcase).join("_")
|
|
30
|
+
|
|
31
|
+
sig { params(string: String).returns(String) }
|
|
32
|
+
def self.pascal(string) = words(string).map(&:capitalize).join
|
|
33
|
+
|
|
34
|
+
SHADOWED = T.let(
|
|
35
|
+
%w[
|
|
36
|
+
__id__ __send__ as_json class class_eval clone deep_dup define_singleton_method
|
|
37
|
+
deserialize display dup enum_for extend freeze gem hash inspect instance_eval
|
|
38
|
+
instance_exec instance_values instance_variable_get instance_variable_names
|
|
39
|
+
instance_variable_set instance_variables itself method methods object_id presence
|
|
40
|
+
presence_in pretty_inspect pretty_print pretty_print_cycle pretty_print_inspect
|
|
41
|
+
pretty_print_instance_variables private_methods protected_methods public_method
|
|
42
|
+
public_methods public_send remove_instance_variable send serialize singleton_class
|
|
43
|
+
singleton_method singleton_methods tap then to_enum to_json to_param to_query to_s
|
|
44
|
+
to_yaml try with with_options yield_self
|
|
45
|
+
].to_set.freeze,
|
|
46
|
+
T::Set[String]
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
sig { params(string: String).returns(Symbol) }
|
|
50
|
+
def self.identifier(string)
|
|
51
|
+
name = snake(string)
|
|
52
|
+
name = "value" if name.empty?
|
|
53
|
+
name = "n#{name}" if name.match?(/\A\d/)
|
|
54
|
+
name = "#{name}_" if RESERVED.include?(name) || SHADOWED.include?(name)
|
|
55
|
+
name.to_sym
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
sig { params(string: String).returns(String) }
|
|
59
|
+
def self.constant(string)
|
|
60
|
+
name = pascal(string)
|
|
61
|
+
name = "Value" if name.empty?
|
|
62
|
+
name = "Value#{name}" if name.match?(/\A\d/)
|
|
63
|
+
name
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
sig { params(value: T.untyped).returns(String) }
|
|
67
|
+
def self.enum_member(value)
|
|
68
|
+
case value
|
|
69
|
+
when ::String then constant(value)
|
|
70
|
+
when ::Integer then "Value#{value.negative? ? "Minus#{value.abs}" : value}"
|
|
71
|
+
when true then "True"
|
|
72
|
+
when false then "False"
|
|
73
|
+
else constant(value.to_s)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module OpenAPIKit
|
|
5
|
+
module Codegen
|
|
6
|
+
class RubyType < T::Struct
|
|
7
|
+
extend T::Sig
|
|
8
|
+
|
|
9
|
+
CONSTANT_PATH = T.let(/\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/, Regexp)
|
|
10
|
+
|
|
11
|
+
const :type, String
|
|
12
|
+
const :codec, String
|
|
13
|
+
|
|
14
|
+
sig { params(where: String, value: T.untyped).returns(RubyType) }
|
|
15
|
+
def self.parse(where, value)
|
|
16
|
+
unless value.is_a?(Hash)
|
|
17
|
+
raise ConfigError,
|
|
18
|
+
"#{where} must be a mapping with `type` and `codec`, got #{value.inspect}.\n " \
|
|
19
|
+
"#{where}:\n type: \"::YourType\"\n codec: \"YourApp::YourTypeCodec\""
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
unknown = value.keys.map(&:to_s) - %w[type codec]
|
|
23
|
+
unless unknown.empty?
|
|
24
|
+
raise ConfigError,
|
|
25
|
+
"#{where} has unknown key#{"s" if unknown.size > 1} #{unknown.sort.join(", ")}. " \
|
|
26
|
+
"Valid keys: type, codec."
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
missing = %w[type codec].reject { |key| value[key] }
|
|
30
|
+
unless missing.empty?
|
|
31
|
+
raise ConfigError,
|
|
32
|
+
"#{where} is missing #{missing.join(" and ")}. Both are required: `type` is what " \
|
|
33
|
+
"appears in signatures, `codec` is what converts it: a module extending, or an " \
|
|
34
|
+
"instance of a class including, OpenAPIKit::Codec."
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
codec = value.fetch("codec").to_s
|
|
38
|
+
unless codec.match?(CONSTANT_PATH)
|
|
39
|
+
raise ConfigError,
|
|
40
|
+
"#{where}.codec is #{codec.inspect}, which is not a Ruby constant path. " \
|
|
41
|
+
"It must name a constant holding a codec, e.g. \"YourApp::YourTypeCodec\"."
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
new(type: value.fetch("type").to_s, codec: codec)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|