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,29 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class MermaidFilter < Banzai::Filter
4
+ TYPES = {
5
+ 'mermaid' => '',
6
+ 'sequence_diagram' => 'sequenceDiagram',
7
+ }.freeze
8
+
9
+ def call(input)
10
+ TYPES.each do |markdown, mermaid|
11
+ input = input.gsub(/```#{markdown}(.+?)```/m) do |_s|
12
+ render_mermaid(mermaid, $1)
13
+ end
14
+ end
15
+
16
+ input
17
+ end
18
+
19
+ def render_mermaid(type, content)
20
+ diagram = <<~HEREDOC
21
+ <div class="mermaid" style="color: transparent;">#{type} #{content.gsub('\\n', '<br />').strip}
22
+ </div>
23
+ HEREDOC
24
+
25
+ "FREEZESTART#{Base64.urlsafe_encode64(diagram)}FREEZEEND"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class ModalFilter < Banzai::Filter
4
+ def call(input)
5
+ modals = []
6
+
7
+ input.gsub!(/@\[(.+?)\]\((.+?)\)/) do |_s|
8
+ id = 'M' + SecureRandom.hex(12)
9
+ modals << { document: $2, id: id }
10
+ "<a href='javascript:void(0)' data-modal='#{id}' class='Vlt-modal-trigger Vlt-text-link'>#{$1}</a>"
11
+ end
12
+
13
+ modals = modals.map do |modal|
14
+ filename = "#{ENV['DOCS_BASE_PATH']}/#{modal[:document]}"
15
+ raise "Could not find modal #{filename}" unless File.exist? filename
16
+
17
+ document = File.read(filename)
18
+ output = Nexmo::Markdown::Renderer.new.call(document)
19
+
20
+ modal = <<~HEREDOC
21
+ <div class="Vlt-modal" id="#{modal[:id]}">
22
+ <div class="Vlt-modal__panel">
23
+ <div class="Vlt-modal__content">
24
+ #{output}
25
+ </div>
26
+ </div>
27
+ </div>
28
+ HEREDOC
29
+
30
+ "FREEZESTART#{Base64.urlsafe_encode64(modal)}FREEZEEND"
31
+ end
32
+
33
+ input + modals.join("\n")
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class PartialFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub(/```partial(.+?)```/m) do |_s|
6
+ config = YAML.safe_load($1)
7
+ file_path = if config['source'].starts_with? 'app/views'
8
+ config['source']
9
+ else
10
+ "#{ENV['DOCS_BASE_PATH']}/#{config['source']}"
11
+ end
12
+ content = File.read(file_path)
13
+
14
+ active = options[:code_language] ? options[:code_language].key == config['platform'] : false
15
+
16
+ if config['platform']
17
+ <<~HEREDOC
18
+ <div class="js-platform" data-platform="#{config['platform']}" data-active="#{active}">
19
+ #{content.render_markdown}
20
+ </div>
21
+ HEREDOC
22
+ else
23
+ content
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class PhpInlinerFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub(/(```php)\n/) do
6
+ "#{$1}?start_inline=1\n"
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class ScreenshotFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub(/```screenshot(.+?)```/m) do |_s|
6
+ config = YAML.safe_load($1)
7
+ if config['image'] && File.file?(config['image'])
8
+ "![Screenshot](#{config['image'].gsub('public', '')})"
9
+ else
10
+ <<~HEREDOC
11
+ ## Missing image
12
+ To fix this run:
13
+ ```
14
+ $ rake screenshots:update
15
+ ```
16
+ HEREDOC
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,298 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class TabFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub(/^(\s*)```tabbed_(examples|content|folder)(.+?)```/m) do |_s|
6
+ @indentation = $1
7
+ @mode = $2
8
+ @config = YAML.safe_load($3)
9
+
10
+ if tabbed_folder?
11
+ raise "#{@config['source']} is not a directory" unless File.directory? "#{ENV['DOCS_BASE_PATH']}/#{@config['source']}"
12
+
13
+ @tabbed_config = YAML.safe_load(File.read("#{ENV['DOCS_BASE_PATH']}/#{@config['source']}/.config.yml"))
14
+ @path = @config['source']
15
+ validate_folder_config
16
+ else
17
+ validate_config
18
+ end
19
+ html
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def create_tabs(content)
26
+ tab = Nokogiri::XML::Element.new 'div', @document
27
+ tab['class'] = 'Vlt-tabs__link'
28
+ tab['class'] += ' Vlt-tabs__link_active' if content[:active]
29
+ tab['role'] = 'tab'
30
+
31
+ if content[:language]
32
+ tab['data-language'] = content[:language].key
33
+ tab['data-language-type'] = content[:language].type
34
+ tab['data-language-linkable'] = content[:language].linkable?
35
+ end
36
+
37
+ if content[:platform]
38
+ tab['data-language'] = content[:platform].languages.map(&:key).join(',')
39
+ tab['data-platform'] = content[:platform].key
40
+ tab['data-platform-type'] = content[:platform].type
41
+ tab['data-platform-linkable'] = content[:platform].linkable?
42
+ end
43
+
44
+ tab_link = Nokogiri::XML::Element.new 'span', @document
45
+ if content[:language]
46
+ # We don't currently have icons for JSON/XML
47
+ if ['json', 'xml'].include? content[:language].key.downcase
48
+ tab_link.content = content[:tab_title]
49
+ elsif content[:language].key == 'objective_c' || content[:language].key == 'swift'
50
+ tab_link.inner_html = "<svg><use xlink:href=\"/assets/images/brands/ios.svg#ios\" /></svg><span>" + content[:tab_title] + '</span>'
51
+ else
52
+ tab_link.inner_html = "<svg><use xlink:href=\"/assets/images/brands/#{content[:language].key}.svg##{content[:language].key}\" /></svg><span>" + content[:tab_title] + '</span>'
53
+ end
54
+ elsif content[:platform]
55
+ tab_link.inner_html = "<svg><use xlink:href=\"/assets/images/brands/#{content[:platform].key}.svg##{content[:platform].key}\" /></svg><span>" + content[:tab_title] + '</span>'
56
+ else
57
+ tab_link.content = content[:tab_title]
58
+ end
59
+
60
+ tab.add_child(tab_link)
61
+ @tabs.add_child(tab)
62
+ end
63
+
64
+ def create_content(content)
65
+ tabs_panel = Nokogiri::XML::Element.new 'div', @document
66
+ tabs_panel['class'] = 'Vlt-tabs__panel'
67
+ tabs_panel['class'] += ' Vlt-tabs__panel_active' if content[:active]
68
+
69
+ element = Nokogiri::XML::Element.new 'p', @document
70
+ element['aria-labelledby'] = "\"#{content[:id]}\""
71
+ element['aria-hidden'] = true
72
+ element.inner_html = content[:body]
73
+
74
+ tabs_panel.add_child(element)
75
+ @tabs_content.add_child(tabs_panel)
76
+ end
77
+
78
+ def tabbed_code_examples?
79
+ @mode == 'examples'
80
+ end
81
+
82
+ def tabbed_content?
83
+ @mode == 'content'
84
+ end
85
+
86
+ def tabbed_folder?
87
+ @mode == 'folder'
88
+ end
89
+
90
+ def html
91
+ html = <<~HEREDOC
92
+ <div class="Vlt-tabs">
93
+ <div class="Vlt-tabs__header Vlt-tabs__header--bordered"></div>
94
+ <div class="Vlt-tabs__content">
95
+ </div>
96
+ </div>
97
+ HEREDOC
98
+
99
+ @document = Nokogiri::HTML::DocumentFragment.parse(html)
100
+ @tabs = @document.at_css('.Vlt-tabs__header')
101
+ @tabs_content = @document.at_css('.Vlt-tabs__content')
102
+
103
+ contents.each do |content|
104
+ create_tabs(content)
105
+ create_content(content)
106
+ end
107
+
108
+ source = @document.to_html
109
+
110
+ "#{@indentation}FREEZESTART#{Base64.urlsafe_encode64(source)}FREEZEEND"
111
+ end
112
+
113
+ def contents
114
+ list = content_from_folder if tabbed_folder?
115
+ list ||= content_from_source if @config['source']
116
+ list ||= content_from_tabs if @config['tabs']
117
+
118
+ list ||= []
119
+
120
+ return list unless list.any?
121
+
122
+ list = resolve_language(list)
123
+
124
+ if tabbed_code_examples?
125
+ list = format_code(list)
126
+ list = resolve_code(list)
127
+ list = resolve_tab_title(list)
128
+ end
129
+
130
+ list = sort_contents(list)
131
+ resolve_active_tab(list)
132
+
133
+ list
134
+ end
135
+
136
+ def validate_config
137
+ return if @config && (@config['source'] || @config['tabs'])
138
+
139
+ raise 'Source or tabs must be present in this tabbed_example config'
140
+ end
141
+
142
+ def validate_folder_config
143
+ return if @tabbed_config && @tabbed_config['tabbed'] == true
144
+
145
+ raise 'Tabbed must be set to true in the folder config YAML file'
146
+ end
147
+
148
+ def content_from_source
149
+ source_path = "#{ENV['DOCS_BASE_PATH']}/#{@config['source']}"
150
+ source_path += '/*' if tabbed_code_examples?
151
+ source_path += '/*.md' if tabbed_content?
152
+
153
+ files = Dir.glob(source_path)
154
+ raise "Empty content_from_source file list in #{source_path}" if files.empty?
155
+
156
+ files.map do |content_path|
157
+ raise "Could not find content_from_source file: #{content_path}" unless File.exist? content_path
158
+
159
+ source = File.read(content_path)
160
+
161
+ next generate_tabbed_code_examples(source, content_path) if tabbed_code_examples?
162
+
163
+ generate_tabbed_content(source) if tabbed_content?
164
+ end
165
+ end
166
+
167
+ def content_from_folder
168
+ source_path = "#{ENV['DOCS_BASE_PATH']}/#{@config['source']}"
169
+ source_path += '/*.md'
170
+
171
+ files = Dir.glob(source_path)
172
+ raise "Empty content_from_source file list in #{source_path}" if files.empty?
173
+
174
+ files.map do |content_path|
175
+ raise "Could not find content_from_source file: #{content_path}" unless File.exist? content_path
176
+
177
+ source = File.read(content_path)
178
+
179
+ generate_tabbed_content(source)
180
+ end
181
+ end
182
+
183
+ def content_from_tabs
184
+ @config['tabs'].map do |title, config|
185
+ raise "Could not find content_from_tabs file: #{ENV['DOCS_BASE_PATH']}/#{@config['source']}" unless File.exist? "#{ENV['DOCS_BASE_PATH']}/#{@config['source']}"
186
+
187
+ source = File.read("#{ENV['DOCS_BASE_PATH']}/#{@config['source']}")
188
+
189
+ config.symbolize_keys.merge({
190
+ id: SecureRandom.hex,
191
+ source: source,
192
+ language_key: title.dup.downcase,
193
+ })
194
+ end
195
+ end
196
+
197
+ def generate_tabbed_content(source)
198
+ content = {
199
+ id: SecureRandom.hex,
200
+ source: source,
201
+ }
202
+
203
+ content[:frontmatter] = YAML.safe_load(source)
204
+ content[:language_key] = content[:frontmatter]['language']
205
+ content[:platform_key] = content[:frontmatter]['platform']
206
+ content[:tab_title] = content[:frontmatter]['title']
207
+ content[:body] = Nexmo::Markdown::Renderer.new(options).call(source)
208
+
209
+ content
210
+ end
211
+
212
+ def generate_tabbed_code_examples(source, content_path)
213
+ content = {
214
+ id: SecureRandom.hex,
215
+ source: source,
216
+ }
217
+ language_key = File.basename(content_path, '.*').downcase
218
+ content[:language_key] = language_key
219
+
220
+ content
221
+ end
222
+
223
+ def resolve_language(contents)
224
+ contents.map do |content|
225
+ if content[:language_key]
226
+ content[:language] = CodeLanguage.find(content[:language_key])
227
+ end
228
+
229
+ if content[:platform_key]
230
+ content[:platform] = CodeLanguage.find(content[:platform_key])
231
+ end
232
+
233
+ content
234
+ end
235
+ end
236
+
237
+ def format_code(contents)
238
+ contents.each do |content|
239
+ if content[:from_line] || content[:to_line]
240
+ lines = content[:source].lines
241
+ total_lines = lines.count
242
+ from_line = (content[:from_line] || 1) - 1
243
+ to_line = (content[:to_line] || total_lines) - 1
244
+ content[:source] = lines[from_line..to_line].join
245
+ end
246
+
247
+ content[:source].unindent! if content[:unindent]
248
+ end
249
+ end
250
+
251
+ def resolve_code(contents)
252
+ contents.map do |content|
253
+ @formatter ||= Rouge::Formatters::HTML.new
254
+ lexer = content[:language].lexer
255
+ highlighted_source = @formatter.format(lexer.lex(content[:source]))
256
+ body = <<~HEREDOC
257
+ <pre class="highlight #{content[:language_key]}"><code>#{highlighted_source}</code></pre>
258
+ HEREDOC
259
+
260
+ content.merge!({ body: body })
261
+ end
262
+ end
263
+
264
+ def resolve_tab_title(contents)
265
+ contents.map do |content|
266
+ content.merge!({ tab_title: content[:language].label })
267
+ end
268
+ end
269
+
270
+ def sort_contents(contents)
271
+ contents.sort_by do |content|
272
+ next content[:language].weight if content[:language]
273
+
274
+ next content[:frontmatter]['menu_weight'] || 999 if content[:frontmatter]
275
+
276
+ 999
277
+ end
278
+ end
279
+
280
+ def resolve_active_tab(contents)
281
+ active_index = nil
282
+
283
+ if options[:code_language]
284
+ contents.each_with_index do |content, index|
285
+ %i[language_key platform_key].each do |key|
286
+ active_index = index if content[key] == options[:code_language].key
287
+ end
288
+ end
289
+ end
290
+
291
+ @tabs['data-has-initial-tab'] = active_index.present?
292
+ active_index ||= 0
293
+
294
+ contents[active_index][:active] = true
295
+ end
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,20 @@
1
+ module Nexmo
2
+ module Markdown
3
+ class TechioFilter < Banzai::Filter
4
+ def call(input)
5
+ input.gsub(/```techio(.+?)```/m) do |_s|
6
+ config = YAML.safe_load($1)
7
+
8
+ techio = <<~HEREDOC
9
+ <div class="techio-container">
10
+ <iframe width="100%" frameborder="0" scrolling="no" allowtransparency="true" style="visibility: hidden" src="https://tech.io/playground-widget#{config['path']}/#{config['title']}"></iframe>
11
+ <script>if(typeof window.techioScriptInjected==="undefined"){window.techioScriptInjected=true;var d=document,s=d.createElement("script");s.src="https://files.codingame.com/codingame/iframe-v-1-4.js";(d.head||d.body).appendChild(s);}</script>
12
+ </div>
13
+ HEREDOC
14
+
15
+ "FREEZESTART#{Base64.urlsafe_encode64(techio)}FREEZEEND"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end