nexmo-oas-renderer 0.11.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +135 -0
  3. data/.travis.yml +1 -0
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +81 -61
  6. data/Rakefile +2 -2
  7. data/bin/console +3 -3
  8. data/lib/nexmo/oas/engine.rb +2 -0
  9. data/lib/nexmo/oas/renderer.rb +5 -5
  10. data/lib/nexmo/oas/renderer/app.rb +70 -45
  11. data/lib/nexmo/oas/renderer/config.ru +4 -2
  12. data/lib/nexmo/oas/renderer/decorators/response_parser_decorator.rb +18 -18
  13. data/lib/nexmo/oas/renderer/helpers/navigation.rb +2 -2
  14. data/lib/nexmo/oas/renderer/helpers/render.rb +2 -1
  15. data/lib/nexmo/oas/renderer/helpers/summary.rb +4 -1
  16. data/lib/nexmo/oas/renderer/helpers/url.rb +2 -0
  17. data/lib/nexmo/oas/renderer/presenters/api_specification.rb +2 -1
  18. data/lib/nexmo/oas/renderer/presenters/endpoint.rb +2 -0
  19. data/lib/nexmo/oas/renderer/presenters/groups.rb +4 -0
  20. data/lib/nexmo/oas/renderer/presenters/navigation.rb +2 -0
  21. data/lib/nexmo/oas/renderer/presenters/open_api_specification.rb +5 -2
  22. data/lib/nexmo/oas/renderer/presenters/request_body_raw.rb +141 -0
  23. data/lib/nexmo/oas/renderer/presenters/response_format.rb +4 -2
  24. data/lib/nexmo/oas/renderer/presenters/response_tab/link.rb +3 -0
  25. data/lib/nexmo/oas/renderer/presenters/response_tab/panel.rb +8 -5
  26. data/lib/nexmo/oas/renderer/presenters/response_tabs.rb +6 -2
  27. data/lib/nexmo/oas/renderer/presenters/versions.rb +11 -10
  28. data/lib/nexmo/oas/renderer/public/assets/javascripts/components/format.js +12 -7
  29. data/lib/nexmo/oas/renderer/public/assets/javascripts/nexmo-oas-renderer.js +51 -24
  30. data/lib/nexmo/oas/renderer/public/assets/javascripts/popper.min.js +5 -0
  31. data/lib/nexmo/oas/renderer/public/assets/javascripts/tooltip.min.js +5 -0
  32. data/lib/nexmo/oas/renderer/public/assets/javascripts/volta.accordion.js +301 -243
  33. data/lib/nexmo/oas/renderer/public/assets/javascripts/volta.tooltip.js +76 -0
  34. data/lib/nexmo/oas/renderer/public/assets/stylesheets/nexmo-oas-renderer.css +255 -823
  35. data/lib/nexmo/oas/renderer/public/assets/stylesheets/nexmo-oas-renderer.css.map +2 -2
  36. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/api.scss +287 -90
  37. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/style.scss +2 -6
  38. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/themes/dark.scss +89 -0
  39. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/themes/light.scss +68 -0
  40. data/lib/nexmo/oas/renderer/public/assets/stylesheets/volta-prism.min.css +1 -1
  41. data/lib/nexmo/oas/renderer/public/assets/stylesheets/volta.min.css +1 -1
  42. data/lib/nexmo/oas/renderer/services/oas_parser.rb +2 -0
  43. data/lib/nexmo/oas/renderer/services/open_api_definition_resolver.rb +3 -1
  44. data/lib/nexmo/oas/renderer/version.rb +3 -1
  45. data/lib/nexmo/oas/renderer/views/layouts/_head.erb +1 -0
  46. data/lib/nexmo/oas/renderer/views/layouts/_javascripts.erb +5 -4
  47. data/lib/nexmo/oas/renderer/views/layouts/open_api.erb +3 -1
  48. data/lib/nexmo/oas/renderer/views/open_api/_auth.erb +74 -0
  49. data/lib/nexmo/oas/renderer/views/open_api/_available_endpoints.erb +25 -0
  50. data/lib/nexmo/oas/renderer/views/open_api/_callback_endpoint.erb +18 -27
  51. data/lib/nexmo/oas/renderer/views/open_api/_callbacks.erb +5 -0
  52. data/lib/nexmo/oas/renderer/views/open_api/_endpoint.erb +39 -124
  53. data/lib/nexmo/oas/renderer/views/open_api/_header.erb +71 -0
  54. data/lib/nexmo/oas/renderer/views/open_api/_model.erb +31 -26
  55. data/lib/nexmo/oas/renderer/views/open_api/_navigation.erb +54 -78
  56. data/lib/nexmo/oas/renderer/views/open_api/_parameter_groups.erb +2 -5
  57. data/lib/nexmo/oas/renderer/views/open_api/_parameters.erb +98 -169
  58. data/lib/nexmo/oas/renderer/views/open_api/_request_json.erb +4 -0
  59. data/lib/nexmo/oas/renderer/views/open_api/_request_one_of.erb +70 -0
  60. data/lib/nexmo/oas/renderer/views/open_api/_request_single.erb +53 -0
  61. data/lib/nexmo/oas/renderer/views/open_api/_requests.erb +22 -0
  62. data/lib/nexmo/oas/renderer/views/open_api/_response_description_parameters.erb +88 -90
  63. data/lib/nexmo/oas/renderer/views/open_api/_response_descriptions.erb +17 -12
  64. data/lib/nexmo/oas/renderer/views/open_api/_response_fields.erb +1 -16
  65. data/lib/nexmo/oas/renderer/views/open_api/_response_tabs.erb +2 -2
  66. data/lib/nexmo/oas/renderer/views/open_api/_responses.erb +35 -0
  67. data/lib/nexmo/oas/renderer/views/open_api/_tabbed_parameters.erb +15 -4
  68. data/lib/nexmo/oas/renderer/views/open_api/_tabbed_single_parameter.erb +56 -0
  69. data/lib/nexmo/oas/renderer/views/open_api/_webhooks.erb +30 -0
  70. data/lib/nexmo/oas/renderer/views/open_api/show.erb +10 -115
  71. data/nexmo-oas-renderer.gemspec +26 -26
  72. metadata +61 -49
  73. data/lib/nexmo/oas/renderer/public/assets/javascripts/components/scroll.js +0 -21
  74. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/core.scss +0 -137
  75. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/navigation.scss +0 -102
  76. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/nexmo.scss +0 -61
  77. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/syntax.scss +0 -63
  78. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/typography.scss +0 -248
  79. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/volta-templates.scss +0 -119
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sinatra/base'
2
4
  require 'active_support'
