nexmo_markdown_renderer 0.0.2

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 (79) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +54 -0
  4. data/config/code_languages.yml +138 -0
  5. data/config/dynamic_content.yml +1 -0
  6. data/config/locales/en.yml +176 -0
  7. data/lib/nexmo_markdown_renderer.rb +28 -0
  8. data/lib/nexmo_markdown_renderer/core_ext/string.rb +14 -0
  9. data/lib/nexmo_markdown_renderer/filters/anchor_filter.rb +14 -0
  10. data/lib/nexmo_markdown_renderer/filters/audio_filter.rb +18 -0
  11. data/lib/nexmo_markdown_renderer/filters/block_escape_filter.rb +21 -0
  12. data/lib/nexmo_markdown_renderer/filters/break_filter.rb +10 -0
  13. data/lib/nexmo_markdown_renderer/filters/code_filter.rb +62 -0
  14. data/lib/nexmo_markdown_renderer/filters/code_snippet_filter.rb +187 -0
  15. data/lib/nexmo_markdown_renderer/filters/code_snippet_list_filter.rb +26 -0
  16. data/lib/nexmo_markdown_renderer/filters/code_snippets_filter.rb +170 -0
  17. data/lib/nexmo_markdown_renderer/filters/collapsible_filter.rb +27 -0
  18. data/lib/nexmo_markdown_renderer/filters/columns_filter.rb +47 -0
  19. data/lib/nexmo_markdown_renderer/filters/concept_list_filter.rb +30 -0
  20. data/lib/nexmo_markdown_renderer/filters/dynamic_content_filter.rb +28 -0
  21. data/lib/nexmo_markdown_renderer/filters/external_link_filter.rb +29 -0
  22. data/lib/nexmo_markdown_renderer/filters/frontmatter_filter.rb +11 -0
  23. data/lib/nexmo_markdown_renderer/filters/heading_filter.rb +57 -0
  24. data/lib/nexmo_markdown_renderer/filters/i18n/frontmatter_filter.rb +16 -0
  25. data/lib/nexmo_markdown_renderer/filters/i18n/smartling_converter_filter.rb +22 -0
  26. data/lib/nexmo_markdown_renderer/filters/icon_filter.rb +19 -0
  27. data/lib/nexmo_markdown_renderer/filters/indent_filter.rb +17 -0
  28. data/lib/nexmo_markdown_renderer/filters/inline_escape_filter.rb +14 -0
  29. data/lib/nexmo_markdown_renderer/filters/js_sequence_diagram_filter.rb +18 -0
  30. data/lib/nexmo_markdown_renderer/filters/label_filter.rb +29 -0
  31. data/lib/nexmo_markdown_renderer/filters/language_filter.rb +12 -0
  32. data/lib/nexmo_markdown_renderer/filters/markdown_filter.rb +81 -0
  33. data/lib/nexmo_markdown_renderer/filters/mermaid_filter.rb +29 -0
  34. data/lib/nexmo_markdown_renderer/filters/modal_filter.rb +37 -0
  35. data/lib/nexmo_markdown_renderer/filters/partial_filter.rb +29 -0
  36. data/lib/nexmo_markdown_renderer/filters/php_inliner_filter.rb +11 -0
  37. data/lib/nexmo_markdown_renderer/filters/screenshot_filter.rb +22 -0
  38. data/lib/nexmo_markdown_renderer/filters/tab_filter.rb +298 -0
  39. data/lib/nexmo_markdown_renderer/filters/techio_filter.rb +20 -0
  40. data/lib/nexmo_markdown_renderer/filters/tooltip_filter.rb +18 -0
  41. data/lib/nexmo_markdown_renderer/filters/unfreeze_filter.rb +16 -0
  42. data/lib/nexmo_markdown_renderer/filters/use_case_list_filter.rb +20 -0
  43. data/lib/nexmo_markdown_renderer/initializers/doc_finder.rb +5 -0
  44. data/lib/nexmo_markdown_renderer/initializers/i18n.rb +4 -0
  45. data/lib/nexmo_markdown_renderer/initializers/redcarpet.rb +7 -0
  46. data/lib/nexmo_markdown_renderer/markdown_renderer.rb +47 -0
  47. data/lib/nexmo_markdown_renderer/models/code_language.rb +79 -0
  48. data/lib/nexmo_markdown_renderer/models/code_snippet.rb +72 -0
  49. data/lib/nexmo_markdown_renderer/models/concept.rb +83 -0
  50. data/lib/nexmo_markdown_renderer/models/tutorial.rb +148 -0
  51. data/lib/nexmo_markdown_renderer/models/use_case.rb +81 -0
  52. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/android.rb +25 -0
  53. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/base.rb +12 -0
  54. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/curl.rb +29 -0
  55. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/dotnet.rb +23 -0
  56. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/java.rb +32 -0
  57. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/javascript.rb +23 -0
  58. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/kotlin.rb +25 -0
  59. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/objective_c.rb +25 -0
  60. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/php.rb +23 -0
  61. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/python.rb +23 -0
  62. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/ruby.rb +23 -0
  63. data/lib/nexmo_markdown_renderer/services/code_snippet_renderer/swift.rb +25 -0
  64. data/lib/nexmo_markdown_renderer/services/doc_finder.rb +119 -0
  65. data/lib/nexmo_markdown_renderer/views/code_snippets/_application_messages_dispatch.html.erb +9 -0
  66. data/lib/nexmo_markdown_renderer/views/code_snippets/_application_rtc.html.erb +28 -0
  67. data/lib/nexmo_markdown_renderer/views/code_snippets/_application_voice.html.erb +24 -0
  68. data/lib/nexmo_markdown_renderer/views/code_snippets/_code_only.html.erb +6 -0
  69. data/lib/nexmo_markdown_renderer/views/code_snippets/_configure_client.html.erb +20 -0
  70. data/lib/nexmo_markdown_renderer/views/code_snippets/_dependencies.html.erb +11 -0
  71. data/lib/nexmo_markdown_renderer/views/code_snippets/_write_code.html.erb +13 -0
  72. data/lib/nexmo_markdown_renderer/views/code_snippets/list/plain.html.erb +10 -0
  73. data/lib/nexmo_markdown_renderer/views/concepts/list/plain.html.erb +5 -0
  74. data/lib/nexmo_markdown_renderer/views/use_case/_index.html.erb +41 -0
  75. data/lib/nexmo_markdown_renderer/views/use_case/index.html.erb +48 -0
  76. data/lib/nexmo_markdown_renderer/views/use_case/list/plain.html.erb +5 -0
  77. data/lib/nexmo_markdown_renderer/views/use_case/show.html.erb +8 -0
  78. data/lib/version.rb +7 -0
  79. metadata +320 -0
