nexmo-oas-renderer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +1 -0
  3. data/.gitignore +5 -0
  4. data/CHANGELOG.md +2 -0
  5. data/CONTRIBUTING.md +46 -0
  6. data/Gemfile +4 -0
  7. data/Gemfile.lock +183 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +73 -0
  10. data/Rakefile +2 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/exe/nexmo-oas-renderer +5 -0
  14. data/lib/nexmo/oas/engine.rb +9 -0
  15. data/lib/nexmo/oas/renderer.rb +13 -0
  16. data/lib/nexmo/oas/renderer/app.rb +116 -0
  17. data/lib/nexmo/oas/renderer/config.ru +7 -0
  18. data/lib/nexmo/oas/renderer/config/code_languages.yml +138 -0
  19. data/lib/nexmo/oas/renderer/config/dynamic_content.yml +1 -0
  20. data/lib/nexmo/oas/renderer/config/redirects.yml +8 -0
  21. data/lib/nexmo/oas/renderer/constraints/open_api.rb +76 -0
  22. data/lib/nexmo/oas/renderer/constraints/redirector.rb +17 -0
  23. data/lib/nexmo/oas/renderer/decorators/response_parser_decorator.rb +55 -0
  24. data/lib/nexmo/oas/renderer/filters/anchor.rb +17 -0
  25. data/lib/nexmo/oas/renderer/filters/audio.rb +21 -0
  26. data/lib/nexmo/oas/renderer/filters/block_escape.rb +24 -0
  27. data/lib/nexmo/oas/renderer/filters/break.rb +13 -0
  28. data/lib/nexmo/oas/renderer/filters/code.rb +64 -0
  29. data/lib/nexmo/oas/renderer/filters/code_snippet.rb +194 -0
  30. data/lib/nexmo/oas/renderer/filters/code_snippet_list.rb +33 -0
  31. data/lib/nexmo/oas/renderer/filters/code_snippets.rb +158 -0
  32. data/lib/nexmo/oas/renderer/filters/collapsible.rb +27 -0
  33. data/lib/nexmo/oas/renderer/filters/columns.rb +50 -0
  34. data/lib/nexmo/oas/renderer/filters/concept_list.rb +33 -0
  35. data/lib/nexmo/oas/renderer/filters/dynamic_content.rb +30 -0
  36. data/lib/nexmo/oas/renderer/filters/external_link.rb +32 -0
  37. data/lib/nexmo/oas/renderer/filters/frontmatter.rb +14 -0
  38. data/lib/nexmo/oas/renderer/filters/heading.rb +61 -0
  39. data/lib/nexmo/oas/renderer/filters/icon.rb +22 -0
  40. data/lib/nexmo/oas/renderer/filters/indent.rb +20 -0
  41. data/lib/nexmo/oas/renderer/filters/inline_escape.rb +17 -0
  42. data/lib/nexmo/oas/renderer/filters/js_sequence_diagram.rb +21 -0
  43. data/lib/nexmo/oas/renderer/filters/label.rb +32 -0
  44. data/lib/nexmo/oas/renderer/filters/language.rb +15 -0
  45. data/lib/nexmo/oas/renderer/filters/markdown.rb +85 -0
  46. data/lib/nexmo/oas/renderer/filters/modal.rb +41 -0
  47. data/lib/nexmo/oas/renderer/filters/partial.rb +28 -0
  48. data/lib/nexmo/oas/renderer/filters/php_inliner.rb +15 -0
  49. data/lib/nexmo/oas/renderer/filters/screenshot.rb +26 -0
  50. data/lib/nexmo/oas/renderer/filters/tab.rb +250 -0
  51. data/lib/nexmo/oas/renderer/filters/techio.rb +24 -0
  52. data/lib/nexmo/oas/renderer/filters/tooltip.rb +22 -0
  53. data/lib/nexmo/oas/renderer/filters/tutorial_link.rb +27 -0
  54. data/lib/nexmo/oas/renderer/filters/tutorials.rb +28 -0
  55. data/lib/nexmo/oas/renderer/filters/unfreeze.rb +20 -0
  56. data/lib/nexmo/oas/renderer/filters/user_personalization.rb +43 -0
  57. data/lib/nexmo/oas/renderer/helpers/navigation.rb +66 -0
  58. data/lib/nexmo/oas/renderer/helpers/render.rb +24 -0
  59. data/lib/nexmo/oas/renderer/helpers/summary.rb +30 -0
  60. data/lib/nexmo/oas/renderer/helpers/url.rb +17 -0
  61. data/lib/nexmo/oas/renderer/lib/core_ext/string.rb +14 -0
  62. data/lib/nexmo/oas/renderer/lib/redcarpet.rb +14 -0
  63. data/lib/nexmo/oas/renderer/models/code_snippet.rb +75 -0
  64. data/lib/nexmo/oas/renderer/models/tutorial.rb +83 -0
  65. data/lib/nexmo/oas/renderer/pipelines/markdown_pipeline.rb +52 -0
  66. data/lib/nexmo/oas/renderer/presenters/api_specification.rb +42 -0
  67. data/lib/nexmo/oas/renderer/presenters/groups.rb +35 -0
  68. data/lib/nexmo/oas/renderer/presenters/navigation.rb +24 -0
  69. data/lib/nexmo/oas/renderer/presenters/open_api_specification.rb +68 -0
  70. data/lib/nexmo/oas/renderer/presenters/versions.rb +40 -0
  71. data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Black.woff +0 -0
  72. data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Black.woff2 +0 -0
  73. data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Heavy.woff +0 -0
  74. data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Heavy.woff2 +0 -0
  75. data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Regular.woff +0 -0
  76. data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Regular.woff2 +0 -0
  77. data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Semibold.woff +0 -0
  78. data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Semibold.woff2 +0 -0
  79. data/lib/nexmo/oas/renderer/public/assets/images/brands/android.svg +1 -0
  80. data/lib/nexmo/oas/renderer/public/assets/images/brands/curl.svg +1 -0
  81. data/lib/nexmo/oas/renderer/public/assets/images/brands/dotnet.svg +1 -0
  82. data/lib/nexmo/oas/renderer/public/assets/images/brands/ios.svg +1 -0
  83. data/lib/nexmo/oas/renderer/public/assets/images/brands/java.svg +1 -0
  84. data/lib/nexmo/oas/renderer/public/assets/images/brands/javascript.svg +1 -0
  85. data/lib/nexmo/oas/renderer/public/assets/images/brands/node.svg +1 -0
  86. data/lib/nexmo/oas/renderer/public/assets/images/brands/php.svg +1 -0
  87. data/lib/nexmo/oas/renderer/public/assets/images/brands/python.svg +11 -0
  88. data/lib/nexmo/oas/renderer/public/assets/images/brands/ruby.svg +1 -0
  89. data/lib/nexmo/oas/renderer/public/assets/images/lost.svg +37 -0
  90. data/lib/nexmo/oas/renderer/public/assets/javascripts/components/format.js +42 -0
  91. data/lib/nexmo/oas/renderer/public/assets/javascripts/volta.accordion.js +249 -0
  92. data/lib/nexmo/oas/renderer/public/assets/javascripts/volta.core.js +230 -0
  93. data/lib/nexmo/oas/renderer/public/assets/javascripts/volta.modal.js +300 -0
  94. data/lib/nexmo/oas/renderer/public/assets/javascripts/volta.tabs.js +139 -0
  95. data/lib/nexmo/oas/renderer/public/assets/stylesheets/api.css +95 -0
  96. data/lib/nexmo/oas/renderer/public/assets/stylesheets/buttons.css +80 -0
  97. data/lib/nexmo/oas/renderer/public/assets/stylesheets/core.css +79 -0
  98. data/lib/nexmo/oas/renderer/public/assets/stylesheets/mediaqueries.css +2 -0
  99. data/lib/nexmo/oas/renderer/public/assets/stylesheets/mediaqueries.css.map +7 -0
  100. data/lib/nexmo/oas/renderer/public/assets/stylesheets/navigation.css +79 -0
  101. data/lib/nexmo/oas/renderer/public/assets/stylesheets/nexmo.css +68 -0
  102. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/api.scss +147 -0
  103. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/core.scss +133 -0
  104. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/mediaqueries.scss +48 -0
  105. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/navigation.scss +106 -0
  106. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/nexmo.scss +61 -0
  107. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/style.scss +10 -0
  108. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/syntax.scss +63 -0
  109. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/typography.scss +248 -0
  110. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/variables.scss +91 -0
  111. data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/volta-templates.scss +119 -0
  112. data/lib/nexmo/oas/renderer/public/assets/stylesheets/style.css +2 -0
  113. data/lib/nexmo/oas/renderer/public/assets/stylesheets/style.css.map +7 -0
  114. data/lib/nexmo/oas/renderer/public/assets/stylesheets/syntax.css +79 -0
  115. data/lib/nexmo/oas/renderer/public/assets/stylesheets/typography.css +86 -0
  116. data/lib/nexmo/oas/renderer/public/assets/stylesheets/variables.css +2 -0
  117. data/lib/nexmo/oas/renderer/public/assets/stylesheets/variables.css.map +7 -0
  118. data/lib/nexmo/oas/renderer/public/assets/stylesheets/volta-templates.css +2 -0
  119. data/lib/nexmo/oas/renderer/public/assets/stylesheets/volta-templates.css.map +7 -0
  120. data/lib/nexmo/oas/renderer/public/assets/stylesheets/volta.min.css +1 -0
  121. data/lib/nexmo/oas/renderer/public/assets/symbol/volta-icons.svg +1 -0
  122. data/lib/nexmo/oas/renderer/public/favicon.ico +0 -0
  123. data/lib/nexmo/oas/renderer/services/code_language_api.rb +98 -0
  124. data/lib/nexmo/oas/renderer/services/oas_parser.rb +21 -0
  125. data/lib/nexmo/oas/renderer/services/open_api_definition_resolver.rb +33 -0
  126. data/lib/nexmo/oas/renderer/version.rb +7 -0
  127. data/lib/nexmo/oas/renderer/views/api/show.erb +1 -0
  128. data/lib/nexmo/oas/renderer/views/code_snippets/_application_messages_dispatch.html.erb +9 -0
  129. data/lib/nexmo/oas/renderer/views/code_snippets/_application_rtc.html.erb +41 -0
  130. data/lib/nexmo/oas/renderer/views/code_snippets/_application_voice.html.erb +24 -0
  131. data/lib/nexmo/oas/renderer/views/code_snippets/_code_only.html.erb +6 -0
  132. data/lib/nexmo/oas/renderer/views/code_snippets/_configure_client.html.erb +20 -0
  133. data/lib/nexmo/oas/renderer/views/code_snippets/_dependencies.html.erb +11 -0
  134. data/lib/nexmo/oas/renderer/views/code_snippets/_write_code.html.erb +13 -0
  135. data/lib/nexmo/oas/renderer/views/code_snippets/list/plain.html.erb +10 -0
  136. data/lib/nexmo/oas/renderer/views/concepts/list/plain.html.erb +5 -0
  137. data/lib/nexmo/oas/renderer/views/layouts/_head.erb +4 -0
  138. data/lib/nexmo/oas/renderer/views/layouts/_javascripts.erb +9 -0
  139. data/lib/nexmo/oas/renderer/views/layouts/api.erb +23 -0
  140. data/lib/nexmo/oas/renderer/views/layouts/open_api.erb +10 -0
  141. data/lib/nexmo/oas/renderer/views/open_api/_callback.erb +5 -0
  142. data/lib/nexmo/oas/renderer/views/open_api/_callback_endpoint.erb +48 -0
  143. data/lib/nexmo/oas/renderer/views/open_api/_code_examples.erb +16 -0
  144. data/lib/nexmo/oas/renderer/views/open_api/_endpoint.erb +156 -0
  145. data/lib/nexmo/oas/renderer/views/open_api/_model.erb +38 -0
  146. data/lib/nexmo/oas/renderer/views/open_api/_navigation.erb +80 -0
  147. data/lib/nexmo/oas/renderer/views/open_api/_parameter_groups.erb +50 -0
  148. data/lib/nexmo/oas/renderer/views/open_api/_parameters.erb +165 -0
  149. data/lib/nexmo/oas/renderer/views/open_api/_response_description_parameters.erb +61 -0
  150. data/lib/nexmo/oas/renderer/views/open_api/_response_descriptions.erb +41 -0
  151. data/lib/nexmo/oas/renderer/views/open_api/show.erb +104 -0
  152. data/lib/nexmo/oas/renderer/views/static/404.erb +6 -0
  153. data/lib/nexmo/oas/renderer/views/tutorials/_index.html.erb +32 -0
  154. data/lib/nexmo/oas/renderer/views/tutorials/index.html.erb +7 -0
  155. data/lib/nexmo/oas/renderer/views/tutorials/list/plain.html.erb +5 -0
  156. data/lib/nexmo/oas/renderer/views/tutorials/show.html.erb +8 -0
  157. data/nexmo-oas-renderer.gemspec +49 -0
  158. metadata +399 -0