3
5
  require 'active_support/core_ext/array/conversions'
@@ -5,15 +7,16 @@ require 'active_support/core_ext/string/output_safety'
5
7
  require 'active_model'
6
8
  require 'nexmo_markdown_renderer'
7
9
 
8
- require_relative'./decorators/response_parser_decorator'
9
- require_relative'./presenters/api_specification'
10
- require_relative'./presenters/open_api_specification'
11
- require_relative'./presenters/navigation'
12
- require_relative'./presenters/response_tabs'
13
- require_relative'./helpers/render'
14
- require_relative'./helpers/navigation'
15
- require_relative'./helpers/summary'
16
- require_relative'./helpers/url'
10
+ require_relative './decorators/response_parser_decorator'
11
+ require_relative './presenters/api_specification'
12
+ require_relative './presenters/open_api_specification'
13
+ require_relative './presenters/navigation'
14
+ require_relative './presenters/request_body_raw'
15
+ require_relative './presenters/response_tabs'
16
+ require_relative './helpers/render'
17
+ require_relative './helpers/navigation'
18
+ require_relative './helpers/summary'
19
+ require_relative './helpers/url'
17
20
 
18
21
  require 'dotenv/load'
19
22
 
@@ -21,18 +24,17 @@ module Nexmo
21
24
  module OAS
22
25
  module Renderer
23
26
  class API < Sinatra::Base
24
-
25
27
  Tilt.register Tilt::ERBTemplate, 'html.erb'
26
28
 
27
29
  if defined?(NexmoDeveloper::Application)
28
- view_paths = [views, NexmoDeveloper::Application.root.join("app", "views")]
30
+ view_paths = [views, NexmoDeveloper::Application.root.join('app', 'views')]
29
31
  set :views, view_paths
30
32
  end
31
33
 
32
34
  set :mustermann_opts, { type: :rails }
33
35
  set :oas_path, (ENV['OAS_PATH'] || './')
34
36
  set :bind, '0.0.0.0'
35
- set :github_path, Proc.new { load_business_yaml }
37
+ set :github_path, (proc { load_business_yaml })
36
38
 
37
39
  helpers do
38
40
  include Helpers::Render
@@ -45,9 +47,9 @@ module Nexmo
45
47
  extensions = extension.split('.')
