open_api_import 0.11.5 → 0.12.0
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 +4 -4
- data/README.md +25 -2
- data/bin/open_api_import +25 -11
- data/lib/open_api_import/filter.rb +10 -6
- data/lib/open_api_import/get_data_all_of_bodies.rb +8 -4
- data/lib/open_api_import/get_examples.rb +57 -47
- data/lib/open_api_import/get_patterns.rb +35 -27
- data/lib/open_api_import/get_required_data.rb +12 -7
- data/lib/open_api_import/get_response_examples.rb +28 -28
- data/lib/open_api_import/open_api_import.rb +232 -187
- data/lib/open_api_import/pretty_hash_symbolized.rb +8 -4
- data/lib/open_api_import/utils.rb +17 -19
- data/lib/open_api_import.rb +3 -3
- metadata +40 -19
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
using OpenApiImportStringExt
|
|
4
|
+
|
|
1
5
|
class OpenApiImport
|
|
6
|
+
class ParseError < StandardError; end
|
|
7
|
+
|
|
8
|
+
VERSION = "0.12.0"
|
|
9
|
+
|
|
10
|
+
extend LibOpenApiImport
|
|
11
|
+
|
|
2
12
|
##############################################################################################
|
|
3
13
|
# Import a Swagger or Open API file and create a Ruby Request Hash file including all requests and responses.
|
|
4
14
|
# The http methods that will be treated are: 'get','post','put','delete', 'patch'.
|
|
@@ -18,8 +28,10 @@ class OpenApiImport
|
|
|
18
28
|
# tags: It will be used the tags key to create the module name, for example the tags: [users,list] will create the module UsersList and all the requests from all modules in the same file.
|
|
19
29
|
# tags_file: It will be used the tags key to create the module name, for example the tags: [users,list] will create the module UsersList and and each module will be in a new requests file.
|
|
20
30
|
# fixed: all the requests will be under the module Requests
|
|
31
|
+
# @param return_data [Boolean]. (default: false) Instead of writing files, return a Hash of {filename => content}.
|
|
21
32
|
##############################################################################################
|
|
22
|
-
def self.from(swagger_file, create_method_name: :operation_id, include_responses: true, mock_response: false,
|
|
33
|
+
def self.from(swagger_file, create_method_name: :operation_id, include_responses: true, mock_response: false,
|
|
34
|
+
name_for_module: :path, silent: false, create_constants: false, return_data: false)
|
|
23
35
|
begin
|
|
24
36
|
f = File.new("#{swagger_file}_open_api_import.log", "w")
|
|
25
37
|
f.sync = true
|
|
@@ -35,59 +47,53 @@ class OpenApiImport
|
|
|
35
47
|
@logger.info "swagger_file: #{swagger_file}, include_responses: #{include_responses}, mock_response: #{mock_response}\n"
|
|
36
48
|
@logger.info "create_method_name: #{create_method_name}, name_for_module: #{name_for_module}\n"
|
|
37
49
|
|
|
38
|
-
file_to_convert =
|
|
39
|
-
swagger_file
|
|
40
|
-
else
|
|
41
|
-
Dir.pwd.to_s + "/" + swagger_file.gsub("./", "")
|
|
42
|
-
end
|
|
50
|
+
file_to_convert = File.expand_path(swagger_file)
|
|
43
51
|
unless File.exist?(file_to_convert)
|
|
44
52
|
raise "The file #{file_to_convert} doesn't exist"
|
|
45
53
|
end
|
|
46
54
|
|
|
47
|
-
file_errors = file_to_convert
|
|
48
|
-
|
|
55
|
+
file_errors = "#{file_to_convert}.errors.log"
|
|
56
|
+
FileUtils.rm_f(file_errors)
|
|
49
57
|
import_errors = ""
|
|
50
58
|
required_constants = []
|
|
51
59
|
|
|
52
60
|
begin
|
|
53
61
|
definition = OasParser::Definition.resolve(swagger_file)
|
|
54
|
-
rescue
|
|
62
|
+
rescue StandardError => e
|
|
55
63
|
message = "There was a problem parsing the Open Api document using the oas_parser_reborn gem. The execution was aborted.\n"
|
|
56
64
|
message += "Visit the github for oas_parser_reborn gem for bugs and more info: https://github.com/MarioRuiz/oas_parser_reborn\n"
|
|
57
|
-
message += "Error: #{
|
|
58
|
-
puts message
|
|
65
|
+
message += "Error: #{e.message}"
|
|
59
66
|
@logger.fatal message
|
|
60
|
-
@logger.fatal
|
|
61
|
-
|
|
67
|
+
@logger.fatal e.backtrace.join("\n")
|
|
68
|
+
raise ParseError, message
|
|
62
69
|
end
|
|
63
70
|
|
|
64
71
|
raw = definition.raw.deep_symbolize_keys
|
|
65
72
|
|
|
66
|
-
if raw.key?(:openapi) &&
|
|
73
|
+
if raw.key?(:openapi) && raw[:openapi].to_f.positive?
|
|
67
74
|
raw[:swagger] = raw[:openapi]
|
|
68
75
|
end
|
|
69
76
|
if raw[:swagger].to_f < 2.0
|
|
70
77
|
raise "Unsupported Swagger version. Only versions >= 2.0 are valid."
|
|
71
78
|
end
|
|
72
79
|
|
|
73
|
-
base_host = ""
|
|
74
80
|
base_path = ""
|
|
75
81
|
|
|
76
|
-
|
|
82
|
+
raw[:host] if raw.key?(:host)
|
|
77
83
|
base_path = raw[:basePath] if raw.key?(:basePath)
|
|
78
84
|
module_name = raw[:info][:title].camel_case
|
|
79
85
|
module_version = "V#{raw[:info][:version].to_s.snake_case}"
|
|
80
86
|
|
|
81
87
|
output = []
|
|
82
88
|
output_header = []
|
|
83
|
-
output_header << "#" * 50
|
|
89
|
+
output_header << ("#" * 50)
|
|
84
90
|
output_header << "# #{raw[:info][:title]}"
|
|
85
91
|
output_header << "# version: #{raw[:info][:version]}"
|
|
86
92
|
output_header << "# description: "
|
|
87
93
|
raw[:info][:description].to_s.split("\n").each do |d|
|
|
88
94
|
output_header << "# #{d}" unless d == ""
|
|
89
95
|
end
|
|
90
|
-
output_header << "#" * 50
|
|
96
|
+
output_header << ("#" * 50)
|
|
91
97
|
|
|
92
98
|
output_header << "module Swagger"
|
|
93
99
|
output_header << "module #{module_name}"
|
|
@@ -102,10 +108,9 @@ class OpenApiImport
|
|
|
102
108
|
raw = path.raw.deep_symbolize_keys
|
|
103
109
|
|
|
104
110
|
if raw.key?(:parameters)
|
|
105
|
-
raw.
|
|
111
|
+
raw.each_key do |met|
|
|
106
112
|
if met != :parameters
|
|
107
113
|
if raw[met].key?(:parameters)
|
|
108
|
-
#in case parameters for all methods in path is present
|
|
109
114
|
raw[met][:parameters] = raw[met][:parameters] + raw[:parameters]
|
|
110
115
|
else
|
|
111
116
|
raw[met][:parameters] = raw[:parameters]
|
|
@@ -124,85 +129,76 @@ class OpenApiImport
|
|
|
124
129
|
params_data = []
|
|
125
130
|
description_parameters = []
|
|
126
131
|
data_form = []
|
|
132
|
+
data_form_hash = {}
|
|
127
133
|
data_required = []
|
|
128
|
-
#todo: add nested one.true.three to data_read_only
|
|
129
134
|
data_read_only = []
|
|
130
135
|
data_default = []
|
|
131
136
|
data_examples = []
|
|
137
|
+
data_examples_hashes = []
|
|
132
138
|
data_pattern = []
|
|
133
139
|
responses = []
|
|
134
140
|
|
|
135
|
-
# for the case operationId is missing
|
|
136
141
|
cont[:operationId] = "undefined" unless cont.key?(:operationId)
|
|
137
142
|
|
|
138
143
|
if create_method_name == :path
|
|
139
|
-
method_name =
|
|
144
|
+
method_name = "#{met}_#{path.path}".snake_case
|
|
140
145
|
method_name.chop! if method_name[-1] == "_"
|
|
141
146
|
elsif create_method_name == :operation_id
|
|
142
|
-
if (name_for_module == :tags
|
|
147
|
+
if ((name_for_module == :tags) || (name_for_module == :tags_file)) && cont.key?(:tags) && cont[:tags].is_a?(Array) && cont[:tags].size.positive?
|
|
143
148
|
metnametmp = cont[:operationId].gsub(/^#{cont[:tags].join}[\s_]*/, "")
|
|
144
|
-
cont[:tags].join.split
|
|
145
|
-
metnametmp.gsub
|
|
149
|
+
cont[:tags].join.split.each do |tag|
|
|
150
|
+
metnametmp = metnametmp.gsub(/^#{tag}[\s_]*/i, "")
|
|
146
151
|
end
|
|
147
152
|
metnametmp = met if metnametmp == ""
|
|
148
153
|
else
|
|
149
154
|
metnametmp = cont[:operationId]
|
|
150
155
|
end
|
|
151
156
|
method_name = metnametmp.to_s.snake_case
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
method_name.gsub!(/^#{tag}[\s_]*/i, "")
|
|
157
|
-
end
|
|
158
|
-
method_name = met if method_name == ""
|
|
159
|
-
else
|
|
160
|
-
method_name = cont[:operationId]
|
|
157
|
+
elsif ((name_for_module == :tags) || (name_for_module == :tags_file)) && cont.key?(:tags) && cont[:tags].is_a?(Array) && cont[:tags].size.positive?
|
|
158
|
+
method_name = cont[:operationId].gsub(/^#{cont[:tags].join}[\s_]*/, "")
|
|
159
|
+
cont[:tags].join.split.each do |tag|
|
|
160
|
+
method_name = method_name.gsub(/^#{tag}[\s_]*/i, "")
|
|
161
161
|
end
|
|
162
|
+
method_name = met if method_name == ""
|
|
163
|
+
else
|
|
164
|
+
method_name = cont[:operationId]
|
|
162
165
|
end
|
|
163
166
|
path_txt = path.path.dup.to_s
|
|
164
167
|
if [:path, :path_file, :tags, :tags_file].include?(name_for_module)
|
|
165
168
|
old_module_requests = module_requests
|
|
166
169
|
if [:path, :path_file].include?(name_for_module)
|
|
167
|
-
|
|
168
|
-
path_requests =
|
|
169
|
-
# to remove version from path fex: /1.0/Customer
|
|
170
|
-
path_requests = path_requests.gsub(/^\/[\d\.]*\//i, "")
|
|
170
|
+
path_requests = path_txt.gsub(%r{^/v[\d.]*/}i, "")
|
|
171
|
+
path_requests = path_requests.gsub(%r{^/[\d.]*/}i, "")
|
|
171
172
|
if (path_requests == path_txt) && (path_txt.scan("/").size == 1)
|
|
172
|
-
# no folder in path
|
|
173
173
|
module_requests = "Root"
|
|
174
174
|
else
|
|
175
175
|
res_path = path_requests.scan(/(\w+)/)
|
|
176
176
|
module_requests = res_path[0][0].camel_case
|
|
177
177
|
end
|
|
178
|
+
elsif cont.key?(:tags) && cont[:tags].is_a?(Array) && cont[:tags].size.positive?
|
|
179
|
+
module_requests = cont[:tags].join(" ").camel_case
|
|
178
180
|
else
|
|
179
|
-
|
|
180
|
-
module_requests = cont[:tags].join(" ").camel_case
|
|
181
|
-
else
|
|
182
|
-
module_requests = "Undefined"
|
|
183
|
-
end
|
|
181
|
+
module_requests = "Undefined"
|
|
184
182
|
end
|
|
185
183
|
|
|
186
|
-
# to remove from method_name: v1_list_regions and add it to module
|
|
187
184
|
if /^(?<vers>v\d+)/i =~ method_name
|
|
188
|
-
method_name.gsub
|
|
185
|
+
method_name = method_name.gsub(/^#{vers}_?/, "")
|
|
189
186
|
module_requests = (vers.capitalize + module_requests).camel_case unless module_requests.start_with?(vers)
|
|
190
187
|
end
|
|
191
188
|
|
|
192
189
|
if old_module_requests != module_requests
|
|
193
|
-
output << "end" unless old_module_requests == ""
|
|
194
|
-
if name_for_module == :path
|
|
195
|
-
# to add the end for the previous module unless is the first one
|
|
190
|
+
output << "end" unless (old_module_requests == "") || (name_for_module == :path_file) || (name_for_module == :tags_file)
|
|
191
|
+
if (name_for_module == :path) || (name_for_module == :tags)
|
|
196
192
|
output << "module #{module_requests}"
|
|
197
|
-
else
|
|
193
|
+
else # :path_file, :tags_file
|
|
198
194
|
if old_module_requests != ""
|
|
199
195
|
unless files.key?(old_module_requests)
|
|
200
|
-
files[old_module_requests] =
|
|
196
|
+
files[old_module_requests] = []
|
|
201
197
|
end
|
|
202
198
|
files[old_module_requests].concat(output)
|
|
203
|
-
output =
|
|
199
|
+
output = []
|
|
204
200
|
end
|
|
205
|
-
output << "module #{module_requests}" unless files.key?(module_requests)
|
|
201
|
+
output << "module #{module_requests}" unless files.key?(module_requests)
|
|
206
202
|
end
|
|
207
203
|
end
|
|
208
204
|
end
|
|
@@ -210,60 +206,57 @@ class OpenApiImport
|
|
|
210
206
|
output << ""
|
|
211
207
|
output << "# operationId: #{cont[:operationId]}, method: #{met}"
|
|
212
208
|
output << "# summary: #{cont[:summary].split("\n").join("\n# ")}" if cont.key?(:summary)
|
|
213
|
-
if
|
|
209
|
+
if cont[:description].to_s.split("\n").empty?
|
|
210
|
+
output << "# description: #{cont[:description]}"
|
|
211
|
+
else
|
|
214
212
|
output << "# description: "
|
|
215
213
|
cont[:description].to_s.split("\n").each do |d|
|
|
216
214
|
output << "# #{d}" unless d == ""
|
|
217
215
|
end
|
|
218
|
-
else
|
|
219
|
-
output << "# description: #{cont[:description]}"
|
|
220
216
|
end
|
|
221
217
|
|
|
222
218
|
mock_example = []
|
|
223
219
|
|
|
224
220
|
if include_responses && cont.key?(:responses) && cont[:responses].is_a?(Hash)
|
|
225
221
|
cont[:responses].each do |k, v|
|
|
226
|
-
response_example = []
|
|
227
222
|
response_example = get_response_examples(v)
|
|
228
223
|
|
|
229
224
|
data_pattern += get_patterns("", v[:schema]) if v.key?(:schema)
|
|
230
225
|
data_pattern.uniq!
|
|
231
|
-
|
|
232
|
-
if
|
|
226
|
+
resp_description = v[:description].to_s.gsub("'", %q(\\\'))
|
|
227
|
+
if response_example.empty?
|
|
228
|
+
responses << "'#{k}': { message: '#{resp_description}'}, "
|
|
229
|
+
else
|
|
233
230
|
responses << "'#{k}': { "
|
|
234
|
-
responses << "message: '#{
|
|
231
|
+
responses << "message: '#{resp_description}', "
|
|
235
232
|
responses << "data: "
|
|
236
233
|
responses << response_example
|
|
237
234
|
responses << "},"
|
|
238
|
-
if mock_response
|
|
235
|
+
if mock_response && mock_example.empty?
|
|
239
236
|
mock_example << "code: '#{k}',"
|
|
240
|
-
mock_example << "message: '#{
|
|
237
|
+
mock_example << "message: '#{resp_description}',"
|
|
241
238
|
mock_example << "data: "
|
|
242
239
|
mock_example << response_example
|
|
243
240
|
end
|
|
244
|
-
else
|
|
245
|
-
responses << "'#{k}': { message: '#{v[:description]}'}, "
|
|
246
241
|
end
|
|
247
242
|
end
|
|
248
243
|
end
|
|
249
|
-
# todo: for open api 3.0 add the new Link feature: https://swagger.io/docs/specification/links/
|
|
250
|
-
# todo: for open api 3.0 is not getting the required params in all cases
|
|
251
244
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if cont.key?(:requestBody) and cont[:requestBody].key?(:content) and
|
|
255
|
-
cont[:requestBody][:content].key?(:'application/json') and cont[:requestBody][:content][:'application/json'].key?(:schema)
|
|
245
|
+
if cont.key?(:requestBody) && cont[:requestBody].key?(:content) &&
|
|
246
|
+
cont[:requestBody][:content].key?(:"application/json") && cont[:requestBody][:content][:"application/json"].key?(:schema)
|
|
256
247
|
cont[:parameters] = [] unless cont.key?(:parameters)
|
|
257
|
-
cont[:parameters] << { in: "body", schema: cont[:requestBody][:content][:
|
|
248
|
+
cont[:parameters] << { in: "body", schema: cont[:requestBody][:content][:"application/json"][:schema] }
|
|
258
249
|
end
|
|
259
250
|
|
|
260
251
|
data_examples_all_of = false
|
|
261
252
|
if cont.key?(:parameters) && cont[:parameters].is_a?(Array)
|
|
262
253
|
cont[:parameters].each do |p|
|
|
263
|
-
if p.keys.include?(:schema)
|
|
254
|
+
if p.keys.include?(:schema) && p[:schema].include?(:type)
|
|
264
255
|
type = p[:schema][:type]
|
|
256
|
+
type = Array(type).reject { |t| t == "null" }.first if type.is_a?(Array)
|
|
265
257
|
elsif p.keys.include?(:type)
|
|
266
258
|
type = p[:type]
|
|
259
|
+
type = Array(type).reject { |t| t == "null" }.first if type.is_a?(Array)
|
|
267
260
|
else
|
|
268
261
|
type = ""
|
|
269
262
|
end
|
|
@@ -271,10 +264,10 @@ class OpenApiImport
|
|
|
271
264
|
if p[:in] == "path"
|
|
272
265
|
if create_method_name == :operationId
|
|
273
266
|
param_name = p[:name]
|
|
274
|
-
path_txt.gsub
|
|
267
|
+
path_txt = path_txt.gsub("{#{param_name}}", "\#{#{param_name}}")
|
|
275
268
|
else
|
|
276
269
|
param_name = p[:name].to_s.snake_case
|
|
277
|
-
path_txt.gsub
|
|
270
|
+
path_txt = path_txt.gsub("{#{p[:name]}}", "\#{#{param_name}}")
|
|
278
271
|
end
|
|
279
272
|
unless params_path.include?(param_name)
|
|
280
273
|
if create_constants
|
|
@@ -283,7 +276,6 @@ class OpenApiImport
|
|
|
283
276
|
else
|
|
284
277
|
params_path << param_name
|
|
285
278
|
end
|
|
286
|
-
#params_required << param_name if p[:required].to_s=="true"
|
|
287
279
|
@logger.warn "Description key is missing for #{met} #{path.path} #{p[:name]}" if p[:description].nil?
|
|
288
280
|
description_parameters << "# #{p[:name]}: (#{type}) #{"(required)" if p[:required].to_s == "true"} #{p[:description].to_s.split("\n").join("\n#\t\t\t")}"
|
|
289
281
|
end
|
|
@@ -292,22 +284,22 @@ class OpenApiImport
|
|
|
292
284
|
params_required << p[:name] if p[:required].to_s == "true"
|
|
293
285
|
@logger.warn "Description key is missing for #{met} #{path.path} #{p[:name]}" if p[:description].nil?
|
|
294
286
|
description_parameters << "# #{p[:name]}: (#{type}) #{"(required)" if p[:required].to_s == "true"} #{p[:description].to_s.split("\n").join("\n#\t\t\t")}"
|
|
295
|
-
elsif p[:in] == "formData"
|
|
296
|
-
#todo: take in consideration: default, required
|
|
297
|
-
#todo: see if we should add the required as params to the method and not required as options
|
|
298
|
-
#todo: set on data the required fields with the values from args
|
|
299
|
-
|
|
287
|
+
elsif (p[:in] == "formData") || (p[:in] == "formdata")
|
|
300
288
|
description_parameters << "# #{p[:name]}: (#{p[:type]}) #{p[:description].split("\n").join("\n#\t\t\t")}"
|
|
301
289
|
|
|
302
290
|
case p[:type]
|
|
303
291
|
when /^string$/i
|
|
304
292
|
data_form << "#{p[:name]}: ''"
|
|
293
|
+
data_form_hash[p[:name].to_sym] = ""
|
|
305
294
|
when /^boolean$/i
|
|
306
295
|
data_form << "#{p[:name]}: true"
|
|
296
|
+
data_form_hash[p[:name].to_sym] = true
|
|
307
297
|
when /^number$/i
|
|
308
298
|
data_form << "#{p[:name]}: 0"
|
|
299
|
+
data_form_hash[p[:name].to_sym] = 0
|
|
309
300
|
when /^integer$/i
|
|
310
301
|
data_form << "#{p[:name]}: 0"
|
|
302
|
+
data_form_hash[p[:name].to_sym] = 0
|
|
311
303
|
else
|
|
312
304
|
puts "! on formData not supported type #{p[:type]}"
|
|
313
305
|
end
|
|
@@ -319,18 +311,19 @@ class OpenApiImport
|
|
|
319
311
|
bodies = p[:schema][:anyOf]
|
|
320
312
|
elsif p[:schema].key?(:allOf)
|
|
321
313
|
data_examples_all_of, bodies = get_data_all_of_bodies(p)
|
|
322
|
-
bodies.unshift(p[:schema]) if p[:schema].key?(:required)
|
|
323
|
-
data_examples_all_of = true
|
|
314
|
+
bodies.unshift(p[:schema]) if p[:schema].key?(:required) || p.key?(:required)
|
|
315
|
+
data_examples_all_of = true
|
|
324
316
|
else
|
|
325
317
|
bodies = [p[:schema]]
|
|
326
318
|
end
|
|
327
319
|
|
|
328
320
|
params_data = []
|
|
321
|
+
params_data_hash = {}
|
|
329
322
|
|
|
330
323
|
bodies.each do |body|
|
|
331
324
|
data_required += get_required_data(body)
|
|
332
325
|
all_properties = []
|
|
333
|
-
all_properties << body[:properties] if body.keys.include?(:properties)
|
|
326
|
+
all_properties << body[:properties] if body.keys.include?(:properties) && body[:properties].size.positive?
|
|
334
327
|
if body.key?(:allOf)
|
|
335
328
|
body[:allOf].each do |item|
|
|
336
329
|
all_properties << item[:properties] if item.key?(:properties)
|
|
@@ -338,30 +331,28 @@ class OpenApiImport
|
|
|
338
331
|
end
|
|
339
332
|
|
|
340
333
|
all_properties.each do |props|
|
|
341
|
-
props.each
|
|
334
|
+
props.each do |dpk, dpv|
|
|
342
335
|
if dpv.keys.include?(:example)
|
|
343
|
-
if dpv[:example].is_a?(Array)
|
|
336
|
+
if dpv[:example].is_a?(Array) && (dpv.type != "array")
|
|
344
337
|
valv = dpv[:example][0]
|
|
345
338
|
else
|
|
346
339
|
valv = dpv[:example].to_s
|
|
347
340
|
end
|
|
348
|
-
|
|
349
|
-
if dpv.
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
valv = valv.join("\n")
|
|
359
|
-
else
|
|
360
|
-
valv = "[]"
|
|
361
|
-
end
|
|
341
|
+
elsif dpv.type == "object"
|
|
342
|
+
if dpv.key?(:properties)
|
|
343
|
+
valv = get_examples(dpv[:properties], :key_value, true).join("\n")
|
|
344
|
+
else
|
|
345
|
+
valv = "{}"
|
|
346
|
+
end
|
|
347
|
+
elsif dpv.type == "array"
|
|
348
|
+
if dpv.key?(:items)
|
|
349
|
+
valv = get_examples({ dpk => dpv }, :only_value)
|
|
350
|
+
valv = valv.join("\n")
|
|
362
351
|
else
|
|
363
|
-
valv = ""
|
|
352
|
+
valv = "[]"
|
|
364
353
|
end
|
|
354
|
+
else
|
|
355
|
+
valv = ""
|
|
365
356
|
end
|
|
366
357
|
|
|
367
358
|
if dpv.keys.include?(:description)
|
|
@@ -372,7 +363,7 @@ class OpenApiImport
|
|
|
372
363
|
data_pattern.uniq!
|
|
373
364
|
dpkeys = []
|
|
374
365
|
data_pattern.reject! do |dp|
|
|
375
|
-
dpkey = dp.scan(/^'[\w
|
|
366
|
+
dpkey = dp.scan(/^'[\w.]+'/)
|
|
376
367
|
|
|
377
368
|
if dpkeys.include?(dpkey)
|
|
378
369
|
true
|
|
@@ -382,7 +373,7 @@ class OpenApiImport
|
|
|
382
373
|
end
|
|
383
374
|
end
|
|
384
375
|
|
|
385
|
-
if dpv.keys.include?(:readOnly)
|
|
376
|
+
if dpv.keys.include?(:readOnly) && (dpv[:readOnly] == true)
|
|
386
377
|
data_read_only << dpk
|
|
387
378
|
end
|
|
388
379
|
if dpv.keys.include?(:default)
|
|
@@ -395,28 +386,34 @@ class OpenApiImport
|
|
|
395
386
|
end
|
|
396
387
|
end
|
|
397
388
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
if dpv.key?(:type)
|
|
389
|
+
params_data_hash[dpk] = build_example_value(dpv)
|
|
390
|
+
|
|
391
|
+
if dpv.key?(:type) && (dpv[:type] != "array")
|
|
401
392
|
params_data << get_examples({ dpk => dpv }, :only_value, true).join
|
|
402
|
-
params_data[-1].chop!.chop! if params_data[-1].to_s[-2
|
|
393
|
+
params_data[-1].chop!.chop! if params_data[-1].to_s[-2..] == ", "
|
|
403
394
|
params_data.pop if params_data[-1].match?(/^\s*$/im)
|
|
404
395
|
else
|
|
405
396
|
if valv.to_s == ""
|
|
406
397
|
valv = '""'
|
|
407
398
|
elsif valv.include?('"')
|
|
408
|
-
valv.gsub
|
|
399
|
+
valv = valv.gsub('"', "'") unless valv.include?("'")
|
|
409
400
|
end
|
|
410
401
|
params_data << "#{dpk}: #{valv}"
|
|
411
402
|
end
|
|
412
|
-
|
|
413
|
-
if params_data.size
|
|
414
|
-
if data_examples_all_of == true
|
|
403
|
+
end
|
|
404
|
+
if params_data.size.positive?
|
|
405
|
+
if (data_examples_all_of == true) && data_examples.size.positive?
|
|
415
406
|
data_examples[0] += params_data
|
|
416
407
|
else
|
|
417
408
|
data_examples << params_data
|
|
418
409
|
end
|
|
410
|
+
if (data_examples_all_of == true) && data_examples_hashes.size.positive?
|
|
411
|
+
data_examples_hashes[0].merge!(params_data_hash)
|
|
412
|
+
else
|
|
413
|
+
data_examples_hashes << params_data_hash.dup
|
|
414
|
+
end
|
|
419
415
|
params_data = []
|
|
416
|
+
params_data_hash = {}
|
|
420
417
|
end
|
|
421
418
|
end
|
|
422
419
|
end
|
|
@@ -427,7 +424,7 @@ class OpenApiImport
|
|
|
427
424
|
end
|
|
428
425
|
end
|
|
429
426
|
elsif p[:in] == "header"
|
|
430
|
-
#
|
|
427
|
+
# TODO: see how we can treat those cases
|
|
431
428
|
else
|
|
432
429
|
puts "! not imported data with :in:#{p[:in]} => #{p.inspect}"
|
|
433
430
|
end
|
|
@@ -450,15 +447,13 @@ class OpenApiImport
|
|
|
450
447
|
required_constants << pr.to_s.snake_case.upcase
|
|
451
448
|
end
|
|
452
449
|
end
|
|
453
|
-
|
|
454
|
-
if
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
params << "#{pr.to_s.snake_case}"
|
|
461
|
-
end
|
|
450
|
+
elsif params_query.include?(pr)
|
|
451
|
+
if create_method_name == :operationId
|
|
452
|
+
path_txt += "#{pr}=\#{#{pr}}&"
|
|
453
|
+
params << pr.to_s
|
|
454
|
+
else
|
|
455
|
+
path_txt += "#{pr}=\#{#{pr.to_s.snake_case}}&"
|
|
456
|
+
params << pr.to_s.snake_case.to_s
|
|
462
457
|
end
|
|
463
458
|
end
|
|
464
459
|
end
|
|
@@ -476,23 +471,17 @@ class OpenApiImport
|
|
|
476
471
|
end
|
|
477
472
|
end
|
|
478
473
|
|
|
479
|
-
if description_parameters.size
|
|
474
|
+
if description_parameters.size.positive?
|
|
480
475
|
output << "# parameters description: "
|
|
481
476
|
output << description_parameters.uniq
|
|
482
477
|
end
|
|
483
478
|
|
|
484
|
-
|
|
485
|
-
if path_txt.scan(/[^#]{\w+}/).size > 0
|
|
479
|
+
if path_txt.scan(/[^#]{\w+}/).size.positive?
|
|
486
480
|
paramst = []
|
|
487
481
|
prms = path_txt.scan(/[^#]{(\w+)}/)
|
|
488
482
|
prms.each do |p|
|
|
489
|
-
#if create_constants
|
|
490
|
-
# paramst<<"#{p[0].to_s.snake_case}: #{p[0].to_s.snake_case.upcase}"
|
|
491
|
-
# required_constants << p[0].to_s.snake_case.upcase
|
|
492
|
-
#else
|
|
493
483
|
paramst << p[0].to_s.snake_case
|
|
494
|
-
#
|
|
495
|
-
path_txt.gsub!("{#{p[0]}}", "\#{#{p[0].to_s.snake_case}}")
|
|
484
|
+
path_txt = path_txt.gsub("{#{p[0]}}", "\#{#{p[0].to_s.snake_case}}")
|
|
496
485
|
end
|
|
497
486
|
paramst.concat params
|
|
498
487
|
params = paramst
|
|
@@ -533,6 +522,7 @@ class OpenApiImport
|
|
|
533
522
|
|
|
534
523
|
unless data_form.empty?
|
|
535
524
|
data_examples << data_form
|
|
525
|
+
data_examples_hashes << data_form_hash unless data_form_hash.empty?
|
|
536
526
|
end
|
|
537
527
|
|
|
538
528
|
unless data_examples.empty?
|
|
@@ -540,18 +530,15 @@ class OpenApiImport
|
|
|
540
530
|
reqdata = []
|
|
541
531
|
begin
|
|
542
532
|
data_examples[0].uniq!
|
|
543
|
-
data_ex =
|
|
544
|
-
rescue
|
|
545
|
-
data_ex = {}
|
|
546
|
-
@logger.warn "Syntax error: #{met} for path: #{path.path} evaluating data_examples[0] => #{data_examples[0].inspect}"
|
|
547
|
-
rescue
|
|
533
|
+
data_ex = data_examples_hashes[0] || {}
|
|
534
|
+
rescue StandardError => e
|
|
548
535
|
data_ex = {}
|
|
549
|
-
@logger.warn "
|
|
536
|
+
@logger.warn "Error processing data examples: #{met} for path: #{path.path} => #{e.message}"
|
|
550
537
|
end
|
|
551
|
-
if
|
|
552
|
-
reqdata = filter(data_ex, data_required)
|
|
538
|
+
if data_required.grep(/\./).empty?
|
|
539
|
+
reqdata = filter(data_ex, data_required)
|
|
553
540
|
else
|
|
554
|
-
reqdata = filter(data_ex, data_required, true)
|
|
541
|
+
reqdata = filter(data_ex, data_required, true)
|
|
555
542
|
end
|
|
556
543
|
unless reqdata.empty?
|
|
557
544
|
reqdata.uniq!
|
|
@@ -560,16 +547,15 @@ class OpenApiImport
|
|
|
560
547
|
output += phsd
|
|
561
548
|
end
|
|
562
549
|
end
|
|
563
|
-
unless data_read_only.empty?
|
|
550
|
+
unless data_read_only.empty? || !data_required.empty?
|
|
564
551
|
reqdata = []
|
|
565
|
-
#remove read only fields from :data
|
|
566
552
|
data_examples[0].each do |edata|
|
|
567
553
|
read_only = false
|
|
568
554
|
data_read_only.each do |rdata|
|
|
569
|
-
if edata.scan(/^#{rdata}:/).size
|
|
555
|
+
if edata.scan(/^#{rdata}:/).size.positive?
|
|
570
556
|
read_only = true
|
|
571
557
|
break
|
|
572
|
-
elsif edata.scan(
|
|
558
|
+
elsif edata.scan(":").empty?
|
|
573
559
|
break
|
|
574
560
|
end
|
|
575
561
|
end
|
|
@@ -614,24 +600,29 @@ class OpenApiImport
|
|
|
614
600
|
end
|
|
615
601
|
output_footer = []
|
|
616
602
|
|
|
617
|
-
output_footer << "end" unless (module_requests == "") &&
|
|
603
|
+
output_footer << "end" unless (module_requests == "") && [:path, :path_file, :tags, :tags_file].include?(name_for_module)
|
|
618
604
|
output_footer << "end" << "end" << "end"
|
|
619
|
-
|
|
605
|
+
|
|
606
|
+
generated_files = {}
|
|
607
|
+
|
|
608
|
+
if files.empty? && !create_constants
|
|
620
609
|
output = output_header + output + output_footer
|
|
621
610
|
output_txt = output.join("\n")
|
|
622
|
-
requests_file_path = file_to_convert
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
611
|
+
requests_file_path = "#{file_to_convert}.rb"
|
|
612
|
+
if return_data
|
|
613
|
+
generated_files[requests_file_path] = output_txt
|
|
614
|
+
else
|
|
615
|
+
File.write(requests_file_path, output_txt)
|
|
616
|
+
format_and_check_file(requests_file_path, @logger)
|
|
617
|
+
message = "** Requests file: #{swagger_file}.rb that contains the code of the requests after importing the Swagger file"
|
|
618
|
+
puts message unless silent
|
|
619
|
+
@logger.info message
|
|
620
|
+
end
|
|
630
621
|
else
|
|
631
622
|
unless files.key?(module_requests)
|
|
632
|
-
files[module_requests] =
|
|
623
|
+
files[module_requests] = []
|
|
633
624
|
end
|
|
634
|
-
files[module_requests].concat(output)
|
|
625
|
+
files[module_requests].concat(output)
|
|
635
626
|
|
|
636
627
|
requires_txt = ""
|
|
637
628
|
message = "** Generated files that contain the code of the requests after importing the Swagger file: "
|
|
@@ -640,19 +631,22 @@ class OpenApiImport
|
|
|
640
631
|
files.each do |mod, out_mod|
|
|
641
632
|
output = output_header + out_mod + output_footer
|
|
642
633
|
output_txt = output.join("\n")
|
|
643
|
-
requests_file_path = file_to_convert
|
|
634
|
+
requests_file_path = "#{file_to_convert}_#{mod}.rb"
|
|
644
635
|
requires_txt += "require_relative '#{File.basename(swagger_file)}_#{mod}'\n"
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
636
|
+
if return_data
|
|
637
|
+
generated_files[requests_file_path] = output_txt
|
|
638
|
+
else
|
|
639
|
+
File.write(requests_file_path, output_txt)
|
|
640
|
+
format_and_check_file(requests_file_path, @logger)
|
|
641
|
+
display_path = "#{swagger_file}_#{mod}.rb"
|
|
642
|
+
message = " - #{display_path}"
|
|
643
|
+
puts message unless silent
|
|
644
|
+
@logger.info message
|
|
645
|
+
end
|
|
652
646
|
end
|
|
653
647
|
|
|
654
|
-
requests_file_path = file_to_convert
|
|
655
|
-
if required_constants.size
|
|
648
|
+
requests_file_path = "#{file_to_convert}.rb"
|
|
649
|
+
if required_constants.size.positive?
|
|
656
650
|
rconsts = "# Required constants\n"
|
|
657
651
|
required_constants.uniq!
|
|
658
652
|
required_constants.each do |rq|
|
|
@@ -663,37 +657,88 @@ class OpenApiImport
|
|
|
663
657
|
rconsts = ""
|
|
664
658
|
end
|
|
665
659
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
660
|
+
if return_data
|
|
661
|
+
generated_files[requests_file_path] = rconsts + requires_txt
|
|
662
|
+
else
|
|
663
|
+
File.write(requests_file_path, rconsts + requires_txt)
|
|
664
|
+
format_and_check_file(requests_file_path, @logger)
|
|
665
|
+
message = "** File that contains all the requires for all Request files: \n"
|
|
666
|
+
message += " - #{swagger_file}.rb "
|
|
667
|
+
puts message unless silent
|
|
668
|
+
@logger.info message
|
|
669
|
+
end
|
|
674
670
|
end
|
|
675
671
|
|
|
672
|
+
return generated_files if return_data
|
|
673
|
+
|
|
676
674
|
begin
|
|
677
|
-
|
|
678
|
-
rescue
|
|
679
|
-
import_errors += "\n\nResult evaluating the ruby file generated: \n"
|
|
675
|
+
load File.expand_path(requests_file_path)
|
|
676
|
+
rescue StandardError => e
|
|
677
|
+
import_errors += "\n\nResult evaluating the ruby file generated: \n#{e}"
|
|
680
678
|
end
|
|
681
679
|
|
|
682
|
-
if import_errors.to_s
|
|
683
|
-
|
|
684
|
-
|
|
680
|
+
if import_errors.to_s == ""
|
|
681
|
+
true
|
|
682
|
+
else
|
|
683
|
+
File.write(file_errors, import_errors)
|
|
684
|
+
message = "* It seems there was a problem importing the Swagger file #{swagger_file}\n"
|
|
685
685
|
message += "* Take a look at the detected errors at #{file_errors}\n"
|
|
686
686
|
warn message
|
|
687
687
|
@logger.fatal message
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
688
|
+
false
|
|
689
|
+
end
|
|
690
|
+
rescue ParseError
|
|
691
|
+
raise
|
|
692
|
+
rescue StandardError => e
|
|
693
|
+
puts e.message
|
|
694
|
+
@logger.fatal e.message
|
|
695
|
+
@logger.fatal e.backtrace
|
|
696
|
+
puts e.backtrace
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
private_class_method def self.format_and_check_file(file_path, logger)
|
|
701
|
+
escaped_path = Shellwords.shellescape(file_path)
|
|
702
|
+
res_rufo = `rufo #{escaped_path}`
|
|
703
|
+
logger.error " Error formatting with rufo" unless res_rufo.to_s.match?(/\AFormat:.+$\s*\z/)
|
|
704
|
+
syntax_result = `ruby -c #{escaped_path} 2>&1`
|
|
705
|
+
logger.error " Syntax Error: #{syntax_result}" unless syntax_result.include?("Syntax OK")
|
|
706
|
+
rescue Errno::ENOENT => e
|
|
707
|
+
logger.error " Could not run formatter/syntax checker: #{e.message}"
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
private_class_method def self.build_example_value(dpv)
|
|
711
|
+
if dpv.key?(:example)
|
|
712
|
+
dpv[:example]
|
|
713
|
+
elsif dpv.key?(:examples) && dpv[:examples].is_a?(Array) && !dpv[:examples].empty?
|
|
714
|
+
dpv[:examples].first
|
|
715
|
+
elsif dpv.key?(:type)
|
|
716
|
+
effective_type = dpv[:type]
|
|
717
|
+
effective_type = Array(effective_type).reject { |t| t == "null" }.first if effective_type.is_a?(Array)
|
|
718
|
+
case effective_type.to_s.downcase
|
|
719
|
+
when "string" then dpv[:format] || "string"
|
|
720
|
+
when "integer" then 0
|
|
721
|
+
when "number"
|
|
722
|
+
%w[float double decimal].include?(dpv[:format].to_s.downcase) ? 0.0 : 0
|
|
723
|
+
when "boolean" then true
|
|
724
|
+
when "object"
|
|
725
|
+
if dpv.key?(:properties)
|
|
726
|
+
result = {}
|
|
727
|
+
dpv[:properties].each { |k, v| result[k] = build_example_value(v) }
|
|
728
|
+
result
|
|
729
|
+
else
|
|
730
|
+
{}
|
|
731
|
+
end
|
|
732
|
+
when "array"
|
|
733
|
+
if dpv.key?(:items) && dpv[:items].is_a?(Hash)
|
|
734
|
+
[build_example_value(dpv[:items])]
|
|
735
|
+
else
|
|
736
|
+
[]
|
|
737
|
+
end
|
|
738
|
+
else dpv[:format] || ""
|
|
691
739
|
end
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
@logger.fatal stack.message
|
|
695
|
-
@logger.fatal stack.backtrace
|
|
696
|
-
puts stack.backtrace
|
|
740
|
+
else
|
|
741
|
+
""
|
|
697
742
|
end
|
|
698
743
|
end
|
|
699
744
|
end
|