@@ -0,0 +1,194 @@
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
@@ -0,0 +1,33 @@
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
@@ -0,0 +1,158 @@
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
@@ -0,0 +1,27 @@
1
+ module Nexmo
2
+ module OAS
3
+ module Renderer
4
+ module Filters
5
+ class Collapsible < Banzai::Filter
6
+ def call(input)
7
+ input.gsub(/^\|\s(\#{1,6})(\s)?(.+?)\n^\|\n(.+?)\n\n/m) do |_s|
8
+ heading = $3
9
+ body = $4.gsub(/^\|\n/, "\n")
10
+ body = body.gsub(/^\|\s/, '')
11
+ parsed_body = MarkdownPipeline.new.call(body)
12
+
13
+ <<~HEREDOC
14
+ <div class="Vlt-accordion Vlt-box Vlt-box--lesspadding Nxd-accordion-emphasis">
15
+ <h5 class="Vlt-accordion__trigger" tabindex="0">#{heading}</h5>
16
+ <div class="Vlt-accordion__content Vlt-accordion__content--noborder">
17
+ #{parsed_body}
18
+ </div>
19
+ </div>
20
+ HEREDOC
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,50 @@
1
+ module Nexmo
2
+ module OAS
3
+ module Renderer
4
+ module Filters
5
+ class Columns < Banzai::Filter
6
+ def call(input)
7
+ input.gsub!(%r{{column\:([1-4])\/([1-4])}\n(.+?){end}}m) do
8
+ s = []
9
+ s << row_start if $1 == '1'
10
+ s << column_start($2)
11
+ s << $3
12
+ s << column_end
13
+ s << row_end if $1 == $2
14
+ s.join('')
15
+ end
16
+
17
+ input
18
+ end
19
+
20
+ private
21
+
22
+ def row_start
23
+ "FREEZESTART#{Base64.urlsafe_encode64('<div class="row">')}FREEZEEND\n"
24
+ end
25
+
26
+ def row_end
27
+ close_tag
28
+ end
29
+
30
+ def close_tag
31
+ "FREEZESTART#{Base64.urlsafe_encode64('</div>')}FREEZEEND"
32
+ end
33
+
34
+ def column_start(columns)
35
+ html = "<div class='column small-12 medium-#{part_size(columns)}'>"
36
+ "FREEZESTART#{Base64.urlsafe_encode64(html)}FREEZEEND\n"
37
+ end
38
+
39
+ def column_end
40
+ "FREEZESTART#{Base64.urlsafe_encode64('</div>')}FREEZEEND\n"
41
+ end
42
+
43
+ def part_size(columns)
44
+ 12 / Integer(columns)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end