46
48
  case extensions.size
47
49
  when 1
48
- { definition: extensions.first}
50
+ { definition: extensions.first }
49
51
  when 2
50
- if extensions.second.match? /v\d+/
52
+ if extensions.second.match?(/v\d+/)
51
53
  { definition: extensions.first, version: extensions.second }
52
54
  else
53
55
  { definition: extensions.first, format: extensions.second }
@@ -60,29 +62,29 @@ module Nexmo
60
62
  end
61
63
 
62
64
  def self.load_business_yaml
63
- if defined?(NexmoDeveloper::Application) && !File.exist?("#{Rails.configuration.docs_base_path}/config/business_info.yml")
64
- raise "Application requires a 'config/business_info.yml' file to be defined inside the documentation path."
65
- elsif defined?(NexmoDeveloper::Application) && File.exist?("#{Rails.configuration.docs_base_path}/config/business_info.yml")
65
+ raise "Application requires a 'config/business_info.yml' file to be defined inside the documentation path." if defined?(NexmoDeveloper::Application) && !File.exist?("#{Rails.configuration.docs_base_path}/config/business_info.yml")
66
+
67
+ if defined?(NexmoDeveloper::Application) && File.exist?("#{Rails.configuration.docs_base_path}/config/business_info.yml")
66
68
  @url ||= begin
67
69
  config = YAML.load_file("#{Rails.configuration.docs_base_path}/config/business_info.yml")
68
70
  config['oas_url']
69
71
  end
70
72
  else
71
- "https://www.github.com/nexmo/api-specification/blob/master/definitions"
73
+ 'https://www.github.com/nexmo/api-specification/blob/master/definitions'
72
74
  end
73
75
  end
74
76
 
75
77
  def check_redirect!
76
- if defined?(NexmoDeveloper::Application)
77
- redirect_path = Redirector.find(request)
78
- redirect(redirect_path) if redirect_path
79
- end
78
+ return unless defined?(NexmoDeveloper::Application)
79
+
80
+ redirect_path = Redirector.find(request)
81
+ redirect(redirect_path) if redirect_path
80
82
  end
81
83
 
82
84
  def check_oas_constraints!(definition)
83
- if defined?(NexmoDeveloper::Application)
84
- pass unless OpenApiConstraint.match?(definition)
85
- end
85
+ return unless defined?(NexmoDeveloper::Application)
86
+
87
+ pass unless OpenApiConstraint.match?(definition)
86
88
  end
87
89
 
88
90
  error Errno::ENOENT do
@@ -96,21 +98,44 @@ module Nexmo
96
98
 
97
99
  unless defined?(NexmoDeveloper::Application)
98
100
  get '/' do
99
- prefix = "#{API.oas_path}"
101
+ prefix = API.oas_path.to_s
100
102
  @definitions = Dir.glob("#{prefix}/**/*.yml").map do |d|
101
103
  d.gsub("#{prefix}/", '').gsub('.yml', '')
102
- end.sort.reject { |d| d.include? 'common/' }
104
+ end
105
+
106
+ @definitions = @definitions.sort.reject { |d| d.include? 'common/' }
103
107
  erb :'api/index', layout: false
104
108
  end
105
109
  end
106
110
 
107
111
  def set_code_language
108
112
  return if params[:code_language] == 'templates'
113
+
109
114
  @code_language = params[:code_language]
110
115
  end
111
116
 
117
+ def set_theme
118
+ persisted_theme = nil
119
+
120
+ if defined?(NexmoDeveloper::Application)
121
+ session[:persisted_theme] = params[:theme] if params[:theme]
122
+ persisted_theme = session[:persisted_theme]
123
+ end
124
+
125
+ @theme = params[:theme] || persisted_theme
126
+
127
+ @theme = 'light' unless %w[light dark].include?(@theme)
128
+
129
+ @theme_light = @theme == 'light'
130
+
131
+ alternate_theme = @theme == 'light' ? 'dark' : 'light'
132
+ @theme_link = "#{request.path_info}?theme=#{alternate_theme}"
133
+ @theme_link = "/api#{@theme_link}" if defined?(NexmoDeveloper::Application)
134
+ end
135
+
112
136
  before do
113
137
  set_code_language
138
+ set_theme
114
139
  end
115
140
 
116
141
  get '(/api)/*definition' do
@@ -122,30 +147,30 @@ module Nexmo
122
147
 