@@ -0,0 +1,14 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class AnchorFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub(/^[\u{2693}](.+?)\n/) do
6
+ <<~HEREDOC
7
+ <a name="#{$1.parameterize}"></a>
8
+ HEREDOC
9
+ end
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class AudioFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub(/[u{🔈}]\[(.+?)\]/) do
6
+ audio = <<~HEREDOC
7
+ <audio controls>
8
+ <source src="#{$1}" type="audio/mpeg">
9
+ </audio>
10
+ HEREDOC
11
+
12
+ "FREEZESTART#{Base64.urlsafe_encode64(audio)}FREEZEEND"
13
+ end
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class BlockEscapeFilter < Banzai::Filter
4
+ def call(input)
5
+ # Freeze to prevent Markdown formatting
6
+ input.gsub(/````\n(.+?)````/m) do |_s|
7
+ lexer = Rouge::Lexer.find('text')
8
+ formatter = Rouge::Formatters::HTML.new
9
+ highlighted_source = formatter.format(lexer.lex($1))
10
+
11
+ output = <<~HEREDOC
12
+ <pre class="highlight #{lexer.tag}"><code>#{highlighted_source}</code></pre>
13
+ HEREDOC
14
+
15
+ "FREEZESTART#{Base64.urlsafe_encode64(output)}FREEZEEND"
16
+ end
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class BreakFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub('§', '<br>')
6
+ end
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,62 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class CodeFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub(/(?!.*snippet)```code(.+?)```/m) do |_s|
6
+ config = YAML.safe_load($1)
7
+
8
+ if config['config']
9
+ configs = YAML.load_file("#{ENV['DOCS_BASE_PATH']}/config/code_examples.yml")
10
+ config = config['config'].split('.').inject(configs) { |h, k| h[k] }
11
+ end
12
+
13
+ code = File.read("#{ENV['DOCS_BASE_PATH']}/#{config['source']}")
14
+ language = File.extname("#{ENV['DOCS_BASE_PATH']}/#{config['source']}")[1..-1]
15
+ lexer = language_to_lexer(language)
16
+
17
+ total_lines = code.lines.count
18
+
19
+ # Minus one since lines are not zero-indexed
20
+ from_line = (config['from_line'] || 1) - 1
21
+ to_line = (config['to_line'] || total_lines) - 1
22
+
23
+ code = code.lines[from_line..to_line].join
24
+ code.unindent! if config['unindent']
25
+
26
+ highlighted_source = highlight(code, lexer)
27
+
28
+ <<~HEREDOC
29
+ <pre class="highlight #{lexer.tag}"><code>#{highlighted_source}</code></pre>
30
+ HEREDOC
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def highlight(source, lexer)
37
+ formatter = Rouge::Formatters::HTML.new
38
+ formatter.format(lexer.lex(source))
39
+ end
40
+
41
+ def language_to_lexer_name(language)
42
+ if language_configuration[language]
43
+ language_configuration[language]['lexer']
44
+ else
45
+ language
46
+ end
47
+ end
48
+
49
+ def language_to_lexer(language)
50
+ language = language_to_lexer_name(language)
51
+ return Rouge::Lexers::PHP.new({ start_inline: true }) if language == 'php'
52
+
53
+ Rouge::Lexer.find(language.downcase) || Rouge::Lexer.find('text')
54
+ end
55
+
56
+ def language_configuration
57
+ @language_configuration ||= YAML.load_file("#{GEM_ROOT}/config/code_languages.yml")
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,187 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class CodeSnippetFilter < Banzai::Filter
4
+ include OcticonsHelper
5
+
6
+ def call(input)
7
+ input.gsub(/```single_code_snippet(.+?)```/m) do |_s|
8
+ config = YAML.safe_load($1)
9
+
10
+ @renderer = get_renderer(config['language'])
11
+
12
+ lexer = Nexmo::Markdown::CodeLanguage.find(config['language']).lexer
13
+ lang = config['title'].delete('.')
14
+
15
+ application_html = generate_application_block(config['application'])
16
+
17
+ # Read the client
18
+ if config['client']
19
+ highlighted_client_source = generate_code_block(config['language'], config['client'], config['unindent'])
20
+ end
21
+
22
+ # Read the code
23
+ highlighted_code_source = generate_code_block(config['language'], config['code'], config['unindent'])
24
+
25
+ dependency_html = ''
26
+ if config['dependencies']
27
+ dependency_html = generate_dependencies(lexer.tag, config['dependencies'])
28
+ end
29
+
30
+ source_url = generate_source_url(config['code'])
31
+
32
+ client_html = ''
33
+ if highlighted_client_source
34
+ client_url = generate_source_url(config['client'])
35
+ id = SecureRandom.hex
36
+ create_instructions = @renderer.create_instructions(config['file_name']).render_markdown
37
+ erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_configure_client.html.erb")
38
+ client_html = ERB.new(erb).result(binding)
39
+ end
40
+
41
+ add_instructions = @renderer.add_instructions(config['file_name']).render_markdown
42
+ if config['code_only']
43
+ erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_code_only.html.erb")
44
+ else
45
+ erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_write_code.html.erb")
46
+ end
47
+
48
+ code_html = ERB.new(erb).result(binding)
49
+
50
+ return code_html if config['code_only']
51
+
52
+ config['run_command'] = config['run_command'].gsub('{filename}', config['file_name']) if config['run_command']
53
+ run_html = @renderer.run_command(config['run_command'], config['file_name'], config['code']['source']).to_s
54
+
55
+ prereqs = (application_html + dependency_html + client_html).strip
56
+ prereqs = "<h2>#{::I18n.t('.filters.prerequisites')}</h2>#{prereqs}" unless prereqs.empty?
57
+ prereqs + code_html + run_html
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def highlight(source, lexer)
64
+ formatter = Rouge::Formatters::HTML.new
65
+ formatter.format(lexer.lex(source))
66
+ end
67
+
68
+ def generate_code_block(language, input, unindent)
69
+ filename = "#{ENV['DOCS_BASE_PATH']}/#{input['source']}"
70
+ return '' unless input
71
+ raise "CodeSnippetFilter - Could not load #{filename} for language #{language}" unless File.exist?(filename)
72
+
73
+ code = File.read(filename)
74
+ lexer = Nexmo::Markdown::CodeLanguage.find(language).lexer
75
+
76
+ total_lines = code.lines.count
77
+
78
+ # Minus one since lines are not zero-indexed
79
+ from_line = (input['from_line'] || 1) - 1
80
+ to_line = (input['to_line'] || total_lines) - 1
81
+
82
+ code = code.lines[from_line..to_line].join
83
+ code.unindent! if unindent
84
+
85
+ highlight(code, lexer)
86
+ end
87
+
88
+ def get_renderer(language)
89
+ language = 'dotnet' if language == 'csharp'
90
+ case language
91
+ when 'curl'
92
+ Nexmo::Markdown::CodeSnippetRenderer::Curl
93
+ when 'node'
94
+ Nexmo::Markdown::CodeSnippetRenderer::Javascript
95
+ when 'javascript'
96
+ Nexmo::Markdown::CodeSnippetRenderer::Javascript
97
+ when 'java'
98
+ Nexmo::Markdown::CodeSnippetRenderer::Java
99
+ when 'dotnet'
100
+ Nexmo::Markdown::CodeSnippetRenderer::Dotnet
101
+ when 'python'
102
+ Nexmo::Markdown::CodeSnippetRenderer::Python
103
+ when 'ruby'
104
+ Nexmo::Markdown::CodeSnippetRenderer::Ruby
105
+ when 'php'
106
+ Nexmo::Markdown::CodeSnippetRenderer::Php
107
+ when 'android'
108
+ Nexmo::Markdown::CodeSnippetRenderer::Android
109
+ when 'kotlin'
110
+ Nexmo::Markdown::CodeSnippetRenderer::Kotlin
111
+ when 'objective_c'
112
+ Nexmo::Markdown::CodeSnippetRenderer::ObjectiveC
113
+ when 'swift'
114
+ Nexmo::Markdown::CodeSnippetRenderer::Swift
115
+ else
116
+ raise "Unknown language: #{language}"
117
+ end
118
+ end
119
+
120
+ def generate_dependencies(language, dependencies)
121
+ # The only valid dependency for curl examples is `JWT`
122
+ if dependencies.map(&:upcase).include?('JWT')
123
+ title = ::I18n.t('filters.generate_your_jwt')
124
+ else
125
+ title = ::I18n.t('filters.install_dependencies')
126
+ end
127
+ deps = @renderer.dependencies(dependencies)
128
+ id = SecureRandom.hex
129
+ erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_dependencies.html.erb")
130
+ ERB.new(erb).result(binding)
131
+ end
132
+
133
+ def generate_application_block(app)
134
+ return '' unless app
135
+
136
+ base_url = 'http://demo.ngrok.io'
137
+ base_url = 'https://example.com' if app['disable_ngrok']
138
+
139
+ app['name'] = 'ExampleProject' unless app['name']
140
+
141
+ # We should remove this default once we're sure that all Code Snippets
142
+ # have a type set e.g audit
143
+ app['type'] ||= 'voice'
144
+
145
+ if ['voice', 'rtc'].include? app['type']
146
+ app['event_url'] = "#{base_url}/webhooks/events" unless app['event_url']
147
+ app['answer_url'] = "#{base_url}/webhooks/answer" unless app['answer_url']
148
+ erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_application_#{app['type']}.html.erb")
149
+ elsif ['messages', 'dispatch'].include? app['type']
150
+ erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/_application_messages_dispatch.html.erb")
151
+ else
152
+ raise "Invalid application type when creating code snippet: '#{app['type']}'"
153
+ end
154
+
155
+ id = SecureRandom.hex
156
+
157
+ ERB.new(erb).result(binding)
158
+ end
159
+
160
+ def generate_source_url(code)
161
+ # Source example: .repos/nexmo/nexmo-java-code-snippets/ExampleClass.java
162
+ # Direct link on GitHub is in form https://github.com/nexmo/nexmo-java-code-snippets/blob/master/ExampleClass.java
163
+ start_section = 'https://github.com'
164
+
165
+ # Insert "blob/master" and strip ".repos"
166
+ repo_path = '\\0blob/master/'
167
+ file_section = code['source'].sub('.repos', '').sub(%r{(-quickstart|-code-snippets|-code-snippets)/}, repo_path)
168
+
169
+ # Line highlighting
170
+ line_section = ''
171
+ if code['from_line']
172
+ line_section += "#L#{code['from_line']}"
173
+ if code['to_line']
174
+ # If we've provided a to_line, use that
175
+ line_section += "-L#{code['to_line']}" if code['to_line']
176
+ else
177
+ # By default we read to the end of the file
178
+ line_section += "-L#{File.read(code['source']).lines.count}"
179
+ end
180
+ end
181
+
182
+ start_section + file_section + line_section
183
+ end
184
+ end
185
+
186
+ end
187
+ end
@@ -0,0 +1,26 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class CodeSnippetListFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub(/```code_snippet_list(.+?)```/m) do |_s|
6
+ config = YAML.safe_load($1)
7
+ @product = config['product']
8
+ @blocks = Nexmo::Markdown::CodeSnippet.by_product(@product)
9
+
10
+ # Top level blocks come before subfolder
11
+ @blocks.sort_by! do |b|
12
+ sort_array = []
13
+ sort_array << (b.category ? 1 : 0)
14
+ sort_array << b.navigation_weight
15
+ sort_array
16
+ end
17
+
18
+ erb = File.read("#{GEM_ROOT}/lib/nexmo_markdown_renderer/views/code_snippets/list/plain.html.erb")
19
+ html = ERB.new(erb).result(binding)
20
+ "FREEZESTART#{Base64.urlsafe_encode64(html)}FREEZEEND"
21
+ end
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,170 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class CodeSnippetsFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub(/^(\s*)```code_snippets(.+?)```/m) do |_s|
6
+ @indentation = $1
7
+ @config = YAML.safe_load($2)
8
+ validate_config
9
+ html
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def create_tabs(content)
16
+ tab = Nokogiri::XML::Element.new 'li', @document
17
+ tab['class'] = 'Vlt-tabs__link'
18
+ tab['class'] += ' Vlt-tabs__link_active' if content[:active]
19
+ tab['aria-selected'] = 'true' if content[:active]
20
+
21
+ if content['language']
22
+ tab['data-language'] = content['language']
23
+ tab['data-language-type'] = content['language_type']
24
+ tab['data-language-linkable'] = true
25
+ end
26
+
27
+ tab_link = Nokogiri::XML::Element.new 'a', @document
28
+ tab_link.inner_html = "<svg><use xlink:href=\"/assets/images/brands/#{content['icon']}.svg##{content['icon']}\" /></svg><span>" + content['title'] + '</span>'
29
+ tab_link['class'] = 'tab-link'
30
+
31
+ tab.add_child(tab_link)
32
+ @tabs.add_child(tab)
33
+ end
34
+
35
+ def create_content(content)
36
+ element = Nokogiri::XML::Element.new 'div', @document
37
+ element['id'] = content['id']
38
+ element['class'] = 'Vlt-tabs__panel'
39
+ element['class'] += ' Vlt-tabs__panel_active' if content[:active]
40
+ element.inner_html = content[:body]
41
+
42
+ @tabs_content.add_child(element)
43
+ end
44
+
45
+ def html
46
+ html = <<~HEREDOC
47
+ <div class="Vlt-tabs">
48
+ <div class="Vlt-tabs__header--bordered"></div>
49
+ <div class="Vlt-tabs__content"></div>
50
+ </div>
51
+ HEREDOC
52
+
53
+ generate_html_content(html)
54
+ end
55
+
56
+ def generate_html_content(html)
57
+ @document = Nokogiri::HTML::DocumentFragment.parse(html)
58
+ @tabs = @document.at_css('.Vlt-tabs__header--bordered')
59
+ @tabs_content = @document.at_css('.Vlt-tabs__content')
60
+
61
+ tab_maker
62
+
63
+ source = @document.to_html
64
+
65
+ "#{@indentation}FREEZESTART#{Base64.urlsafe_encode64(source)}FREEZEEND"
66
+ end
67
+
68
+ def contents
69
+ list = content_from_source
70
+ list ||= []
71
+
72
+ list = sort_contents(list)
73
+ resolve_active_tab(list)
74
+
75
+ list
76
+ end
77
+
78
+ def tab_maker
79
+ contents.each do |content|
80
+ create_tabs(content)
81
+ create_content(content)
82
+ end
83
+ end
84
+
85
+ def validate_config
86
+ return if @config && @config['source']
87
+
88
+ raise 'A source key must be present in this building_blocks config'
89
+ end
90
+
91
+ def content_from_source
92
+ source_path = "#{ENV['DOCS_BASE_PATH']}/#{@config['source']}/*.yml"
93
+
94
+ files = Dir[source_path]
95
+ raise "No .yml files found for #{@config['source']} code snippets" if files.empty?
96
+
97
+ generate_content(files)
98
+ end
99
+
100
+ def generate_content(files)
101
+ files.map do |content_path|
102
+ source = File.read(content_path)
103
+
104
+ # Load the defaults for this language
105
+ filename = File.basename(content_path, '.yml')
106
+ defaults = Nexmo::Markdown::CodeLanguage.find(filename)
107
+
108
+ content = YAML.safe_load(source)
109
+ content['source'] = source
110
+ content['id'] = SecureRandom.hex
111
+ content['title'] ||= defaults.label
112
+ content['language'] ||= defaults.key
113
+ content['language_type'] ||= defaults.type
114
+ content['dependencies'] ||= defaults.dependencies
115
+ content['icon'] = defaults.icon
116
+ content['weight'] ||= defaults.weight
117
+ content['run_command'] ||= defaults.run_command
118
+ content['unindent'] = defaults.unindent || false
119
+
120
+ # If we don't have a file_name in config, use the one in the repo
121
+ content['file_name'] ||= File.basename(content['code']['source'])
122
+
123
+ parent_config = { 'code_only' => @config['code_only'], 'source' => @config['source'].gsub('_examples/', '') }
124
+ if @config['application']
125
+ parent_config = parent_config.merge({ 'application' => @config['application'] })
126
+ end
127
+
128
+ parent_config = parent_config.to_yaml.lines[1..-1].join
129
+
130
+ source = render_single_snippet(content, parent_config)
131
+
132
+ content[:body] = Nexmo::Markdown::Renderer.new(options).call(source)
133
+
134
+ content
135
+ end
136
+ end
137
+
138
+ def render_single_snippet(content, parent_config)
139
+ <<~HEREDOC
140
+ ```single_code_snippet
141
+ #{content.to_yaml}\n#{parent_config}
142
+ ```
143
+ HEREDOC
144
+ end
145
+
146
+ def sort_contents(contents)
147
+ contents.sort_by do |content|
148
+ content['weight']
149
+ end
150
+ end
151
+
152
+ def resolve_active_tab(contents)
153
+ active_index = nil
154
+
155
+ if options[:code_language]
156
+ contents.each_with_index do |content, index|
157
+ active_index = index if content['language'] == options[:code_language].key
158
+ end
159
+ end
160
+
161
+ @tabs['data-has-initial-tab'] = active_index.present?
162
+ @tabs['class'] += ' skip-pushstate' if @tabs['data-has-initial-tab']
163
+ active_index ||= 0
164
+
165
+ contents[active_index][:active] = true
166
+ end
167
+ end
168
+
169
+ end
170
+ end