nexmo-oas-renderer 0.7.1 → 0.8.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/Gemfile.lock +16 -7
  4. data/lib/nexmo/oas/renderer/app.rb +2 -4
  5. data/lib/nexmo/oas/renderer/presenters/api_specification.rb +1 -1
  6. data/lib/nexmo/oas/renderer/presenters/open_api_specification.rb +1 -1
  7. data/lib/nexmo/oas/renderer/public/assets/stylesheets/nexmo-oas-renderer.css +1 -1
  8. data/lib/nexmo/oas/renderer/version.rb +1 -1
  9. data/lib/nexmo/oas/renderer/views/open_api/_model.erb +1 -1
  10. data/lib/nexmo/oas/renderer/views/open_api/_parameter_groups.erb +7 -37
  11. data/lib/nexmo/oas/renderer/views/open_api/_tabbed_parameters.erb +53 -0
  12. data/nexmo-oas-renderer.gemspec +1 -0
  13. metadata +17 -53
  14. data/lib/nexmo/oas/renderer/filters/anchor.rb +0 -17
  15. data/lib/nexmo/oas/renderer/filters/audio.rb +0 -21
  16. data/lib/nexmo/oas/renderer/filters/block_escape.rb +0 -24
  17. data/lib/nexmo/oas/renderer/filters/break.rb +0 -13
  18. data/lib/nexmo/oas/renderer/filters/code.rb +0 -64
  19. data/lib/nexmo/oas/renderer/filters/code_snippet.rb +0 -194
  20. data/lib/nexmo/oas/renderer/filters/code_snippet_list.rb +0 -33
  21. data/lib/nexmo/oas/renderer/filters/code_snippets.rb +0 -158
  22. data/lib/nexmo/oas/renderer/filters/collapsible.rb +0 -27
  23. data/lib/nexmo/oas/renderer/filters/columns.rb +0 -50
  24. data/lib/nexmo/oas/renderer/filters/concept_list.rb +0 -33
  25. data/lib/nexmo/oas/renderer/filters/dynamic_content.rb +0 -30
  26. data/lib/nexmo/oas/renderer/filters/external_link.rb +0 -32
  27. data/lib/nexmo/oas/renderer/filters/frontmatter.rb +0 -14
  28. data/lib/nexmo/oas/renderer/filters/heading.rb +0 -61
  29. data/lib/nexmo/oas/renderer/filters/icon.rb +0 -22
  30. data/lib/nexmo/oas/renderer/filters/indent.rb +0 -20
  31. data/lib/nexmo/oas/renderer/filters/inline_escape.rb +0 -17
  32. data/lib/nexmo/oas/renderer/filters/js_sequence_diagram.rb +0 -21
  33. data/lib/nexmo/oas/renderer/filters/label.rb +0 -32
  34. data/lib/nexmo/oas/renderer/filters/language.rb +0 -15
  35. data/lib/nexmo/oas/renderer/filters/markdown.rb +0 -85
  36. data/lib/nexmo/oas/renderer/filters/modal.rb +0 -41
  37. data/lib/nexmo/oas/renderer/filters/partial.rb +0 -28
  38. data/lib/nexmo/oas/renderer/filters/php_inliner.rb +0 -15
  39. data/lib/nexmo/oas/renderer/filters/screenshot.rb +0 -26
  40. data/lib/nexmo/oas/renderer/filters/tab.rb +0 -250
  41. data/lib/nexmo/oas/renderer/filters/techio.rb +0 -24
  42. data/lib/nexmo/oas/renderer/filters/tooltip.rb +0 -22
  43. data/lib/nexmo/oas/renderer/filters/tutorial_link.rb +0 -27
  44. data/lib/nexmo/oas/renderer/filters/tutorials.rb +0 -28
  45. data/lib/nexmo/oas/renderer/filters/unfreeze.rb +0 -20
  46. data/lib/nexmo/oas/renderer/filters/user_personalization.rb +0 -43
  47. data/lib/nexmo/oas/renderer/lib/core_ext/string.rb +0 -14
  48. data/lib/nexmo/oas/renderer/lib/redcarpet.rb +0 -14
  49. data/lib/nexmo/oas/renderer/models/code_snippet.rb +0 -75
  50. data/lib/nexmo/oas/renderer/models/tutorial.rb +0 -83
  51. data/lib/nexmo/oas/renderer/pipelines/markdown_pipeline.rb +0 -52
  52. data/lib/nexmo/oas/renderer/services/code_language_api.rb +0 -98
  53. data/lib/nexmo/oas/renderer/views/code_snippets/_application_messages_dispatch.html.erb +0 -9
  54. data/lib/nexmo/oas/renderer/views/code_snippets/_application_rtc.html.erb +0 -41
  55. data/lib/nexmo/oas/renderer/views/code_snippets/_application_voice.html.erb +0 -24
  56. data/lib/nexmo/oas/renderer/views/code_snippets/_code_only.html.erb +0 -6
  57. data/lib/nexmo/oas/renderer/views/code_snippets/_configure_client.html.erb +0 -20
  58. data/lib/nexmo/oas/renderer/views/code_snippets/_dependencies.html.erb +0 -11
  59. data/lib/nexmo/oas/renderer/views/code_snippets/_write_code.html.erb +0 -13
  60. data/lib/nexmo/oas/renderer/views/code_snippets/list/plain.html.erb +0 -10
  61. data/lib/nexmo/oas/renderer/views/tutorials/_index.html.erb +0 -32
  62. data/lib/nexmo/oas/renderer/views/tutorials/index.html.erb +0 -7
  63. data/lib/nexmo/oas/renderer/views/tutorials/list/plain.html.erb +0 -5
  64. data/lib/nexmo/oas/renderer/views/tutorials/show.html.erb +0 -8