123
148
  @specification = Presenters::OpenApiSpecification.new(
124
149
  definition_name: definition,
125
- expand_responses: params.fetch(:expandResponses, nil),
150
+ expand_responses: params.fetch(:expandResponses, nil)
126
151
  )
127
152
 
128
- if ['yml', 'json'].include?(parameters[:format])
129
- send_file @specification.definition.path, disposition: :attachment
153
+ if %w[yml json].include?(parameters[:format])
154
+ next send_file @specification.definition.path, disposition: :attachment
155
+ end
156
+
157
+ if defined?(NexmoDeveloper::Application)
158
+ erb :'open_api/show', layout: :'layouts/open-api.html'
130
159
  else
131
- if defined?(NexmoDeveloper::Application)
132
- erb :'open_api/show', layout: :'layouts/page-full.html'
133
- else
134
- erb :'open_api/show', layout: :'layouts/open_api'
135
- end
160
+ erb :'open_api/show', layout: :'layouts/open_api'
136
161
  end
137
162
  end
138
163
 
139
164
  def set_document
140
- if params[:code_language] == 'templates'
141
- @document = 'verify/templates'
142
- elsif params[:code_language] == 'ncco'
143
- @document = 'voice/ncco'
144
- elsif ::Nexmo::Markdown::CodeLanguage.exists?(params[:code_language])
145
- @document = params[:document]
146
- else
147
- @document = "#{params[:document]}/#{params[:code_language]}"
148
- end
165
+ @document = if params[:code_language] == 'templates'
166
+ 'verify/templates'
167
+ elsif params[:code_language] == 'ncco'
168
+ 'voice/ncco'
169
+ elsif ::Nexmo::Markdown::CodeLanguage.exists?(params[:code_language])
170
+ params[:document]
171
+ else
172
+ "#{params[:document]}/#{params[:code_language]}"
173
+ end
149
174
  end
150
175
 
151
176
  get '(/api)/*document(/:code_language)' do
@@ -158,7 +183,7 @@ module Nexmo
158
183
 
159
184
  @navigation = Presenters::Navigation.new(
160
185
  content: @specification.content,
161
- title: @specification.side_navigation_title,
186
+ title: @specification.side_navigation_title
162
187
  )
163
188
 
164
189
  if defined?(NexmoDeveloper::Application)
@@ -1,5 +1,7 @@
1
- require_relative "./app"
2
- require "sass/plugin/rack"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './app'
4
+ require 'sass/plugin/rack'
3
5
 
4
6
  Sass::Plugin.options[:style] = :compressed
5
7
  use Sass::Plugin::Rack
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rouge'
2
4
  require 'neatjson'
3
5
  require_relative '../services/oas_parser'
@@ -8,43 +10,41 @@ module Nexmo
8
10
  class ResponseParserDecorator < ::OasParser::ResponseParser
9
11
  def formatted_json
10
12
  JSON.neat_generate(parse, {
11
- wrap: true,
12
- after_colon: 1,
13
- })
13
+ wrap: true,
14
+ after_colon: 1,
15
+ })
14
16
  end
15
17
 
16
18
  def formatted_xml(xml_options = {})
17
19
  xml_options[:root] = xml_options['name'] if xml_options
18
20
  xml_string = xml(xml_options)
