nexmo-oas-renderer 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.env.example +1 -0
- data/.gitignore +5 -0
- data/CHANGELOG.md +2 -0
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +183 -0
- data/LICENSE.txt +21 -0
- data/README.md +73 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/nexmo-oas-renderer +5 -0
- data/lib/nexmo/oas/engine.rb +9 -0
- data/lib/nexmo/oas/renderer.rb +13 -0
- data/lib/nexmo/oas/renderer/app.rb +116 -0
- data/lib/nexmo/oas/renderer/config.ru +7 -0
- data/lib/nexmo/oas/renderer/config/code_languages.yml +138 -0
- data/lib/nexmo/oas/renderer/config/dynamic_content.yml +1 -0
- data/lib/nexmo/oas/renderer/config/redirects.yml +8 -0
- data/lib/nexmo/oas/renderer/constraints/open_api.rb +76 -0
- data/lib/nexmo/oas/renderer/constraints/redirector.rb +17 -0
- data/lib/nexmo/oas/renderer/decorators/response_parser_decorator.rb +55 -0
- data/lib/nexmo/oas/renderer/filters/anchor.rb +17 -0
- data/lib/nexmo/oas/renderer/filters/audio.rb +21 -0
- data/lib/nexmo/oas/renderer/filters/block_escape.rb +24 -0
- data/lib/nexmo/oas/renderer/filters/break.rb +13 -0
- data/lib/nexmo/oas/renderer/filters/code.rb +64 -0
- data/lib/nexmo/oas/renderer/filters/code_snippet.rb +194 -0
- data/lib/nexmo/oas/renderer/filters/code_snippet_list.rb +33 -0
- data/lib/nexmo/oas/renderer/filters/code_snippets.rb +158 -0
- data/lib/nexmo/oas/renderer/filters/collapsible.rb +27 -0
- data/lib/nexmo/oas/renderer/filters/columns.rb +50 -0
- data/lib/nexmo/oas/renderer/filters/concept_list.rb +33 -0
- data/lib/nexmo/oas/renderer/filters/dynamic_content.rb +30 -0
- data/lib/nexmo/oas/renderer/filters/external_link.rb +32 -0
- data/lib/nexmo/oas/renderer/filters/frontmatter.rb +14 -0
- data/lib/nexmo/oas/renderer/filters/heading.rb +61 -0
- data/lib/nexmo/oas/renderer/filters/icon.rb +22 -0
- data/lib/nexmo/oas/renderer/filters/indent.rb +20 -0
- data/lib/nexmo/oas/renderer/filters/inline_escape.rb +17 -0
- data/lib/nexmo/oas/renderer/filters/js_sequence_diagram.rb +21 -0
- data/lib/nexmo/oas/renderer/filters/label.rb +32 -0
- data/lib/nexmo/oas/renderer/filters/language.rb +15 -0
- data/lib/nexmo/oas/renderer/filters/markdown.rb +85 -0
- data/lib/nexmo/oas/renderer/filters/modal.rb +41 -0
- data/lib/nexmo/oas/renderer/filters/partial.rb +28 -0
- data/lib/nexmo/oas/renderer/filters/php_inliner.rb +15 -0
- data/lib/nexmo/oas/renderer/filters/screenshot.rb +26 -0
- data/lib/nexmo/oas/renderer/filters/tab.rb +250 -0
- data/lib/nexmo/oas/renderer/filters/techio.rb +24 -0
- data/lib/nexmo/oas/renderer/filters/tooltip.rb +22 -0
- data/lib/nexmo/oas/renderer/filters/tutorial_link.rb +27 -0
- data/lib/nexmo/oas/renderer/filters/tutorials.rb +28 -0
- data/lib/nexmo/oas/renderer/filters/unfreeze.rb +20 -0
- data/lib/nexmo/oas/renderer/filters/user_personalization.rb +43 -0
- data/lib/nexmo/oas/renderer/helpers/navigation.rb +66 -0
- data/lib/nexmo/oas/renderer/helpers/render.rb +24 -0
- data/lib/nexmo/oas/renderer/helpers/summary.rb +30 -0
- data/lib/nexmo/oas/renderer/helpers/url.rb +17 -0
- data/lib/nexmo/oas/renderer/lib/core_ext/string.rb +14 -0
- data/lib/nexmo/oas/renderer/lib/redcarpet.rb +14 -0
- data/lib/nexmo/oas/renderer/models/code_snippet.rb +75 -0
- data/lib/nexmo/oas/renderer/models/tutorial.rb +83 -0
- data/lib/nexmo/oas/renderer/pipelines/markdown_pipeline.rb +52 -0
- data/lib/nexmo/oas/renderer/presenters/api_specification.rb +42 -0
- data/lib/nexmo/oas/renderer/presenters/groups.rb +35 -0
- data/lib/nexmo/oas/renderer/presenters/navigation.rb +24 -0
- data/lib/nexmo/oas/renderer/presenters/open_api_specification.rb +68 -0
- data/lib/nexmo/oas/renderer/presenters/versions.rb +40 -0
- data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Black.woff +0 -0
- data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Black.woff2 +0 -0
- data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Heavy.woff +0 -0
- data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Heavy.woff2 +0 -0
- data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Regular.woff +0 -0
- data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Regular.woff2 +0 -0
- data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Semibold.woff +0 -0
- data/lib/nexmo/oas/renderer/public/assets/fonts/Lato-Semibold.woff2 +0 -0
- data/lib/nexmo/oas/renderer/public/assets/images/brands/android.svg +1 -0
- data/lib/nexmo/oas/renderer/public/assets/images/brands/curl.svg +1 -0
- data/lib/nexmo/oas/renderer/public/assets/images/brands/dotnet.svg +1 -0
- data/lib/nexmo/oas/renderer/public/assets/images/brands/ios.svg +1 -0
- data/lib/nexmo/oas/renderer/public/assets/images/brands/java.svg +1 -0
- data/lib/nexmo/oas/renderer/public/assets/images/brands/javascript.svg +1 -0
- data/lib/nexmo/oas/renderer/public/assets/images/brands/node.svg +1 -0
- data/lib/nexmo/oas/renderer/public/assets/images/brands/php.svg +1 -0
- data/lib/nexmo/oas/renderer/public/assets/images/brands/python.svg +11 -0
- data/lib/nexmo/oas/renderer/public/assets/images/brands/ruby.svg +1 -0
- data/lib/nexmo/oas/renderer/public/assets/images/lost.svg +37 -0
- data/lib/nexmo/oas/renderer/public/assets/javascripts/components/format.js +42 -0
- data/lib/nexmo/oas/renderer/public/assets/javascripts/volta.accordion.js +249 -0
- data/lib/nexmo/oas/renderer/public/assets/javascripts/volta.core.js +230 -0
- data/lib/nexmo/oas/renderer/public/assets/javascripts/volta.modal.js +300 -0
- data/lib/nexmo/oas/renderer/public/assets/javascripts/volta.tabs.js +139 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/api.css +95 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/buttons.css +80 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/core.css +79 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/mediaqueries.css +2 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/mediaqueries.css.map +7 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/navigation.css +79 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/nexmo.css +68 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/api.scss +147 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/core.scss +133 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/mediaqueries.scss +48 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/navigation.scss +106 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/nexmo.scss +61 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/style.scss +10 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/syntax.scss +63 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/typography.scss +248 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/variables.scss +91 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/sass/volta-templates.scss +119 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/style.css +2 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/style.css.map +7 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/syntax.css +79 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/typography.css +86 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/variables.css +2 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/variables.css.map +7 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/volta-templates.css +2 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/volta-templates.css.map +7 -0
- data/lib/nexmo/oas/renderer/public/assets/stylesheets/volta.min.css +1 -0
- data/lib/nexmo/oas/renderer/public/assets/symbol/volta-icons.svg +1 -0
- data/lib/nexmo/oas/renderer/public/favicon.ico +0 -0
- data/lib/nexmo/oas/renderer/services/code_language_api.rb +98 -0
- data/lib/nexmo/oas/renderer/services/oas_parser.rb +21 -0
- data/lib/nexmo/oas/renderer/services/open_api_definition_resolver.rb +33 -0
- data/lib/nexmo/oas/renderer/version.rb +7 -0
- data/lib/nexmo/oas/renderer/views/api/show.erb +1 -0
- data/lib/nexmo/oas/renderer/views/code_snippets/_application_messages_dispatch.html.erb +9 -0
- data/lib/nexmo/oas/renderer/views/code_snippets/_application_rtc.html.erb +41 -0
- data/lib/nexmo/oas/renderer/views/code_snippets/_application_voice.html.erb +24 -0
- data/lib/nexmo/oas/renderer/views/code_snippets/_code_only.html.erb +6 -0
- data/lib/nexmo/oas/renderer/views/code_snippets/_configure_client.html.erb +20 -0
- data/lib/nexmo/oas/renderer/views/code_snippets/_dependencies.html.erb +11 -0
- data/lib/nexmo/oas/renderer/views/code_snippets/_write_code.html.erb +13 -0
- data/lib/nexmo/oas/renderer/views/code_snippets/list/plain.html.erb +10 -0
- data/lib/nexmo/oas/renderer/views/concepts/list/plain.html.erb +5 -0
- data/lib/nexmo/oas/renderer/views/layouts/_head.erb +4 -0
- data/lib/nexmo/oas/renderer/views/layouts/_javascripts.erb +9 -0
- data/lib/nexmo/oas/renderer/views/layouts/api.erb +23 -0
- data/lib/nexmo/oas/renderer/views/layouts/open_api.erb +10 -0
- data/lib/nexmo/oas/renderer/views/open_api/_callback.erb +5 -0
- data/lib/nexmo/oas/renderer/views/open_api/_callback_endpoint.erb +48 -0
- data/lib/nexmo/oas/renderer/views/open_api/_code_examples.erb +16 -0
- data/lib/nexmo/oas/renderer/views/open_api/_endpoint.erb +156 -0
- data/lib/nexmo/oas/renderer/views/open_api/_model.erb +38 -0
- data/lib/nexmo/oas/renderer/views/open_api/_navigation.erb +80 -0
- data/lib/nexmo/oas/renderer/views/open_api/_parameter_groups.erb +50 -0
- data/lib/nexmo/oas/renderer/views/open_api/_parameters.erb +165 -0
- data/lib/nexmo/oas/renderer/views/open_api/_response_description_parameters.erb +61 -0
- data/lib/nexmo/oas/renderer/views/open_api/_response_descriptions.erb +41 -0
- data/lib/nexmo/oas/renderer/views/open_api/show.erb +104 -0
- data/lib/nexmo/oas/renderer/views/static/404.erb +6 -0
- data/lib/nexmo/oas/renderer/views/tutorials/_index.html.erb +32 -0
- data/lib/nexmo/oas/renderer/views/tutorials/index.html.erb +7 -0
- data/lib/nexmo/oas/renderer/views/tutorials/list/plain.html.erb +5 -0
- data/lib/nexmo/oas/renderer/views/tutorials/show.html.erb +8 -0
- data/nexmo-oas-renderer.gemspec +49 -0
- metadata +399 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
module Nexmo
|
2
|
+
module OAS
|
3
|
+
module Renderer
|
4
|
+
module Helpers
|
5
|
+
module Navigation
|
6
|
+
|
7
|
+
HEADING_TAG_DEPTHS = {
|
8
|
+
'h0' => 0,
|
9
|
+
'h1' => 1,
|
10
|
+
'h2' => 2,
|
11
|
+
'h3' => 3,
|
12
|
+
'h4' => 4,
|
13
|
+
'h5' => 5,
|
14
|
+
'h6' => 6,
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
def navigation_from_content(content:, title: nil)
|
18
|
+
content = "<h0 class='injected'>#{title}</h0>\n" + content if title
|
19
|
+
document = build_document(content)
|
20
|
+
|
21
|
+
nodes = ['<ul class="Vlt-sidemenu Vlt-sidemenu--rounded Vlt-sidemenu--flat navigation js-navigation">']
|
22
|
+
last_node = nil
|
23
|
+
|
24
|
+
document.css('.reveal').remove
|
25
|
+
|
26
|
+
document.css('h0,h2,h3,h4,h5,h6').each do |heading|
|
27
|
+
# If it's a header within tabbed content (including Code Snippets) we don't want to treat
|
28
|
+
# the header as a navigation item in the sidebar
|
29
|
+
next unless heading.ancestors('.Vlt-tabs').empty?
|
30
|
+
|
31
|
+
# Same with callouts
|
32
|
+
next unless heading.ancestors('.Vlt-callout').empty?
|
33
|
+
|
34
|
+
if last_node.nil? || heading.name == last_node.name
|
35
|
+
# Do nothing (cleaner than adding wrapping further conditions)
|
36
|
+
elsif heading.name >= last_node.name # e.g. h2 -> h3
|
37
|
+
nodes << '<ul>'
|
38
|
+
else # e.g. h4 -> h2
|
39
|
+
(HEADING_TAG_DEPTHS[last_node.name] - HEADING_TAG_DEPTHS[heading.name]).times do
|
40
|
+
nodes << '</li></ul>'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
nodes << <<~HEREDOC
|
45
|
+
<li>
|
46
|
+
<a class="Vlt-sidemenu__link" href="##{heading.attributes['id']}" data-scrollspy-id="#{heading['data-id']}">
|
47
|
+
#{heading.text}
|
48
|
+
</a>
|
49
|
+
HEREDOC
|
50
|
+
last_node = heading
|
51
|
+
end
|
52
|
+
nodes << '</li></ul>'
|
53
|
+
nodes.join("\n").html_safe
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def build_document(content)
|
59
|
+
Nokogiri::HTML::DocumentFragment.parse(content)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Nexmo
|
2
|
+
module OAS
|
3
|
+
module Renderer
|
4
|
+
module Helpers
|
5
|
+
module Render
|
6
|
+
|
7
|
+
def find_template(views, name, engine, &block)
|
8
|
+
Array(views).each do |v|
|
9
|
+
super(v, name, engine, &block)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def render(*args)
|
14
|
+
if args.length > 2
|
15
|
+
super
|
16
|
+
else
|
17
|
+
ApplicationController.renderer.render(*args)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Nexmo
|
2
|
+
module OAS
|
3
|
+
module Renderer
|
4
|
+
module Helpers
|
5
|
+
module Summary
|
6
|
+
def normalize_summary_title(summary, operation_id)
|
7
|
+
# return summary early if provided
|
8
|
+
return summary unless summary.nil?
|
9
|
+
|
10
|
+
# If the operation ID is camelCase,
|
11
|
+
if operation_id.match?(/^[a-zA-Z]\w+(?:[A-Z]\w+){1,}/x)
|
12
|
+
# Use the rails `.underscore` method to convert someString to some_string
|
13
|
+
operation_id = operation_id.underscore
|
14
|
+
end
|
15
|
+
|
16
|
+
# Replace snake_case and kebab-case with spaces and titelize the string
|
17
|
+
operation_id = operation_id.gsub(/(_|-)/, ' ').titleize
|
18
|
+
|
19
|
+
# Some terms need to be capitalised all the time
|
20
|
+
uppercase_array = ['SMS', 'DTMF']
|
21
|
+
operation_id.split(' ').map do |c|
|
22
|
+
next c.upcase if uppercase_array.include?(c.upcase)
|
23
|
+
c
|
24
|
+
end.join(' ')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Nexmo
|
2
|
+
module OAS
|
3
|
+
module Renderer
|
4
|
+
module Helpers
|
5
|
+
module URL
|
6
|
+
def parameter_values(enum)
|
7
|
+
enum.map { |value| "<code>#{value}</code>" }.to_sentence(last_word_connector: ' or ', two_words_connector: ' or ')
|
8
|
+
end
|
9
|
+
|
10
|
+
def canonical_path
|
11
|
+
request.path.chomp("/#{params[:code_language]}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class String
|
2
|
+
def render_markdown(options = {})
|
3
|
+
Nexmo::OAS::Renderer::MarkdownPipeline.new(options).call(self).html_safe
|
4
|
+
end
|
5
|
+
|
6
|
+
def unindent
|
7
|
+
indent = squeeze("\n").lines.map { |line| line.index(/[^\s]/) }.compact.min || 0
|
8
|
+
gsub(/^[[:blank:]]{#{indent}}/, '')
|
9
|
+
end
|
10
|
+
|
11
|
+
def unindent!
|
12
|
+
replace(unindent)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Nexmo
|
2
|
+
module OAS
|
3
|
+
module Renderer
|
4
|
+
module Models
|
5
|
+
class CodeSnippet
|
6
|
+
include ActiveModel::Model
|
7
|
+
attr_accessor :title, :product, :category, :navigation_weight, :document_path, :url
|
8
|
+
|
9
|
+
def self.by_product(product)
|
10
|
+
all.select do |block|
|
11
|
+
block.product == product
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.all
|
16
|
+
blocks = files.map do |document_path|
|
17
|
+
document = File.read(document_path)
|
18
|
+
product = extract_product(document_path)
|
19
|
+
|
20
|
+
frontmatter = YAML.safe_load(document)
|
21
|
+
|
22
|
+
new({
|
23
|
+
title: frontmatter['title'],
|
24
|
+
navigation_weight: frontmatter['navigation_weight'] || 999,
|
25
|
+
product: product,
|
26
|
+
document_path: document_path,
|
27
|
+
category: extract_category(document_path),
|
28
|
+
url: generate_url(document_path),
|
29
|
+
})
|
30
|
+
end
|
31
|
+
|
32
|
+
blocks.sort_by(&:navigation_weight)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.generate_url(path)
|
36
|
+
'/' + path.gsub("#{origin}/", '').gsub('.md', '')
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.extract_product(path)
|
40
|
+
# Remove the prefix
|
41
|
+
path = path.gsub!("#{origin}/", '')
|
42
|
+
|
43
|
+
# Each file is in the form code-snippets/<title>.md, so let's remove everything after code-snippets
|
44
|
+
path = path.gsub(%r{/code-snippets/.*}, '')
|
45
|
+
|
46
|
+
path
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.extract_category(path)
|
50
|
+
# Remove the prefix
|
51
|
+
path = path.gsub("#{origin}/", '')
|
52
|
+
|
53
|
+
# Each file is in the form code-snippets/<title>.md, so let's capture everything after code-snippets
|
54
|
+
path = path.gsub(%r{.*/code-snippets/(.*)$}, '\1')
|
55
|
+
|
56
|
+
parts = path.split('/')
|
57
|
+
parts = parts[0...-1]
|
58
|
+
|
59
|
+
return nil if parts.empty?
|
60
|
+
|
61
|
+
parts.join('/').tr('-', ' ').humanize
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.files
|
65
|
+
Dir.glob("#{origin}/**/code-snippets/**/*.md")
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.origin
|
69
|
+
"_documentation"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Nexmo
|
2
|
+
module OAS
|
3
|
+
module Renderer
|
4
|
+
module Models
|
5
|
+
class Tutorial
|
6
|
+
|
7
|
+
include ActiveModel::Model
|
8
|
+
attr_accessor :title, :description, :external_link, :products, :document_path, :languages
|
9
|
+
|
10
|
+
def body
|
11
|
+
File.read(document_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def path
|
15
|
+
return external_link if external_link
|
16
|
+
"/tutorials/#{document_path.relative_path_from(self.class.origin)}".gsub('.md', '')
|
17
|
+
end
|
18
|
+
|
19
|
+
def subtitle
|
20
|
+
normalized_products = products.map do |product|
|
21
|
+
normalise_product_title(product)
|
22
|
+
end
|
23
|
+
|
24
|
+
normalized_products.sort.to_sentence
|
25
|
+
end
|
26
|
+
|
27
|
+
def normalise_product_title(product)
|
28
|
+
return 'SMS' if product == 'messaging/sms'
|
29
|
+
return 'Voice' if product == 'voice/voice-api'
|
30
|
+
return 'Number Insight' if product == 'number-insight'
|
31
|
+
return 'Messages' if product == 'messages'
|
32
|
+
return 'Dispatch' if product == 'dispatch'
|
33
|
+
return 'Client SDK' if product == 'client-sdk'
|
34
|
+
product.camelcase
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.by_product(product, tutorials = [])
|
38
|
+
tutorials = all if tutorials.empty?
|
39
|
+
tutorials.select do |tutorial|
|
40
|
+
tutorial.products.include? product
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.by_language(language, tutorials = [])
|
45
|
+
language = language.downcase
|
46
|
+
tutorials = all if tutorials.empty?
|
47
|
+
|
48
|
+
tutorials.select do |tutorial|
|
49
|
+
tutorial.languages.map(&:downcase).include? language
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.origin
|
54
|
+
Pathname.new("_tutorials")
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.all
|
58
|
+
files.map do |document_path|
|
59
|
+
document_path = Pathname.new(document_path)
|
60
|
+
document = File.read(document_path)
|
61
|
+
frontmatter = YAML.safe_load(document)
|
62
|
+
|
63
|
+
new({
|
64
|
+
title: frontmatter['title'],
|
65
|
+
description: frontmatter['description'],
|
66
|
+
external_link: frontmatter['external_link'],
|
67
|
+
products: frontmatter['products'].split(',').map(&:strip),
|
68
|
+
languages: frontmatter['languages'] || [],
|
69
|
+
document_path: document_path,
|
70
|
+
})
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
private_class_method def self.files
|
77
|
+
Dir.glob("#{origin}/**/*.md")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'banzai'
|
2
|
+
|
3
|
+
Dir[File.join(__dir__, '../filters', '*.rb')].each { |f| require_relative f }
|
4
|
+
|
5
|
+
module Nexmo
|
6
|
+
module OAS
|
7
|
+
module Renderer
|
8
|
+
class MarkdownPipeline < Banzai::Pipeline
|
9
|
+
def initialize(options = {})
|
10
|
+
super(
|
11
|
+
# As Markdown
|
12
|
+
Filters::Frontmatter,
|
13
|
+
Filters::PHPInliner,
|
14
|
+
Filters::InlineEscape,
|
15
|
+
Filters::BlockEscape,
|
16
|
+
Filters::Screenshot,
|
17
|
+
Filters::Anchor,
|
18
|
+
Filters::Audio,
|
19
|
+
Filters::DynamicContent,
|
20
|
+
Filters::Tooltip,
|
21
|
+
Filters::Collapsible,
|
22
|
+
Filters::Tab.new(options),
|
23
|
+
Filters::CodeSnippets.new(options),
|
24
|
+
Filters::CodeSnippet.new(options),
|
25
|
+
Filters::Code,
|
26
|
+
Filters::Indent,
|
27
|
+
Filters::Modal,
|
28
|
+
Filters::JsSequenceDiagram,
|
29
|
+
Filters::Partial.new(options),
|
30
|
+
Filters::Techio,
|
31
|
+
Filters::Tutorials,
|
32
|
+
Filters::CodeSnippetList,
|
33
|
+
Filters::ConceptList,
|
34
|
+
Filters::Language,
|
35
|
+
Filters::Columns,
|
36
|
+
Filters::Markdown.new(options),
|
37
|
+
|
38
|
+
# As HTML
|
39
|
+
Filters::UserPersonalization.new(options),
|
40
|
+
Filters::Heading,
|
41
|
+
Filters::Label.new(options),
|
42
|
+
Filters::Break,
|
43
|
+
Filters::Unfreeze,
|
44
|
+
Filters::Icon,
|
45
|
+
Filters::ExternalLink,
|
46
|
+
Filters::TutorialLink
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Nexmo
|
2
|
+
module OAS
|
3
|
+
module Renderer
|
4
|
+
module Presenters
|
5
|
+
class ApiSpecification
|
6
|
+
|
7
|
+
def initialize(document_name:)
|
8
|
+
@document_name = document_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def side_navigation
|
12
|
+
"api/#{@document_name}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def document_path
|
16
|
+
"_api/#{@document_name}.md"
|
17
|
+
end
|
18
|
+
|
19
|
+
def document
|
20
|
+
@document ||= File.read(document_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def frontmatter
|
24
|
+
@frontmatter ||= YAML.safe_load(document)
|
25
|
+
end
|
26
|
+
|
27
|
+
def side_navigation_title
|
28
|
+
@side_navigation_title ||= frontmatter.fetch('api')
|
29
|
+
end
|
30
|
+
|
31
|
+
def document_title
|
32
|
+
@document_title ||= "#{side_navigation_title} > #{frontmatter.fetch('title')}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def content
|
36
|
+
@content ||= MarkdownPipeline.new.call(document)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Nexmo
|
2
|
+
module OAS
|
3
|
+
module Renderer
|
4
|
+
module Presenters
|
5
|
+
class Groups
|
6
|
+
def initialize(definition)
|
7
|
+
@definition = definition
|
8
|
+
end
|
9
|
+
|
10
|
+
def groups
|
11
|
+
tags = @definition.raw['tags']
|
12
|
+
# For now we only use the first tag in the list as an equivalent for the old x-group functionality
|
13
|
+
@groups = @definition.endpoints.group_by do |endpoint|
|
14
|
+
next nil unless tags
|
15
|
+
endpoint.raw['tags']&.first
|
16
|
+
end
|
17
|
+
|
18
|
+
# We want to use the order in which the tags are defined in the definition, so iterate over the tags
|
19
|
+
# and store the index against the tag name. We'll use this later for sorting
|
20
|
+
ordering = {}
|
21
|
+
tags&.each_with_index do |tag, index|
|
22
|
+
ordering[tag['name'].capitalize] = index
|
23
|
+
end
|
24
|
+
|
25
|
+
# Sort by the order in which they're defined in the definition
|
26
|
+
@groups = @groups.sort_by do |name, _|
|
27
|
+
next -1 if name.nil?
|
28
|
+
ordering[name.capitalize] || 999
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|