@@ -1,13 +0,0 @@
1
- module Nexmo
2
- module OAS
3
- module Renderer
4
- module Filters
5
- class Break < Banzai::Filter
6
- def call(input)
7
- input.gsub('§', '<br>')
8
- end
9
- end
10
- end
11
- end
12
- end
13
- end
@@ -1,64 +0,0 @@
1
- module Nexmo
2
- module OAS
3
- module Renderer
4
- module Filters
5
- class Code < Banzai::Filter
6
- def call(input)
7
- input.gsub(/(?!.*snippet)```code(.+?)```/m) do |_s|
8
- config = YAML.safe_load($1)
9
-
10
- if config['config']
11
- configs = YAML.load_file("#{API.root}/config/code_examples.yml")
12
- config = config['config'].split('.').inject(configs) { |h, k| h[k] }
13
- end
14
-
15
- code = File.read("#{API.root}/#{config['source']}")
16
- language = File.extname("#{API.root}/#{config['source']}")[1..-1]
17
- lexer = language_to_lexer(language)
18
-
19
- total_lines = code.lines.count
20
-
21
- # Minus one since lines are not zero-indexed
22
- from_line = (config['from_line'] || 1) - 1
23
- to_line = (config['to_line'] || total_lines) - 1
24
-
25
- code = code.lines[from_line..to_line].join
26
- code.unindent! if config['unindent']
27
-
28
- highlighted_source = highlight(code, lexer)
29
-
30
- <<~HEREDOC
31
- <pre class="highlight #{lexer.tag}"><code>#{highlighted_source}</code></pre>
32
- HEREDOC
33
- end
34
- end
35
-
36
- private
37
-
38
- def highlight(source, lexer)
39
- formatter = Rouge::Formatters::HTML.new
40
- formatter.format(lexer.lex(source))
41
- end
42
-
43
- def language_to_lexer_name(language)
44
- if language_configuration[language]
45
- language_configuration[language]['lexer']
46
- else
47
- language
48
- end
49
- end
50
-
51
- def language_to_lexer(language)
52
- language = language_to_lexer_name(language)
53
- return Rouge::Lexers::PHP.new({ start_inline: true }) if language == 'php'
54
- Rouge::Lexer.find(language.downcase) || Rouge::Lexer.find('text')
55
- end
56
-
57
- def language_configuration
58
- @language_configuration ||= YAML.load_file("#{API.root}/config/code_languages.yml")
59
- end
60
- end
61
- end
62
- end
63
- end
64
- end
@@ -1,194 +0,0 @@
1
- require 'octicons_helper'
2
-
3
- module Nexmo
4
- module OAS
5
- module Renderer
6
- module Filters
7
- class CodeSnippet < Banzai::Filter
8
- include OcticonsHelper
9
-
10
- def call(input)
11
- input.gsub(/```single_code_snippet(.+?)```/m) do |_s|
12
- config = YAML.safe_load($1)
13
-
14
- @renderer = get_renderer(config['language'])
15
-
16
- lexer = CodeLanguageAPI.find(config['language']).lexer
17
- lang = config['title'].delete('.')
18
-
19
- application_html = generate_application_block(config['application'])
20
-
21
- # Read the client
22
- if config['client']
23
- highlighted_client_source = generate_code_block(config['language'], config['client'], config['unindent'])
24
- end
25
-
26
- # Read the code
27
- highlighted_code_source = generate_code_block(config['language'], config['code'], config['unindent'])
28
-
29
- dependency_html = ''
30
- if config['dependencies']
31
- dependency_html = generate_dependencies(lexer.tag, config['dependencies'])
32
- end
33
-
34
- source_url = generate_source_url(config['code'])
35
-
36
- client_html = ''
37
- if highlighted_client_source
38
- client_url = generate_source_url(config['client'])
39
- id = SecureRandom.hex
40
- create_instructions = @renderer.create_instructions(config['file_name']).render_markdown
41
- erb = File.read("#{API.root}/views/code_snippets/_configure_client.html.erb")
42
- client_html = ERB.new(erb).result(binding)
43
- end
44
-
45
- add_instructions = @renderer.add_instructions(config['file_name']).render_markdown
46
- if config['code_only']
47
- erb = File.read("#{API.root}/views/code_snippets/_code_only.html.erb")
48
- else
49
- erb = File.read("#{API.root}/views/code_snippets/_write_code.html.erb")
50
- end
51
-
52
- code_html = ERB.new(erb).result(binding)
53
-
54
- return code_html if config['code_only']
55
-
56
- config['run_command'] = config['run_command'].gsub('{filename}', config['file_name']) if config['run_command']
57
- run_html = @renderer.run_command(config['run_command'], config['file_name'], config['code']['source']).to_s
58
-
59
- prereqs = (application_html + dependency_html + client_html).strip
60
- prereqs = "<h2>Prerequisites</h2>#{prereqs}" unless prereqs.empty?
61
- prereqs + code_html + run_html
62
- end
63
- end
64
-
65
- private
66
-
67
- def highlight(source, lexer)
68
- formatter = Rouge::Formatters::HTML.new
69
- formatter.format(lexer.lex(source))
70
- end
71
-
72
- def generate_code_block(language, input, unindent)
73
- filename = input['source']
74
- return '' unless input
75
- raise "CodeSnippetFilter - Could not load #{filename} for language #{language}" unless File.exist?(filename)
76
-
77
- code = File.read(filename)
78
- lexer = CodeLanguageAPI.find(language).lexer
79
-
80
- total_lines = code.lines.count
81
-
82
- # Minus one since lines are not zero-indexed
83
- from_line = (input['from_line'] || 1) - 1
84
- to_line = (input['to_line'] || total_lines) - 1
85
-
86
- code = code.lines[from_line..to_line].join
87
- code.unindent! if unindent
88
-
89
- highlight(code, lexer)
90
- end
91
-
92
- def get_renderer(language)
93
- language = 'dotnet' if language == 'csharp'
94
- case language
95
- when 'curl'
96
- CodeSnippetRenderer::Curl
97
- when 'node'
98
- CodeSnippetRenderer::Javascript
99
- when 'javascript'
100
- CodeSnippetRenderer::Javascript
101
- when 'java'
102
- CodeSnippetRenderer::Java
103
- when 'dotnet'
104
- CodeSnippetRenderer::Dotnet
105
- when 'python'
106
- CodeSnippetRenderer::Python
107
- when 'ruby'
108
- CodeSnippetRenderer::Ruby
109
- when 'php'
110
- CodeSnippetRenderer::Php
111
- when 'android'
112
- CodeSnippetRenderer::Android
113
- when 'kotlin'
114
- CodeSnippetRenderer::Kotlin
115
- when 'objective_c'
116
- CodeSnippetRenderer::ObjectiveC
117
- when 'swift'
118
- CodeSnippetRenderer::Swift
119
- else
120
- raise "Unknown language: #{language}"
121
- end
122
- end
123
-
124
- def generate_dependencies(language, dependencies)
125
- # The only valid dependency for curl examples is `JWT`
126
- dependencies = dependencies.map(&:upcase)
127
- if dependencies.include?('JWT')
128
- title = 'Generate your JWT'
129
- else
130
- title = 'Install dependencies'
131
- end
132
- deps = @renderer.dependencies(dependencies)
133
- id = SecureRandom.hex
134
- erb = File.read("#{API.root}/views/code_snippets/_dependencies.html.erb")
135
- ERB.new(erb).result(binding)
136
- end
137
-
138
- def generate_application_block(app)
139
- return '' unless app
140
-
141
- base_url = 'http://demo.ngrok.io'
142
- base_url = 'https://example.com' if app['disable_ngrok']
143
-
144
- app['name'] = 'ExampleProject' unless app['name']
145
-
146
- # We should remove this default once we're sure that all Code Snippets
147
- # have a type set e.g audit
148
- app['type'] ||= 'voice'
149
-
150
- if ['voice', 'rtc'].include? app['type']
151
- app['event_url'] = "#{base_url}/webhooks/events" unless app['event_url']
152
- app['answer_url'] = "#{base_url}/webhooks/answer" unless app['answer_url']
153
- erb = File.read("#{API.root}/views/code_snippets/_application_#{app['type']}.html.erb")
154
- elsif ['messages', 'dispatch'].include? app['type']
155
- erb = File.read("#{API.root}/views/code_snippets/_application_messages_dispatch.html.erb")
156
- else
157
- raise "Invalid application type when creating code snippet: '#{app['type']}'"
158
- end
159
-
160
- id = SecureRandom.hex
161
-
162
- ERB.new(erb).result(binding)
163
- end
164
-
165
- def generate_source_url(code)
166
- # Source example: .repos/nexmo/nexmo-java-code-snippets/ExampleClass.java
167
- # Direct link on GitHub is in form https://github.com/nexmo/nexmo-java-code-snippets/blob/master/ExampleClass.java
168
- start_section = 'https://github.com'
169
-
170
- # Insert "blob/master" and strip ".repos" - except dotnet that needs "blob/ASPNET" instead
171
- repo_path = '\\0blob/master/'
172
- repo_path = '\\0blob/ASPNET/' if code['source'].include?('dotnet')
173
- file_section = code['source'].sub('.repos', '').sub(%r{(-quickstart|-code-snippets|-code-snippets)/}, repo_path)
174
-
175
- # Line highlighting
176
- line_section = ''
177
- if code['from_line']
178
- line_section += "#L#{code['from_line']}"
179
- if code['to_line']
180
- # If we've provided a to_line, use that
181
- line_section += "-L#{code['to_line']}" if code['to_line']
182
- else
183
- # By default we read to the end of the file
184
- line_section += "-L#{File.read(code['source']).lines.count}"
185
- end
186
- end
187
-
188
- start_section + file_section + line_section
189
- end
190
- end
191
- end
192
- end
193
- end
194
- end
@@ -1,33 +0,0 @@
1
- require 'yaml'
2
- require 'banzai'
3
- require_relative '../models/code_snippet'
4
-
5
- module Nexmo
6
- module OAS
7
- module Renderer
8
- module Filters
9
- class CodeSnippetList < Banzai::Filter
10
- def call(input)
11
- input.gsub(/```code_snippet_list(.+?)```/m) do |_s|
12
- config = YAML.safe_load($1)
13
- @product = config['product']
14
- @blocks = Models::CodeSnippet.by_product(@product)
15
-
16
- # Top level blocks come before subfolder
17
- @blocks.sort_by! do |b|
18
- sort_array = []
19
- sort_array << (b.category ? 1 : 0)
20
- sort_array << b.navigation_weight
21
- sort_array
22
- end
23
-
24
- erb = File.read("#{API.root}/views/code_snippets/list/plain.html.erb")
25
- html = ERB.new(erb).result(binding)
26
- "FREEZESTART#{Base64.urlsafe_encode64(html)}FREEZEEND"
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,158 +0,0 @@
1
- module Nexmo
2
- module OAS
3
- module Renderer
4
- module Filters
5
- class CodeSnippets < Banzai::Filter
6
- def call(input)
7
- input.gsub(/^(\s*)```code_snippets(.+?)```/m) do |_s|
8
- @indentation = $1
9
- @config = YAML.safe_load($2)
10
- validate_config
11
- html
12
- end
13
- end
14
-
15
- private
16
-
17
- def create_tabs(content)
18
- tab = Nokogiri::XML::Element.new 'li', @document
19
- tab['class'] = 'Vlt-tabs__link'
20
- tab['class'] += ' Vlt-tabs__link_active' if content[:active]
21
- tab['aria-selected'] = 'true' if content[:active]
22
-
23
- if content['language']
24
- tab['data-language'] = content['language']
25
- tab['data-language-type'] = content['language_type']
26
- tab['data-language-linkable'] = true
27
- end
28
-
29
- tab_link = Nokogiri::XML::Element.new 'a', @document
30
- tab_link.inner_html = "<svg><use xlink:href=\"/assets/images/brands/#{content['icon']}.svg##{content['icon']}\" /></svg><span>" + content['title'] + '</span>'
31
- tab_link['class'] = 'tab-link'
32
-
33
- tab.add_child(tab_link)
34
- @tabs.add_child(tab)
35
- end
36
-
37
- def create_content(content)
38
- element = Nokogiri::XML::Element.new 'div', @document
39
- element['id'] = content['id']
40
- element['class'] = 'Vlt-tabs__panel'
41
- element['class'] += ' Vlt-tabs__panel_active' if content[:active]
42
- element.inner_html = content[:body]
43
-
44
- @tabs_content.add_child(element)
45
- end
46
-
47
- def html
48
- html = <<~HEREDOC
49
- <div class="Vlt-tabs">
50
- <div class="Vlt-tabs__header--bordered"></div>
51
- <div class="Vlt-tabs__content"></div>
52
- </div>
53
- HEREDOC
54
-
55
- @document = Nokogiri::HTML::DocumentFragment.parse(html)
56
- @tabs = @document.at_css('.Vlt-tabs__header--bordered')
57
- @tabs_content = @document.at_css('.Vlt-tabs__content')
58
-
59
- contents.each do |content|
60
- create_tabs(content)
61
- create_content(content)
62
- end
63
-
64
- source = @document.to_html
65
-
66
- "#{@indentation}FREEZESTART#{Base64.urlsafe_encode64(source)}FREEZEEND"
67
- end
68
-
69
- def contents
70
- list = content_from_source
71
- list ||= []
72
-
73
- return list unless list.any?
74
-
75
- list = sort_contents(list)
76
- resolve_active_tab(list)
77
-
78
- list
79
- end
80
-
81
- def validate_config
82
- return if @config && @config['source']
83
- raise 'A source key must be present in this building_blocks config'
84
- end
85
-
86
- def content_from_source
87
- source_path = "#{@config['source']}/*.yml"
88
-
89
- files = Dir[source_path]
90
- raise "No .yml files found for #{@config['source']} code snippets" if files.empty?
91
-
92
- files.map do |content_path|
93
- source = File.read(content_path)
94
-
95
- # Load the defaults for this language
96
- filename = File.basename(content_path, '.yml')
97
- defaults = CodeLanguageAPI.find(filename)
98
-
99
- content = YAML.safe_load(source)
100
- content['source'] = source
101
- content['id'] = SecureRandom.hex
102
- content['title'] ||= defaults.label
103
- content['language'] ||= defaults.key
104
- content['language_type'] ||= defaults.type
105
- content['dependencies'] ||= defaults.dependencies
106
- content['icon'] = defaults.icon
107
- content['weight'] ||= defaults.weight
108
- content['run_command'] ||= defaults.run_command
109
- content['unindent'] = defaults.unindent || false
110
-
111
- # If we don't have a file_name in config, use the one in the repo
112
- content['file_name'] ||= File.basename(content['code']['source'])
113
-
114
- parent_config = { 'code_only' => @config['code_only'], 'source' => @config['source'].gsub('_examples/', '') }
115
- if @config['application']
116
- parent_config = parent_config.merge({ 'application' => @config['application'] })
117
- end
118
-
119
- parent_config = parent_config.to_yaml.lines[1..-1].join
120
-
121
- source = <<~HEREDOC
122
- ```single_code_snippet
123
- #{content.to_yaml}\n#{parent_config}
124
- ```
125
- HEREDOC
126
-
127
- content[:body] = MarkdownPipeline.new(options).call(source)
128
-
129
- content
130
- end
131
- end
132
-
133
- def sort_contents(contents)
134
- contents.sort_by do |content|
135
- content['weight']
136
- end
137
- end
138
-
139
- def resolve_active_tab(contents)
140
- active_index = nil
141
-
142
- if options[:code_language]
143
- contents.each_with_index do |content, index|
144
- active_index = index if content['language'] == options[:code_language].key
145
- end
146
- end
147
-
148
- @tabs['data-has-initial-tab'] = active_index.present?
149
- @tabs['class'] += ' skip-pushstate' if @tabs['data-has-initial-tab']
150
- active_index ||= 0
151
-
152
- contents[active_index][:active] = true
153
- end
154
- end
155
- end
156
- end
157
- end
158
- end