19
- xml_string.gsub!(%r{^(\s+?)(<(?:\w|\=|\"|\_|\s)+?\>)(.+?)(</.+?>)}).each do |s|
20
- indentation = $1
21
- indentation_plus_one = "#{$1} "
22
- opening_tag = $2
23
- content = $3
24
- closing_tag = $4
21
+ xml_string.gsub!(%r{^(\s+?)(<(?:\w|=|"|_|\s)+?>)(.+?)(</.+?>)}).each do |s|
22
+ indentation = Regexp.last_match(1)
23
+ indentation_plus_one = "#{Regexp.last_match(1)} "
24
+ opening_tag = Regexp.last_match(2)
25
+ content = Regexp.last_match(3)
26
+ closing_tag = Regexp.last_match(4)
25
27
 
26
28
  next(s) if (indentation.size + opening_tag.size + content.size) < 60
27
29
 
28
30
  next "#{indentation}#{opening_tag}\n#{indentation_plus_one}#{content}\n#{indentation}#{closing_tag}"
29
31
  end
30
32
 
31
- xml_string
33
+ xml_string.gsub('<', '&lt;')
32
34
  end
33
35
 
34
- def html(format = 'application/json', xml_options: nil)
35
- formatter = Rouge::Formatters::HTML.new
36
-
36
+ def html(format = 'application/json', xml_options: nil, theme_light: nil)
37
37
  case format
38
38
  when 'application/json'
39
- lexer = Rouge::Lexer.find('json')
40
- highlighted_response = formatter.format(lexer.lex(formatted_json))
39
+ language = 'json'
40
+ response = formatted_json
41
41
  when 'text/xml', 'application/xml'
42
- lexer = Rouge::Lexer.find('xml')
43
- highlighted_response = formatter.format(lexer.lex(formatted_xml(xml_options)))
42
+ language = 'xml'
43
+ response = formatted_xml(xml_options)
44
44
  end
45
45
 
46
46
  output = <<~HEREDOC
47
- <pre class="language-#{lexer && lexer.tag || 'json'} Vlt-prism--dark Vlt-prism--copy-disabled"><code>#{highlighted_response}</code></pre>
47
+ <pre class="pre-wrap language-#{language} #{theme_light ? 'Vlt-prism--dark' : ''} Vlt-prism--copy-disabled"><code>#{response}</code></pre>
48
48
  HEREDOC
49
49
 
50
50
  output
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Nexmo
2
4
  module OAS
3
5
  module Renderer
4
6
  module Helpers
5
7
  module Navigation
6
-
7
8
  HEADING_TAG_DEPTHS = {
8
9
  'h0' => 0,
9
10
  'h1' => 1,
@@ -58,7 +59,6 @@ module Nexmo
58
59
  def build_document(content)
59
60
  Nokogiri::HTML::DocumentFragment.parse(content)
60
61
  end
61
-
62
62
  end
63
63
  end
64
64
  end
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Nexmo
2
4
  module OAS
3
5
  module Renderer
4
6
  module Helpers
5
7
  module Render
6
-
7
8
  def find_template(views, name, engine, &block)
8
9
  Array(views).each do |v|
9
10
  super(v, name, engine, &block)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Nexmo
2
4
  module OAS
3
5
  module Renderer
@@ -17,9 +19,10 @@ module Nexmo
17
19
  operation_id = operation_id.gsub(/(_|-)/, ' ').titleize
18
20
 
19
21
  # Some terms need to be capitalised all the time
20
- uppercase_array = ['SMS', 'DTMF']
22
+ uppercase_array = %w[SMS DTMF]
21
23
  operation_id.split(' ').map do |c|
22
24
  next c.upcase if uppercase_array.include?(c.upcase)
25
+
23
26
  c
24
27
  end.join(' ')
25
28
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Nexmo
2
4
  module OAS
3
5
  module Renderer
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Nexmo
2
4
  module OAS
3
5
  module Renderer
4
6
  module Presenters
5
7
  class ApiSpecification
6
-
7
8
  def initialize(document_name:, code_language: nil)
8
9
  @document_name = document_name
9
10
  @code_language = code_language
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative './response_format'
2
4
 
3
5
  module Nexmo
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Nexmo
2
4
  module OAS
3
5
  module Renderer
@@ -12,6 +14,7 @@ module Nexmo
12
14
  # For now we only use the first tag in the list as an equivalent for the old x-group functionality
13
15
  @groups = @definition.endpoints.group_by do |endpoint|
14
16
  next nil unless tags
17
+
15
18
  endpoint.raw['tags']&.first
16
19
  end
17
20
 
@@ -25,6 +28,7 @@ module Nexmo
25
28
  # Sort by the order in which they're defined in the definition
26
29
  @groups = @groups.sort_by do |name, _|
27
30
  next -1 if name.nil?
31
+
28
32
  ordering[name.capitalize] || 999
29
33
  end
30
34
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../helpers/navigation'
2
4
 
3
5
  module Nexmo
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
2
4
  require_relative './endpoint'
3
5
  require_relative './response_format'
@@ -9,7 +11,6 @@ module Nexmo
9
11
  module OAS
10
12
  module Renderer
11
13
  module Presenters
12
-
13
14
  class OpenApiSpecification
14
15
  extend Forwardable
15
16
 
@@ -30,9 +31,11 @@ module Nexmo
30
31
  end
31
32
 
32
33
  def definition_errors
34
+ return unless errors?
35
+
33
36
  @definition_errors ||= Nexmo::Markdown::Renderer.new.call(
34
37
  File.read("#{API.oas_path}/../../errors/#{@definition_name}.md")
35
- ) if errors?
38
+ )
36
39
  end
37
40
 
38
41
  def definition
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nexmo
4
+ module OAS
5
+ module Renderer
6
+ module Presenters
7
+ class RequestBodyRaw
8
+ def initialize(parameters, options = {}, endpoint = nil)
9
+ @parameters = parameters
10
+ @options = options
11
+ @endpoint = endpoint
12
+ end
13
+
14
+ def to_format(format)
15
+ return to_urlencoded if format == 'application/x-www-form-urlencoded'
16
+
17
+ to_json
18
+ end
19
+
20
+ def to_urlencoded
21
+ example = ''
22
+ body = URI.encode_www_form(generate_request)
23
+ if @endpoint
24
+ servers = @endpoint.path.servers || @endpoint.definition.servers
25
+ path = @endpoint.path.path.gsub(/\{(.+?)\}/, ':\1')
26
+ uri = URI("#{servers[0]['url']}#{path}")
27
+ example += "#{@endpoint.method.upcase} #{uri.path} HTTP/1.1\n"
28
+ example += "Host: #{uri.host} \n"
29
+ example += "Content-Type: application/x-www-form-urlencoded\n"
30
+ example += "Content-Length: #{body.length}\n"
31
+ example += "\n"
32
+ end
33
+ example += body
34
+ example
35
+ end
36
+
37
+ def to_json(*_args)
38
+ JSON.pretty_generate(generate_request)
39
+ end
40
+
41
+ def generate_request(parameters = nil, options = nil)
42
+ parameters ||= @parameters
43
+ options ||= @options
44
+ output = {}
45
+
46
+ parameters.each do |parameter|
47
+ next if options['required_only'] && optional?(parameter, options['required'])
48
+
49
+ parameter_name = name(parameter)
50
+ param = parameter
51
+
52
+ # This is all required to handle an edge case where parameter.name is an OasParser::Property
53
+ # Which happens when you use a oneOf inside items in a property.
54
+ # I believe this is a bug, but it's a BC break in the parser
55
+
56
+ if parameter_name.instance_of?(OasParser::Property)
57
+ parameter_name = parameter.owner.name
58
+ param = OasParser::Parameter.new(parameter_name, parameter.schema)
59
+ end
60
+
61
+ if param.raw['items'] && param.raw['example']
62
+ output[parameter_name] = param.raw['example']
63
+ elsif param.raw['items'] && param.raw['items']['oneOf']
64
+ param = param.raw['items']['oneOf'][0]
65
+ output[parameter_name] = [generate_request(properties(param).map(&:name))]
66
+ elsif collection?(param) && properties?(param)
67
+ nested_output = generate_request(properties(param))
68
+ next unless nested_output.keys.length.positive?
69
+
70
+ nested_output = [nested_output] if param.array?
71
+ output[parameter_name] = nested_output
72
+ else
73
+ ex = example(param)
74
+ next unless ex
75
+
76
+ if ex.is_a?(String)
77
+ # Remove line breaks
78
+ ex = ex.gsub('<br />', ' ')
79
+ end
80
+ output[parameter_name] = ex
81
+ end
82
+ end
83
+ output
84
+ end
85
+
86
+ def items(parameter)
87
+ return parameter['items'] unless parameter.respond_to?(:items)
88
+
89
+ parameter.items
90
+ end
91
+
92
+ def example(parameter)
93
+ return parameter['example'] unless parameter.respond_to?(:example)
94
+
95
+ parameter.example
96
+ end
97
+
98
+ def name(parameter)
99
+ return parameter['name'] unless parameter.respond_to?(:name)
100
+
101
+ parameter.name
102
+ end
103
+
104
+ def properties(parameter)
105
+ return parameter['properties'] unless parameter.respond_to?(:properties)
106
+
107
+ parameter.properties
108
+ end
109
+
110
+ def array?(parameter)
111
+ return parameter['items'] unless parameter.respond_to?(:array?)
112
+
113
+ parameter.array?
114
+ end
115
+
116
+ def collection?(parameter)
117
+ return parameter['properties'] unless parameter.respond_to?(:collection?)
118
+
119
+ parameter.collection?
120
+ end
121
+
122
+ def properties?(parameter)
123
+ return parameter['properties'] unless parameter.respond_to?(:collection?)
124
+
125
+ parameter.properties.size.positive?
126
+ end
127
+
128
+ def optional?(parameter, allow_list)
129
+ return false if allow_list&.include?(name(parameter))
130
+
131
+ return false unless parameter.respond_to?(:required)
132
+
133
+ return false unless parameter.schema
134
+
135
+ !parameter.required
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end