diff --git a/lib/asciidoctor-foodogsquared-extensions.rb b/lib/asciidoctor-foodogsquared-extensions.rb
index 5957c58..f0ce2cd 100644
--- a/lib/asciidoctor-foodogsquared-extensions.rb
+++ b/lib/asciidoctor-foodogsquared-extensions.rb
@@ -1,3 +1,3 @@
# frozen_string_literal: true
-require 'asciidoctor/foodogsquared-extensions'
+require 'asciidoctor/foodogsquared/extensions'
diff --git a/lib/asciidoctor/chat-block-processor/extension.rb b/lib/asciidoctor/chat-block-processor/extension.rb
deleted file mode 100644
index 6589db9..0000000
--- a/lib/asciidoctor/chat-block-processor/extension.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-class ChatBlock < Asciidoctor::Extensions::BlockProcessor
- use_dsl
-
- named :chat
- on_context :example
- name_positional_attributes 'avatar', 'state'
- default_attributes 'state' => 'default'
-
- def process(parent, reader, attrs)
- block = create_block parent, :pass, nil, attrs, content_model: :compound
- block.add_role('dialogblock')
-
- # You can think of this section as a pipeline constructing the HTML
- # component for this block. Specifically, we're building one component that
- # contains two output: the dialog image of our avatar and its content.
- attrs['name'] ||= attrs['avatar']
-
- block << (create_html_fragment block, <<~HTML
-
-
- HTML
-
- )
-
- attrs['avatarsdir'] ||= File.expand_path('./avatars', attrs['iconsdir'])
- attrs['avatarstype'] ||= parent.attributes['avatarstype'] || 'avif'
-
- avatar_sticker = "#{attrs['avatar'].to_kebab}/#{attrs['state'].to_kebab}.#{attrs['avatarstype']}"
- avatar_img_attrs = {
- 'target' => parent.image_uri(avatar_sticker, 'avatarsdir'),
- 'alt' => attrs['name']
- }
- avatar_imgblock = create_image_block block, avatar_img_attrs
-
- block << avatar_imgblock
- block << (create_html_fragment block, <<~HTML
-
-
- #{attrs['name']}
- HTML
- )
-
- parse_content block, reader
-
- block << (create_html_fragment block, <<~HTML
-
-
- HTML
- )
-
- block
- end
-
- private
-
- def create_html_fragment(parent, html, attributes = nil)
- create_block parent, :pass, html, attributes
- end
-end
diff --git a/lib/asciidoctor/fdroid-link-inline-macro/extension.rb b/lib/asciidoctor/fdroid-link-inline-macro/extension.rb
deleted file mode 100644
index ab86c9c..0000000
--- a/lib/asciidoctor/fdroid-link-inline-macro/extension.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-require 'open-uri'
-require 'yaml'
-
-class FDroidLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :fdroid
- name_positional_attributes 'caption'
- default_attributes 'lang' => 'en'
-
- def process(parent, target, attrs)
- doc = parent.document
-
- app_id = target
- app_metadata_uri = %(https://gitlab.com/fdroid/fdroiddata/-/raw/master/metadata/#{app_id}.yml)
-
- metadata = OpenURI.open_uri(app_metadata_uri) { |f| YAML.safe_load(f.read) }
- attrs['caption'] ||= metadata['AutoName']
-
- url = %(https://f-droid.org/#{attrs['lang']}/packages/#{app_id})
- doc.register :links, url
- create_anchor parent, attrs['caption'], type: :link, target: url
- end
-end
diff --git a/lib/asciidoctor/flathub-link-inline-macro/extension.rb b/lib/asciidoctor/flathub-link-inline-macro/extension.rb
deleted file mode 100644
index dc5cd51..0000000
--- a/lib/asciidoctor/flathub-link-inline-macro/extension.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-require 'json'
-require 'open-uri'
-
-class FlathubLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :flathub
- name_positional_attributes 'caption'
-
- def process(parent, target, attrs)
- doc = parent.document
-
- # FlatHub API seems to have no documentation aside from the source code.
- # You can easily infer the API with its source code at
- # https://github.com/flathub/website.
- app_id = target
- app_metadata_uri = %(https://flathub.org/api/v2/appstream/#{app_id})
-
- headers = {
- 'Accept' => 'application/json',
- 'User-Agent' => ::Asciidoctor::FoodogsquaredCustomExtensions::USER_AGENT
- }
-
- metadata = OpenURI.open_uri(app_metadata_uri, headers) { |f| JSON.parse(f.read) }
- attrs['caption'] ||= metadata['name']
-
- url = %(https://flathub.org/apps/#{app_id})
- doc.register :links, url
- create_anchor parent, attrs['caption'], type: :link, target: url
- end
-end
diff --git a/lib/asciidoctor/foodogsquared-extensions.rb b/lib/asciidoctor/foodogsquared-extensions.rb
deleted file mode 100644
index 7e4e9c8..0000000
--- a/lib/asciidoctor/foodogsquared-extensions.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# frozen_string_literal: true
-
-require 'asciidoctor'
-require 'asciidoctor/extensions'
-
-require_relative 'helpers'
-
-require_relative 'man-inline-macro/extension'
-require_relative 'swhid-inline-macro/extension'
-require_relative 'swhid-include-processor/extension'
-require_relative 'github-link-inline-macro/extension'
-require_relative 'github-raw-content-include-processor/extension'
-require_relative 'gitlab-link-inline-macro/extension'
-require_relative 'gitlab-raw-content-include-processor/extension'
-require_relative 'chat-block-processor/extension'
-require_relative 'git-blob-include-processor/extension'
-require_relative 'wikipedia-inline-macro/extension'
-require_relative 'package-indices-link-macro/extension'
-require_relative 'fdroid-link-inline-macro/extension'
-require_relative 'musicbrainz-link-inline-macro/extension'
-require_relative 'flathub-link-inline-macro/extension'
-require_relative 'repology-link-inline-macro/extension'
-require_relative 'ietf-rfc-link-inline-macro/extension'
-
-Asciidoctor::Extensions.register do
- inline_macro ManInlineMacro
- inline_macro IETFRFCLinkInlineMacro
- block ChatBlock if @document.basebackend? 'html'
-
- inline_macro SWHInlineMacro
- include_processor SWHIDIncludeProcessor
-
- inline_macro GitHubLinkInlineMacro
- include_processor GitHubRawIncludeProcessor
-
- inline_macro GitLabLinkInlineMacro
- include_processor GitLabRawIncludeProcessor
-
- include_processor GitBlobIncludeProcessor
-
- inline_macro WikipediaInlineMacro
-
- # Package indices
- inline_macro CtanLinkInlineMacro
- inline_macro PypiLinkInlineMacro
- inline_macro CratesIOLinkInlineMacro
-
- # App stores
- inline_macro FDroidLinkInlineMacro
- inline_macro FlathubLinkInlineMacro
-
- # Databases
- inline_macro MusicBrainzLinkInlineMacro
- inline_macro RepologyLinkInlineMacro
-end
diff --git a/lib/asciidoctor/chat-block-processor/README.adoc b/lib/asciidoctor/foodogsquared/chat-block/README.adoc
similarity index 100%
rename from lib/asciidoctor/chat-block-processor/README.adoc
rename to lib/asciidoctor/foodogsquared/chat-block/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/chat-block/extension.rb b/lib/asciidoctor/foodogsquared/chat-block/extension.rb
new file mode 100644
index 0000000..5214bdf
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/chat-block/extension.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+module Asciidoctor::Foodogsquared::Extensions
+ class ChatBlock < Asciidoctor::Extensions::BlockProcessor
+ use_dsl
+
+ named :chat
+ on_context :example
+ name_positional_attributes 'avatar', 'state'
+ default_attributes 'state' => 'default'
+
+ def process(parent, reader, attrs)
+ # You can think of this section as a pipeline constructing the HTML
+ # component for this block. Specifically, we're building one component that
+ # contains two output: the dialog image of our avatar and its content.
+ attrs['name'] ||= attrs['avatar']
+
+ block = create_block parent, :pass, nil, attrs, content_model: :compound
+ block.add_role('dialogblock')
+
+ block << (create_html_fragment block, <<~HTML
+
+
+ HTML
+
+ )
+
+ attrs['avatarsdir'] ||= File.expand_path('./avatars', attrs['iconsdir'])
+ attrs['avatarstype'] ||= parent.attributes['avatarstype'] || 'avif'
+
+ avatar_sticker = "#{attrs['avatar'].to_kebab}/#{attrs['state'].to_kebab}.#{attrs['avatarstype']}"
+ avatar_img_attrs = {
+ 'target' => parent.image_uri(avatar_sticker, 'avatarsdir'),
+ 'alt' => attrs['name']
+ }
+ avatar_imgblock = create_image_block block, avatar_img_attrs
+
+ block << avatar_imgblock
+ block << (create_html_fragment block, <<~HTML
+
+
+ #{attrs['name']}
+ HTML
+ )
+
+ parse_content block, reader
+
+ block << (create_html_fragment block, <<~HTML
+
+
+ HTML
+ )
+
+ block
+ end
+
+ private
+
+ def create_html_fragment(parent, html, attributes = nil)
+ create_block parent, :pass, html, attributes
+ end
+ end
+end
diff --git a/lib/asciidoctor/foodogsquared/extensions.rb b/lib/asciidoctor/foodogsquared/extensions.rb
new file mode 100644
index 0000000..33b52a6
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/extensions.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'asciidoctor'
+require 'asciidoctor/extensions'
+
+require_relative 'helpers'
+
+require_relative 'man-inline-macro/extension'
+require_relative 'swhid-inline-macro/extension'
+require_relative 'swhid-include-processor/extension'
+require_relative 'github-inline-macro/extension'
+require_relative 'github-include-processor/extension'
+require_relative 'gitlab-inline-macro/extension'
+require_relative 'gitlab-include-processor/extension'
+require_relative 'chat-block/extension'
+require_relative 'git-blob-include-processor/extension'
+require_relative 'wikipedia-inline-macro/extension'
+require_relative 'package-indices-macro/extension'
+require_relative 'fdroid-inline-macro/extension'
+require_relative 'musicbrainz-inline-macro/extension'
+require_relative 'flathub-inline-macro/extension'
+require_relative 'repology-inline-macro/extension'
+require_relative 'ietf-rfc-inline-macro/extension'
+
+include Asciidoctor::Foodogsquared::Extensions
+Asciidoctor::Extensions.register do
+
+ inline_macro ManInlineMacro
+ inline_macro IETFRFCInlineMacro
+ block ChatBlock if @document.basebackend? 'html'
+
+ inline_macro SWHInlineMacro
+ include_processor SWHIncludeProcessor
+
+ inline_macro GitHubInlineMacro
+ include_processor GitHubIncludeProcessor
+
+ inline_macro GitLabInlineMacro
+ include_processor GitLabIncludeProcessor
+
+ include_processor GitBlobIncludeProcessor
+
+ inline_macro WikipediaInlineMacro
+
+ # Package indices
+ inline_macro CtanInlineMacro
+ inline_macro PypiInlineMacro
+ inline_macro CratesIOInlineMacro
+
+ # App stores
+ inline_macro FDroidInlineMacro
+ inline_macro FlathubInlineMacro
+
+ # Databases
+ inline_macro MusicBrainzInlineMacro
+ inline_macro RepologyInlineMacro
+end
diff --git a/lib/asciidoctor/fdroid-link-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/fdroid-inline-macro/README.adoc
similarity index 100%
rename from lib/asciidoctor/fdroid-link-inline-macro/README.adoc
rename to lib/asciidoctor/foodogsquared/fdroid-inline-macro/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/fdroid-inline-macro/extension.rb b/lib/asciidoctor/foodogsquared/fdroid-inline-macro/extension.rb
new file mode 100644
index 0000000..b1c59ab
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/fdroid-inline-macro/extension.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'open-uri'
+require 'yaml'
+
+module Asciidoctor::Foodogsquared::Extensions
+ class FDroidInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :fdroid
+ name_positional_attributes 'caption'
+ default_attributes 'lang' => 'en'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+
+ app_id = target
+ app_metadata_uri = %(https://gitlab.com/fdroid/fdroiddata/-/raw/master/metadata/#{app_id}.yml)
+
+ metadata = OpenURI.open_uri(app_metadata_uri) { |f| YAML.safe_load(f.read) }
+ attrs['caption'] ||= metadata['AutoName']
+
+ url = %(https://f-droid.org/#{attrs['lang']}/packages/#{app_id})
+ doc.register :links, url
+ create_anchor parent, attrs['caption'], type: :link, target: url
+ end
+ end
+end
diff --git a/lib/asciidoctor/flathub-link-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/flathub-inline-macro/README.adoc
similarity index 100%
rename from lib/asciidoctor/flathub-link-inline-macro/README.adoc
rename to lib/asciidoctor/foodogsquared/flathub-inline-macro/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/flathub-inline-macro/extension.rb b/lib/asciidoctor/foodogsquared/flathub-inline-macro/extension.rb
new file mode 100644
index 0000000..30f77aa
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/flathub-inline-macro/extension.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'json'
+require 'open-uri'
+
+module Asciidoctor::Foodogsquared::Extensions
+ class FlathubInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :flathub
+ name_positional_attributes 'caption'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+
+ # FlatHub API seems to have no documentation aside from the source code.
+ # You can easily infer the API with its source code at
+ # https://github.com/flathub/website.
+ app_id = target
+ app_metadata_uri = %(https://flathub.org/api/v2/appstream/#{app_id})
+
+ headers = {
+ 'Accept' => 'application/json',
+ 'User-Agent' => ::Asciidoctor::Foodogsquared::USER_AGENT
+ }
+
+ metadata = OpenURI.open_uri(app_metadata_uri, headers) { |f| JSON.parse(f.read) }
+ attrs['caption'] ||= metadata['name']
+
+ url = %(https://flathub.org/apps/#{app_id})
+ doc.register :links, url
+ create_anchor parent, attrs['caption'], type: :link, target: url
+ end
+ end
+end
diff --git a/lib/asciidoctor/git-blob-include-processor/README.adoc b/lib/asciidoctor/foodogsquared/git-blob-include-processor/README.adoc
similarity index 100%
rename from lib/asciidoctor/git-blob-include-processor/README.adoc
rename to lib/asciidoctor/foodogsquared/git-blob-include-processor/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/git-blob-include-processor/extension.rb b/lib/asciidoctor/foodogsquared/git-blob-include-processor/extension.rb
new file mode 100644
index 0000000..55c0931
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/git-blob-include-processor/extension.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'rugged'
+
+module Asciidoctor::Foodogsquared::Extensions
+ class GitBlobIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
+ def handles?(target)
+ target.start_with? 'git:'
+ end
+
+ def process(doc, reader, target, attrs)
+ attrs['gitrepo'] ||= doc.attributes['gitrepo'] || doc.base_dir
+ repo = Rugged::Repository.discover(attrs['gitrepo'])
+
+ git_object_ref = target.delete_prefix 'git:'
+ git_object_ref = doc.attributes['doccontentref'] if git_object_ref.empty?
+
+ begin
+ git_object = repo.rev_parse git_object_ref
+
+ if attrs.key? 'diff-option'
+ options = {}
+
+ options[:paths] = attrs['path'].split(';') if attrs.key? 'path'
+ options[:context_lines] = attrs['context-lines'] if attrs.key? 'context-lines'
+ options[:reverse] = true if attrs.key? 'reverse-option'
+
+ if attrs.key? 'other'
+ other = repo.rev_parse attrs['other'] || nil
+ reader.push_include git_object.diff(other, **options).patch
+ else
+ reader.push_include git_object.diff(**options).patch
+ end
+ else
+ inner_entry = case git_object.type
+ when :blob
+ git_object
+ when :commit
+ git_object.tree.path attrs['path']
+ when :tree
+ git_object.path attrs['path']
+ when :tag
+ git_object.target.tree.path attrs['path']
+ end
+
+ content = repo.lookup(inner_entry[:oid]).content
+
+ if attrs.key? 'lines'
+ content_lines = content.lines
+ new_content = +''
+ doc.resolve_lines_to_highlight(content, attrs['lines']).each do |line_no|
+ new_content << content_lines.at(line_no - 1)
+ end
+
+ content = new_content
+ end
+
+ reader.push_include content
+ end
+ rescue StandardError => e
+ reader.push_include "Unresolved directive for '#{target}' with the following error:\n#{e}"
+ warn e
+ end
+
+ reader
+ end
+ end
+end
diff --git a/lib/asciidoctor/github-raw-content-include-processor/README.adoc b/lib/asciidoctor/foodogsquared/github-include-processor/README.adoc
similarity index 100%
rename from lib/asciidoctor/github-raw-content-include-processor/README.adoc
rename to lib/asciidoctor/foodogsquared/github-include-processor/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/github-include-processor/extension.rb b/lib/asciidoctor/foodogsquared/github-include-processor/extension.rb
new file mode 100644
index 0000000..1a1cd27
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/github-include-processor/extension.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'base64'
+require 'json'
+require 'open-uri'
+require 'uri'
+
+module Asciidoctor::Foodogsquared::Extensions
+ class GitHubIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
+ def handles?(target)
+ target.start_with? 'github:'
+ end
+
+ def warn_or_raise(doc, warning)
+ if (doc.safe > Asciidoctor::SafeMode::SERVER) && !(doc.attr? 'allow-uri-read')
+ raise warning
+ else
+ warn warning
+ end
+ end
+
+ def process(doc, reader, target, attrs)
+ src = target.delete_prefix('github:').split('/', 3)
+ owner = src.at 0
+ repo = src.at 1
+ namespaced_repo = "#{owner}/#{repo}"
+
+ path = attrs['path'] || ''
+
+ # For more information, see https://docs.github.com/en/rest/repos/contents.
+ uri = URI.parse %(https://api.github.com/repos/#{owner}/#{repo}/contents/#{path})
+
+ if attrs['rev']
+ query = { ref: attrs['rev'] }
+ uri.query = URI.encode_www_form query
+ end
+
+ begin
+ headers = {
+ 'Header' => 'application/vnd.github+json',
+ 'X-GitHub-Api-Version' => '2022-11-28'
+ }
+
+ headers['Authorization'] = "Token #{ENV['GITHUB_API_BEARER_TOKEN']}" if ENV['GITHUB_API_BEARER_TOKEN']
+
+ OpenURI.open_uri(uri, headers) do |f|
+ response = JSON.parse(f.read)
+
+ # If the response is an array, it is likely to be a directory. In this
+ # usecase, we'll just list them.
+ content = if response.is_a? Array
+ warning = %(given path '#{path}' from GitHub repo '#{repo}' is a directory)
+ warn_or_raise doc, warning
+ warning
+ elsif response.is_a? Object
+ Base64.decode64 response['content'] if response['content'] && response['encoding'] == 'base64'
+ end
+
+ reader.push_include content, target, target, 1, attrs
+ end
+ rescue OpenURI::HTTPError => e
+ warning = %(error while getting '#{path}' in GitHub repo '#{namespaced_repo}: #{e}')
+ warn_or_raise doc, warning
+ reader.push_include warning, target, target, 1, attrs
+ end
+
+ reader
+ end
+ end
+end
diff --git a/lib/asciidoctor/github-link-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/github-inline-macro/README.adoc
similarity index 100%
rename from lib/asciidoctor/github-link-inline-macro/README.adoc
rename to lib/asciidoctor/foodogsquared/github-inline-macro/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/github-inline-macro/extension.rb b/lib/asciidoctor/foodogsquared/github-inline-macro/extension.rb
new file mode 100644
index 0000000..ca3870e
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/github-inline-macro/extension.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'uri'
+
+module Asciidoctor::Foodogsquared::Extensions
+ class GitHubInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :github
+ name_positional_attributes 'caption'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+
+ default_caption = if attrs.key?('repo-option')
+ target.split('/').at(1)
+ else
+ target
+ end
+ text = attrs['caption'] || default_caption
+ uri = URI.parse %(https://github.com/#{target})
+
+ if attrs.key? 'issue'
+ uri.path += %(/issues/#{attrs['issue']})
+ text << "##{attrs['issue']}" if text == target
+ else
+ uri.path += %(/tree/#{attrs['rev']}) if attrs.key? 'rev'
+ uri.path += %(/#{attrs['path']}) if attrs.key? 'path'
+ text << "@#{attrs['rev']}" if attrs.key?('rev') && text == target
+ end
+
+ target = uri.to_s
+
+ doc.register :links, target
+ create_anchor parent, text, type: :link, target: target
+ end
+ end
+end
diff --git a/lib/asciidoctor/gitlab-raw-content-include-processor/README.adoc b/lib/asciidoctor/foodogsquared/gitlab-include-processor/README.adoc
similarity index 100%
rename from lib/asciidoctor/gitlab-raw-content-include-processor/README.adoc
rename to lib/asciidoctor/foodogsquared/gitlab-include-processor/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/gitlab-include-processor/extension.rb b/lib/asciidoctor/foodogsquared/gitlab-include-processor/extension.rb
new file mode 100644
index 0000000..a1bdd10
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/gitlab-include-processor/extension.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'base64'
+require 'json'
+require 'open-uri'
+require 'uri'
+
+module Asciidoctor::Foodogsquared::Extensions
+ class GitLabIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
+ def handles?(target)
+ target.start_with? 'gitlab:'
+ end
+
+ def process(doc, reader, target, attrs)
+ src = target.delete_prefix('gitlab:').split('/', 2)
+ owner = src.at 0
+ repo = src.at 1
+ namespaced_repo = "#{owner}/#{repo}"
+
+ raise %(there is no 'path' attribute given for GitLab repo '#{namespaced_repo}') unless attrs.key? 'path'
+ raise %(no given ref for getting file in '#{namespaced_repo}') unless attrs.key? 'rev'
+
+ path = attrs['path']
+ rev = attrs['rev']
+
+ domain = attrs['domain'] || 'gitlab.com'
+ version = attrs['version'] || 'v4'
+
+ uri = URI.parse %(https://#{domain}/api/#{version})
+
+ # Set the project.
+ uri += %(/projects/#{URI.encode_www_form_component namespaced_repo})
+
+ # Then the filename.
+ uri += %(/repository/files/#{URI.encode_www_form_component path})
+
+ # Then the revision.
+ query = { ref: rev }
+ uri.query = URI.encode_www_form query
+
+ content = begin
+ headers = { 'Content-Type' => 'application-json' }
+ header['PRIVATE-TOKEN'] = ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN'] if ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN']
+
+ OpenURI.open_uri(uri, headers) do |f|
+ response = JSON.parse(f.read)
+
+ Base64.decode64 response['content'] if response['content'] && response['encoding'] == 'base64'
+ end
+ rescue OpenURI::HTTPError => e
+ warning = %(error while getting '#{path}' in GitLab repo '#{repo}': #{e})
+ warn_or_raise doc, warning
+ warning
+ end
+
+ reader.push_include content, target, target, 1, attrs
+ reader
+ end
+ end
+end
diff --git a/lib/asciidoctor/gitlab-link-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/gitlab-inline-macro/README.adoc
similarity index 100%
rename from lib/asciidoctor/gitlab-link-inline-macro/README.adoc
rename to lib/asciidoctor/foodogsquared/gitlab-inline-macro/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/gitlab-inline-macro/extension.rb b/lib/asciidoctor/foodogsquared/gitlab-inline-macro/extension.rb
new file mode 100644
index 0000000..0b5be3e
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/gitlab-inline-macro/extension.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'uri'
+
+module Asciidoctor::Foodogsquared::Extensions
+ class GitLabInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :gitlab
+ name_positional_attributes 'caption'
+ default_attributes 'domain' => 'gitlab.com'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+
+ default_caption = if attrs.key?('repo-option')
+ target.split('/').at(1)
+ else
+ target
+ end
+ text = attrs['caption'] || default_caption
+ uri = URI.parse %(https://#{attrs['domain']}/#{target})
+
+ if attrs.key? 'issue'
+ uri.path += %(/-/issues/#{attrs['issue']})
+ text << "##{attrs['issue']}" if text == target
+ else
+ uri.path += %(/-/tree/#{attrs['rev']}) if attrs.key? 'rev'
+ uri.path += %(/#{attrs['path']}) if attrs.key? 'path'
+ text << "@#{attrs['rev']}" if attrs.key?('rev') && text == target
+ end
+
+ target = uri.to_s
+
+ doc.register :links, target
+ create_anchor parent, text, type: :link, target: target
+ end
+ end
+end
diff --git a/lib/asciidoctor/foodogsquared/helpers.rb b/lib/asciidoctor/foodogsquared/helpers.rb
new file mode 100644
index 0000000..49ef7f6
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/helpers.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class String
+ def to_kebab
+ self.gsub(/\s+/, '-') # Replace all spaces with dashes.
+ .gsub(/[^a-zA-Z0-9-]/, '') # Remove all non-alphanumerical (and dashes) characters.
+ .gsub(/-+/, '-') # Reduce all dashes into only one.
+ .gsub(/^-|-+$/, '') # Remove all leading and trailing dashes.
+ .downcase
+ end
+end
+
+# The namespace for storing Asciidoctor. This is the entry point for the
+# entirety of this project.
+module Asciidoctor::Foodogsquared
+ NAME = 'asciidoctor-foodogsquared-custom-extensions'
+ VERSION = '1.2.0'
+ CONTACT_EMAIL = 'foodogsquared@foodogsquared.one'
+ USER_AGENT = "#{NAME}/#{VERSION} ( #{CONTACT_EMAIL} )".freeze
+
+ def warn_or_raise(doc, warning)
+ return raise warning if (doc.safe > Asciidoctor::SafeMode::SERVER) && !(doc.attr? 'allow-uri-read')
+
+ warn warning
+ end
+end
diff --git a/lib/asciidoctor/ietf-rfc-link-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/ietf-rfc-inline-macro/README.adoc
similarity index 100%
rename from lib/asciidoctor/ietf-rfc-link-inline-macro/README.adoc
rename to lib/asciidoctor/foodogsquared/ietf-rfc-inline-macro/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/ietf-rfc-inline-macro/extension.rb b/lib/asciidoctor/foodogsquared/ietf-rfc-inline-macro/extension.rb
new file mode 100644
index 0000000..a13973a
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/ietf-rfc-inline-macro/extension.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Asciidoctor::Foodogsquared::Extensions
+ class IETFRFCInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :rfc
+ name_positional_attributes 'caption'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+ url = %(https://datatracker.ietf.org/doc/html/#{target})
+ attrs['caption'] ||= "RFC#{target}"
+ doc.register :links, url
+ create_anchor parent, attrs['caption'], type: :link, target: url
+ end
+ end
+end
diff --git a/lib/asciidoctor/man-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/man-inline-macro/README.adoc
similarity index 100%
rename from lib/asciidoctor/man-inline-macro/README.adoc
rename to lib/asciidoctor/foodogsquared/man-inline-macro/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/man-inline-macro/extension.rb b/lib/asciidoctor/foodogsquared/man-inline-macro/extension.rb
new file mode 100644
index 0000000..aba87b7
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/man-inline-macro/extension.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module Asciidoctor::Foodogsquared::Extensions
+ class ManInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :man
+ name_positional_attributes 'volnum'
+ default_attributes 'service' => 'debian', 'subpath' => ''
+
+ def process(parent, target, attrs)
+ doc = parent.document
+ manname = target
+
+ text = %(#{manname}(#{attrs['volnum']}))
+
+ if doc.basebackend? 'html'
+ domain = case attrs['service']
+ when 'debian'
+ 'https://manpages.debian.org'
+ when 'ubuntu'
+ 'https://manpages.ubuntu.org'
+ when 'arch'
+ 'https://man.archlinux.org/man'
+ when 'opensuse'
+ 'https://manpages.opensuse.org'
+ when 'voidlinux'
+ 'https://man.voidlinux.org'
+ when 'openbsd'
+ 'https://man.openbsd.org'
+ when 'none'
+ nil
+ else
+ raise "no available manpage service #{attrs['service']}"
+ end
+
+ if !domain.nil?
+ target = %(#{domain}/#{attrs['subpath'].delete_prefix '/'}#{manname}.#{attrs['volnum']})
+ doc.register :links, target
+ node = create_anchor parent, text, type: :link, target: target
+ else
+ node = create_inline parent, :quoted, text
+ end
+ elsif doc.backend == 'manpage'
+ node = create_inline parent, :quoted, text, type: :strong
+ else
+ node = create_inline parent, :quoted, text
+ end
+
+ node
+ end
+ end
+end
diff --git a/lib/asciidoctor/musicbrainz-link-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/musicbrainz-inline-macro/README.adoc
similarity index 100%
rename from lib/asciidoctor/musicbrainz-link-inline-macro/README.adoc
rename to lib/asciidoctor/foodogsquared/musicbrainz-inline-macro/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/musicbrainz-inline-macro/extension.rb b/lib/asciidoctor/foodogsquared/musicbrainz-inline-macro/extension.rb
new file mode 100644
index 0000000..915f002
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/musicbrainz-inline-macro/extension.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'json'
+require 'open-uri'
+require 'uri'
+
+module Asciidoctor::Foodogsquared::Extensions
+ class MusicBrainzInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :musicbrainz
+ name_positional_attributes 'caption', 'type'
+ default_attributes 'type' => 'release'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+ root_endpoint = 'https://musicbrainz.org/ws/2'
+
+ begin
+ headers = {
+ 'Accept' => 'application/json',
+ 'User-Agent' => ::Asciidoctor::Foodogsquared::USER_AGENT
+ }
+
+ uri = %(#{root_endpoint}/#{attrs['type']}/#{target})
+
+ metadata = OpenURI.open_uri(uri, headers) { |f| JSON.parse(f.read) }
+ attrs['caption'] ||= case attrs['type']
+ when 'artist', 'area', 'events', 'genre', 'instrument', 'label', 'place', 'series'
+ metadata['name']
+ when 'recording', 'release-group', 'release', 'cdstub', 'work'
+ metadata['title']
+ when 'url'
+ metadata['resource']
+ end
+
+ target = %(https://musicbrainz.org/#{attrs['type']}/#{target})
+ doc.register :links, target
+ create_anchor parent, attrs['caption'], type: :link, target: target
+ rescue StandardError
+ warning = %(error while getting Musicbrainz database object '#{target}: #{e}')
+ warn_or_raise doc, warning
+ reader.push_include warning, target, target, 1, attrs
+ end
+ end
+ end
+end
diff --git a/lib/asciidoctor/foodogsquared/package-indices-macro/extension.rb b/lib/asciidoctor/foodogsquared/package-indices-macro/extension.rb
new file mode 100644
index 0000000..851cae3
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/package-indices-macro/extension.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+# I'm fairly sure this could be programmed since Ruby has nice metaprogramming
+# capabilities. Though, we'll be keeping it manually defining classes for now
+# for initial versions since there could be additional features for each macro.
+
+module Asciidoctor::Foodogsquared::Extensions
+ class CtanInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :ctan
+ name_positional_attributes 'caption'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+ text = attrs['caption'] || target
+ url = %(https://ctan.org/pkg/#{target})
+
+ doc.register :links, url
+
+ create_anchor parent, text, type: :link, target: url
+ end
+ end
+
+ class PypiInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :pypi
+ name_positional_attributes 'caption'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+ text = attrs['caption'] || target
+ url = %(https://pypi.org/project/#{target})
+
+ doc.register :links, url
+
+ create_anchor parent, text, type: :link, target: url
+ end
+ end
+
+ class CratesIOInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :cratesio
+ name_positional_attributes 'caption'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+ text = attrs['caption'] || target
+ url = %(https://crates.io/crates/#{target})
+
+ doc.register :links, url
+
+ create_anchor parent, text, type: :link, target: url
+ end
+ end
+end
diff --git a/lib/asciidoctor/repology-link-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/repology-inline-macro/README.adoc
similarity index 100%
rename from lib/asciidoctor/repology-link-inline-macro/README.adoc
rename to lib/asciidoctor/foodogsquared/repology-inline-macro/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/repology-inline-macro/extension.rb b/lib/asciidoctor/foodogsquared/repology-inline-macro/extension.rb
new file mode 100644
index 0000000..9fdc355
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/repology-inline-macro/extension.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Asciidoctor::Foodogsquared::Extensions
+ class RepologyInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :repology
+ name_positional_attributes 'caption'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+ text = attrs['caption'] || target
+ url = %(https://repology.org/project/#{target})
+
+ doc.register :links, url
+
+ create_anchor parent, text, type: :link, target: url
+ end
+ end
+end
diff --git a/lib/asciidoctor/foodogsquared/spdx-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/spdx-inline-macro/README.adoc
new file mode 100644
index 0000000..0d20143
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/spdx-inline-macro/README.adoc
@@ -0,0 +1,26 @@
+= SPDX link inline macro
+:toc:
+
+It's an inline macro for easily creating licenses from SPDX license data.
+
+
+== Synopsis
+
+[source, asciidoc]
+----
+spdx:$LICENSE_ID[$CAPTION]
+----
+
+Where...
+
+* `$LICENSE_ID` is the identifier for the license.
+
+* `$CAPTION` is the link caption to be used.
+By default, it will use the name of the license.
+
+
+== Example usage
+
+* `spdx:MIT[]` will result to the link:https://spdx.org/licenses/MIT.html[MIT license page on SPDX] with the caption `MIT License`.
+
+* `spdx:MIT[the MIT license]` is the same as the previous example but with a different caption of `the MIT license`.
diff --git a/lib/asciidoctor/swhid-include-processor/README.adoc b/lib/asciidoctor/foodogsquared/swhid-include-processor/README.adoc
similarity index 100%
rename from lib/asciidoctor/swhid-include-processor/README.adoc
rename to lib/asciidoctor/foodogsquared/swhid-include-processor/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/swhid-include-processor/extension.rb b/lib/asciidoctor/foodogsquared/swhid-include-processor/extension.rb
new file mode 100644
index 0000000..94c21e2
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/swhid-include-processor/extension.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'json'
+require 'open-uri'
+require 'uri'
+
+module Asciidoctor::Foodogsquared::Extensions
+ class SWHIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
+ def handles?(target)
+ target.start_with? 'swh:'
+ end
+
+ def process(doc, reader, target, attributes)
+ swhid = target
+ swhid_core_identifier = swhid.split(';').at(0)
+ swhid_object_type = (swhid_core_identifier.split ':').at 2
+
+ unless (doc.safe <= Asciidoctor::SafeMode::SERVER) && (doc.attr? 'allow-uri-read')
+ raise %('swh:' include cannot be used in safe mode level > SERVER and without attribute 'allow-uri-read')
+ end
+
+ # We're already going to throw out anything that is not content object type
+ # just to make the later pipelines easier to construct.
+ if swhid_object_type != 'cnt'
+ warn %(SWHID '#{swhid_core_identifier}' is not of 'cnt' type; ignoring)
+ return reader
+ end
+
+ version = '1'
+
+ content = begin
+ uri = URI.parse %(https://archive.softwareheritage.org/api/#{version}/resolve/#{target}/)
+
+ headers = {
+ 'Accept' => 'application/json'
+ }
+
+ headers['Authorization'] = "Bearer #{ENV['SWH_API_BEARER_TOKEN']}" if ENV['SWH_API_BEARER_TOKEN']
+
+ metadata = OpenURI.open_uri(uri, headers) { |f| JSON.parse(f.read) }
+ object_hash = metadata['object_id']
+
+ uri = URI.parse %(https://archive.softwareheritage.org/api/#{version}/content/sha1_git:#{object_hash}/raw/)
+ OpenURI.open_uri(uri, headers, &:read)
+ rescue OpenURI::HTTPError => e
+ warning = %(error while getting '#{swhid_core_identifier}': #{e})
+ warn warning
+ warning
+ end
+
+ reader.push_include content, target, target, 1, attributes
+ reader
+ end
+ end
+end
diff --git a/lib/asciidoctor/swhid-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/swhid-inline-macro/README.adoc
similarity index 100%
rename from lib/asciidoctor/swhid-inline-macro/README.adoc
rename to lib/asciidoctor/foodogsquared/swhid-inline-macro/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/swhid-inline-macro/extension.rb b/lib/asciidoctor/foodogsquared/swhid-inline-macro/extension.rb
new file mode 100644
index 0000000..d69d314
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/swhid-inline-macro/extension.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Asciidoctor::Foodogsquared::Extensions
+ class SWHInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :swh
+ name_positional_attributes 'caption'
+
+ def process(parent, target, attrs)
+ doc = parent.document
+
+ # We're only considering `swh:` starting with the scheme version. Also, it
+ # looks nice aesthetically.
+ swhid = target.start_with?('swh:') ? target : %(swh:#{target})
+ default_caption = if attrs.key? 'full-option'
+ swhid
+ else
+ swhid.split(';').at(0)
+ end
+ text = attrs['caption'] || default_caption
+ target = %(https://archive.softwareheritage.org/#{swhid})
+
+ doc.register :links, target
+ create_anchor parent, text, type: :link, target: target
+ end
+ end
+end
diff --git a/lib/asciidoctor/wikipedia-inline-macro/README.adoc b/lib/asciidoctor/foodogsquared/wikipedia-inline-macro/README.adoc
similarity index 100%
rename from lib/asciidoctor/wikipedia-inline-macro/README.adoc
rename to lib/asciidoctor/foodogsquared/wikipedia-inline-macro/README.adoc
diff --git a/lib/asciidoctor/foodogsquared/wikipedia-inline-macro/extension.rb b/lib/asciidoctor/foodogsquared/wikipedia-inline-macro/extension.rb
new file mode 100644
index 0000000..1b7d5db
--- /dev/null
+++ b/lib/asciidoctor/foodogsquared/wikipedia-inline-macro/extension.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'uri'
+
+module Asciidoctor::Foodogsquared::Extensions
+ class WikipediaInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :wikipedia
+ name_positional_attributes 'caption'
+ default_attributes 'lang' => 'en'
+
+ def process(parent, target, attrs)
+ caption = attrs['caption'] || target
+ parser = URI::Parser.new
+ page = parser.escape target
+ link = %(https://#{attrs['lang']}.wikipedia.org/wiki/#{page})
+ node = create_anchor parent, caption, type: :link, target: link
+
+ create_inline parent, :quoted, node.convert
+ end
+ end
+end
diff --git a/lib/asciidoctor/git-blob-include-processor/extension.rb b/lib/asciidoctor/git-blob-include-processor/extension.rb
deleted file mode 100644
index 1291aba..0000000
--- a/lib/asciidoctor/git-blob-include-processor/extension.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-# frozen_string_literal: true
-
-require 'rugged'
-
-class GitBlobIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
- def handles?(target)
- target.start_with? 'git:'
- end
-
- def process(doc, reader, target, attrs)
- attrs['gitrepo'] ||= doc.attributes['gitrepo'] || doc.base_dir
- repo = Rugged::Repository.discover(attrs['gitrepo'])
-
- git_object_ref = target.delete_prefix 'git:'
- git_object_ref = doc.attributes['doccontentref'] if git_object_ref.empty?
-
- begin
- git_object = repo.rev_parse git_object_ref
-
- if attrs.key? 'diff-option'
- options = {}
-
- options[:paths] = attrs['path'].split(';') if attrs.key? 'path'
- options[:context_lines] = attrs['context-lines'] if attrs.key? 'context-lines'
- options[:reverse] = true if attrs.key? 'reverse-option'
-
- if attrs.key? 'other'
- other = repo.rev_parse attrs['other'] || nil
- reader.push_include git_object.diff(other, **options).patch
- else
- reader.push_include git_object.diff(**options).patch
- end
- else
- inner_entry = case git_object.type
- when :blob
- git_object
- when :commit
- git_object.tree.path attrs['path']
- when :tree
- git_object.path attrs['path']
- when :tag
- git_object.target.tree.path attrs['path']
- end
-
- content = repo.lookup(inner_entry[:oid]).content
-
- if attrs.key? 'lines'
- content_lines = content.lines
- new_content = +''
- doc.resolve_lines_to_highlight(content, attrs['lines']).each do |line_no|
- new_content << content_lines.at(line_no - 1)
- end
-
- content = new_content
- end
-
- reader.push_include content
- end
- rescue StandardError => e
- reader.push_include "Unresolved directive for '#{target}' with the following error:\n#{e}"
- warn e
- end
-
- reader
- end
-end
diff --git a/lib/asciidoctor/github-link-inline-macro/extension.rb b/lib/asciidoctor/github-link-inline-macro/extension.rb
deleted file mode 100644
index 32366a8..0000000
--- a/lib/asciidoctor/github-link-inline-macro/extension.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-require 'uri'
-
-class GitHubLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :github
- name_positional_attributes 'caption'
-
- def process(parent, target, attrs)
- doc = parent.document
-
- default_caption = if attrs.key?('repo-option')
- target.split('/').at(1)
- else
- target
- end
- text = attrs['caption'] || default_caption
- uri = URI.parse %(https://github.com/#{target})
-
- if attrs.key? 'issue'
- uri.path += %(/issues/#{attrs['issue']})
- text << "##{attrs['issue']}" if text == target
- else
- uri.path += %(/tree/#{attrs['rev']}) if attrs.key? 'rev'
- uri.path += %(/#{attrs['path']}) if attrs.key? 'path'
- text << "@#{attrs['rev']}" if attrs.key?('rev') && text == target
- end
-
- target = uri.to_s
-
- doc.register :links, target
- create_anchor parent, text, type: :link, target: target
- end
-end
diff --git a/lib/asciidoctor/github-raw-content-include-processor/extension.rb b/lib/asciidoctor/github-raw-content-include-processor/extension.rb
deleted file mode 100644
index 20bdda8..0000000
--- a/lib/asciidoctor/github-raw-content-include-processor/extension.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-# frozen_string_literal: true
-
-require 'base64'
-require 'json'
-require 'open-uri'
-require 'uri'
-
-class GitHubRawIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
- def handles?(target)
- target.start_with? 'github:'
- end
-
- def warn_or_raise(doc, warning)
- if (doc.safe > Asciidoctor::SafeMode::SERVER) && !(doc.attr? 'allow-uri-read')
- raise warning
- else
- warn warning
- end
- end
-
- def process(doc, reader, target, attrs)
- src = target.delete_prefix('github:').split('/', 3)
- owner = src.at 0
- repo = src.at 1
- namespaced_repo = "#{owner}/#{repo}"
-
- path = attrs['path'] || ''
-
- # For more information, see https://docs.github.com/en/rest/repos/contents.
- uri = URI.parse %(https://api.github.com/repos/#{owner}/#{repo}/contents/#{path})
-
- if attrs['rev']
- query = { ref: attrs['rev'] }
- uri.query = URI.encode_www_form query
- end
-
- begin
- headers = {
- 'Header' => 'application/vnd.github+json',
- 'X-GitHub-Api-Version' => '2022-11-28'
- }
-
- headers['Authorization'] = "Token #{ENV['GITHUB_API_BEARER_TOKEN']}" if ENV['GITHUB_API_BEARER_TOKEN']
-
- OpenURI.open_uri(uri, headers) do |f|
- response = JSON.parse(f.read)
-
- # If the response is an array, it is likely to be a directory. In this
- # usecase, we'll just list them.
- content = if response.is_a? Array
- warning = %(given path '#{path}' from GitHub repo '#{repo}' is a directory)
- warn_or_raise doc, warning
- warning
- elsif response.is_a? Object
- Base64.decode64 response['content'] if response['content'] && response['encoding'] == 'base64'
- end
-
- reader.push_include content, target, target, 1, attrs
- end
- rescue OpenURI::HTTPError => e
- warning = %(error while getting '#{path}' in GitHub repo '#{namespaced_repo}: #{e}')
- warn_or_raise doc, warning
- reader.push_include warning, target, target, 1, attrs
- end
-
- reader
- end
-end
diff --git a/lib/asciidoctor/gitlab-link-inline-macro/extension.rb b/lib/asciidoctor/gitlab-link-inline-macro/extension.rb
deleted file mode 100644
index 6d40e26..0000000
--- a/lib/asciidoctor/gitlab-link-inline-macro/extension.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-require 'uri'
-
-class GitLabLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :gitlab
- name_positional_attributes 'caption'
- default_attributes 'domain' => 'gitlab.com'
-
- def process(parent, target, attrs)
- doc = parent.document
-
- default_caption = if attrs.key?('repo-option')
- target.split('/').at(1)
- else
- target
- end
- text = attrs['caption'] || default_caption
- uri = URI.parse %(https://#{attrs['domain']}/#{target})
-
- if attrs.key? 'issue'
- uri.path += %(/-/issues/#{attrs['issue']})
- text << "##{attrs['issue']}" if text == target
- else
- uri.path += %(/-/tree/#{attrs['rev']}) if attrs.key? 'rev'
- uri.path += %(/#{attrs['path']}) if attrs.key? 'path'
- text << "@#{attrs['rev']}" if attrs.key?('rev') && text == target
- end
-
- target = uri.to_s
-
- doc.register :links, target
- create_anchor parent, text, type: :link, target: target
- end
-end
diff --git a/lib/asciidoctor/gitlab-raw-content-include-processor/extension.rb b/lib/asciidoctor/gitlab-raw-content-include-processor/extension.rb
deleted file mode 100644
index 770fded..0000000
--- a/lib/asciidoctor/gitlab-raw-content-include-processor/extension.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-# frozen_string_literal: true
-
-require 'base64'
-require 'json'
-require 'open-uri'
-require 'uri'
-
-class GitLabRawIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
- def handles?(target)
- target.start_with? 'gitlab:'
- end
-
- def warn_or_raise(doc, warning)
- if (doc.safe > Asciidoctor::SafeMode::SERVER) && !(doc.attr? 'allow-uri-read')
- raise warning
- else
- warn warning
- end
- end
-
- def process(doc, reader, target, attrs)
- src = target.delete_prefix('gitlab:').split('/', 2)
- owner = src.at 0
- repo = src.at 1
- namespaced_repo = "#{owner}/#{repo}"
-
- raise %(there is no 'path' attribute given for GitLab repo '#{namespaced_repo}') unless attrs.key? 'path'
- raise %(no given ref for getting file in '#{namespaced_repo}') unless attrs.key? 'rev'
-
- path = attrs['path']
- rev = attrs['rev']
-
- domain = attrs['domain'] || 'gitlab.com'
- version = attrs['version'] || 'v4'
-
- uri = URI.parse %(https://#{domain}/api/#{version})
-
- # Set the project.
- uri += %(/projects/#{URI.encode_www_form_component namespaced_repo})
-
- # Then the filename.
- uri += %(/repository/files/#{URI.encode_www_form_component path})
-
- # Then the revision.
- query = { ref: rev }
- uri.query = URI.encode_www_form query
-
- content = begin
- headers = { 'Content-Type' => 'application-json' }
- header['PRIVATE-TOKEN'] = ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN'] if ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN']
-
- OpenURI.open_uri(uri, headers) do |f|
- response = JSON.parse(f.read)
-
- Base64.decode64 response['content'] if response['content'] && response['encoding'] == 'base64'
- end
- rescue OpenURI::HTTPError => e
- warning = %(error while getting '#{path}' in GitLab repo '#{repo}': #{e})
- warn_or_raise doc, warning
- warning
- end
-
- reader.push_include content, target, target, 1, attrs
- reader
- end
-end
diff --git a/lib/asciidoctor/helpers.rb b/lib/asciidoctor/helpers.rb
deleted file mode 100644
index c5e1f99..0000000
--- a/lib/asciidoctor/helpers.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-class String
- def to_kebab
- self.gsub(/\s+/, '-') # Replace all spaces with dashes.
- .gsub(/[^a-zA-Z0-9-]/, '') # Remove all non-alphanumerical (and dashes) characters.
- .gsub(/-+/, '-') # Reduce all dashes into only one.
- .gsub(/^-|-+$/, '') # Remove all leading and trailing dashes.
- .downcase
- end
-end
-
-module Asciidoctor
- module FoodogsquaredCustomExtensions
- NAME = 'asciidoctor-foodogsquared-custom-extensions'
- VERSION = '1.0.0'
- CONTACT_EMAIL = 'foodogsquared@foodogsquared.one'
- USER_AGENT = "#{NAME}/#{VERSION} ( #{CONTACT_EMAIL} )"
- end
-end
diff --git a/lib/asciidoctor/ietf-rfc-link-inline-macro/extension.rb b/lib/asciidoctor/ietf-rfc-link-inline-macro/extension.rb
deleted file mode 100644
index e846e4d..0000000
--- a/lib/asciidoctor/ietf-rfc-link-inline-macro/extension.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-class IETFRFCLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :rfc
- name_positional_attributes 'caption'
-
- def process(parent, target, attrs)
- doc = parent.document
- url = %(https://datatracker.ietf.org/doc/html/#{target})
- attrs['caption'] ||= "RFC#{target}"
- doc.register :links, url
- create_anchor parent, attrs['caption'], type: :link, target: url
- end
-end
diff --git a/lib/asciidoctor/man-inline-macro/extension.rb b/lib/asciidoctor/man-inline-macro/extension.rb
deleted file mode 100644
index 5126f19..0000000
--- a/lib/asciidoctor/man-inline-macro/extension.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-class ManInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :man
- name_positional_attributes 'volnum'
- default_attributes 'service' => 'debian', 'subpath' => ''
-
- def process(parent, target, attrs)
- doc = parent.document
- manname = target
-
- text = %(#{manname}(#{attrs['volnum']}))
-
- if doc.basebackend? 'html'
- domain = case attrs['service']
- when 'debian'
- 'https://manpages.debian.org'
- when 'ubuntu'
- 'https://manpages.ubuntu.org'
- when 'arch'
- 'https://man.archlinux.org/man'
- when 'opensuse'
- 'https://manpages.opensuse.org'
- when 'voidlinux'
- 'https://man.voidlinux.org'
- when 'openbsd'
- 'https://man.openbsd.org'
- when 'none'
- nil
- else
- raise "no available manpage service #{attrs['service']}"
- end
-
- if !domain.nil?
- target = %(#{domain}/#{attrs['subpath'].delete_prefix '/'}#{manname}.#{attrs['volnum']})
- doc.register :links, target
- node = create_anchor parent, text, type: :link, target: target
- else
- node = create_inline parent, :quoted, text
- end
- elsif doc.backend == 'manpage'
- node = create_inline parent, :quoted, text, type: :strong
- else
- node = create_inline parent, :quoted, text
- end
-
- node
- end
-end
diff --git a/lib/asciidoctor/musicbrainz-link-inline-macro/extension.rb b/lib/asciidoctor/musicbrainz-link-inline-macro/extension.rb
deleted file mode 100644
index 55d52c8..0000000
--- a/lib/asciidoctor/musicbrainz-link-inline-macro/extension.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require 'json'
-require 'open-uri'
-require 'uri'
-
-class MusicBrainzLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :musicbrainz
- name_positional_attributes 'caption', 'type'
- default_attributes 'type' => 'release'
-
- def process(parent, target, attrs)
- doc = parent.document
- root_endpoint = 'https://musicbrainz.org/ws/2'
-
- begin
- headers = {
- 'Accept' => 'application/json',
- 'User-Agent' => ::Asciidoctor::FoodogsquaredCustomExtensions::USER_AGENT
- }
-
- uri = %(#{root_endpoint}/#{attrs['type']}/#{target})
-
- metadata = OpenURI.open_uri(uri, headers) { |f| JSON.parse(f.read) }
- attrs['caption'] ||= case attrs['type']
- when 'artist', 'area', 'events', 'genre', 'instrument', 'label', 'place', 'series'
- metadata['name']
- when 'recording', 'release-group', 'release', 'cdstub', 'work'
- metadata['title']
- when 'url'
- metadata['resource']
- end
-
- target = %(https://musicbrainz.org/#{attrs['type']}/#{target})
- doc.register :links, target
- create_anchor parent, attrs['caption'], type: :link, target: target
- rescue
- warning = %(error while getting Musicbrainz database object '#{target}: #{e}')
- warn_or_raise doc, warning
- reader.push_include warning, target, target, 1, attrs
- end
- end
-end
diff --git a/lib/asciidoctor/package-indices-link-macro/extension.rb b/lib/asciidoctor/package-indices-link-macro/extension.rb
deleted file mode 100644
index 62ebd1f..0000000
--- a/lib/asciidoctor/package-indices-link-macro/extension.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-# I'm fairly sure this could be programmed since Ruby has nice metaprogramming
-# capabilities. Though, we'll be keeping it manually defining classes for now
-# for initial versions since there could be additional features for each macro.
-
-class CtanLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :ctan
- name_positional_attributes 'caption'
-
- def process(parent, target, attrs)
- doc = parent.document
- text = attrs['caption'] || target
- url = %(https://ctan.org/pkg/#{target})
-
- doc.register :links, url
-
- create_anchor parent, text, type: :link, target: url
- end
-end
-
-class PypiLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :pypi
- name_positional_attributes 'caption'
-
- def process(parent, target, attrs)
- doc = parent.document
- text = attrs['caption'] || target
- url = %(https://pypi.org/project/#{target})
-
- doc.register :links, url
-
- create_anchor parent, text, type: :link, target: url
- end
-end
-
-class CratesIOLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :cratesio
- name_positional_attributes 'caption'
-
- def process(parent, target, attrs)
- doc = parent.document
- text = attrs['caption'] || target
- url = %(https://crates.io/crates/#{target})
-
- doc.register :links, url
-
- create_anchor parent, text, type: :link, target: url
- end
-end
diff --git a/lib/asciidoctor/repology-link-inline-macro/extension.rb b/lib/asciidoctor/repology-link-inline-macro/extension.rb
deleted file mode 100644
index 41d4694..0000000
--- a/lib/asciidoctor/repology-link-inline-macro/extension.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-class RepologyLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :repology
- name_positional_attributes 'caption'
-
- def process(parent, target, attrs)
- doc = parent.document
- text = attrs['caption'] || target
- url = %(https://repology.org/project/#{target})
-
- doc.register :links, url
-
- create_anchor parent, text, type: :link, target: url
- end
-end
diff --git a/lib/asciidoctor/swhid-include-processor/extension.rb b/lib/asciidoctor/swhid-include-processor/extension.rb
deleted file mode 100644
index b56d8f2..0000000
--- a/lib/asciidoctor/swhid-include-processor/extension.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-require 'json'
-require 'open-uri'
-require 'uri'
-
-class SWHIDIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
- def handles?(target)
- target.start_with? 'swh:'
- end
-
- def process(doc, reader, target, attributes)
- swhid = target
- swhid_core_identifier = swhid.split(';').at(0)
- swhid_object_type = (swhid_core_identifier.split ':').at 2
-
- unless (doc.safe <= Asciidoctor::SafeMode::SERVER) && (doc.attr? 'allow-uri-read')
- raise %('swh:' include cannot be used in safe mode level > SERVER and without attribute 'allow-uri-read')
- end
-
- # We're already going to throw out anything that is not content object type
- # just to make the later pipelines easier to construct.
- if swhid_object_type != 'cnt'
- warn %(SWHID '#{swhid_core_identifier}' is not of 'cnt' type; ignoring)
- return reader
- end
-
- version = '1'
-
- content = begin
- uri = URI.parse %(https://archive.softwareheritage.org/api/#{version}/resolve/#{target}/)
-
- headers = {
- 'Accept' => 'application/json'
- }
-
- headers['Authorization'] = "Bearer #{ENV['SWH_API_BEARER_TOKEN']}" if ENV['SWH_API_BEARER_TOKEN']
-
- metadata = OpenURI.open_uri(uri, headers) { |f| JSON.parse(f.read) }
- object_hash = metadata['object_id']
-
- uri = URI.parse %(https://archive.softwareheritage.org/api/#{version}/content/sha1_git:#{object_hash}/raw/)
- OpenURI.open_uri(uri, headers, &:read)
- rescue OpenURI::HTTPError => e
- warning = %(error while getting '#{swhid_core_identifier}': #{e})
- warn warning
- warning
- end
-
- reader.push_include content, target, target, 1, attributes
- reader
- end
-end
diff --git a/lib/asciidoctor/swhid-inline-macro/extension.rb b/lib/asciidoctor/swhid-inline-macro/extension.rb
deleted file mode 100644
index aa0f819..0000000
--- a/lib/asciidoctor/swhid-inline-macro/extension.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-class SWHInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :swh
- name_positional_attributes 'caption'
-
- def process(parent, target, attrs)
- doc = parent.document
-
- # We're only considering `swh:` starting with the scheme version. Also, it
- # looks nice aesthetically.
- swhid = target.start_with?('swh:') ? target : %(swh:#{target})
- default_caption = if attrs.key? 'full-option'
- swhid
- else
- swhid.split(';').at(0)
- end
- text = attrs['caption'] || default_caption
- target = %(https://archive.softwareheritage.org/#{swhid})
-
- doc.register :links, target
- create_anchor parent, text, type: :link, target: target
- end
-end
diff --git a/lib/asciidoctor/wikipedia-inline-macro/extension.rb b/lib/asciidoctor/wikipedia-inline-macro/extension.rb
deleted file mode 100644
index 5c7a6c7..0000000
--- a/lib/asciidoctor/wikipedia-inline-macro/extension.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-require 'uri'
-
-class WikipediaInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
- use_dsl
-
- named :wikipedia
- name_positional_attributes 'caption'
- default_attributes 'lang' => 'en'
-
- def process(parent, target, attrs)
- caption = attrs['caption'] || target
- parser = URI::Parser.new
- page = parser.escape target
- link = %(https://#{attrs['lang']}.wikipedia.org/wiki/#{page})
- node = create_anchor parent, caption, type: :link, target: link
-
- create_inline parent, :quoted, node.convert
- end
-end
diff --git a/spec/fdroid_link_inline_macro_spec.rb b/spec/fdroid_link_inline_macro_spec.rb
index fb94a3c..a7e5426 100644
--- a/spec/fdroid_link_inline_macro_spec.rb
+++ b/spec/fdroid_link_inline_macro_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe FDroidLinkInlineMacro do
+describe FDroidInlineMacro do
it 'should create a FDroid link' do
input = 'fdroid:org.moire.ultrasonic[]'
diff --git a/spec/flathub_link_inline_macro_spec.rb b/spec/flathub_link_inline_macro_spec.rb
index 3425f9e..13d1d16 100644
--- a/spec/flathub_link_inline_macro_spec.rb
+++ b/spec/flathub_link_inline_macro_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe FlathubLinkInlineMacro do
+describe FlathubInlineMacro do
it 'should create a Flathub link to Icon Library app' do
input = 'flathub:org.gnome.design.IconLibrary[]'
diff --git a/spec/github_link_inline_macro_spec.rb b/spec/github_link_inline_macro_spec.rb
index b7f0a13..b320bbb 100644
--- a/spec/github_link_inline_macro_spec.rb
+++ b/spec/github_link_inline_macro_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe GitHubLinkInlineMacro do
+describe GitHubInlineMacro do
it 'should create a GitHub link with the caption being the target' do
input = <<~INPUT
github:foo-dogsquared/foobarbazxyz[]
diff --git a/spec/github_raw_content_include_processor_spec.rb b/spec/github_raw_content_include_processor_spec.rb
index 9599151..632d9f3 100644
--- a/spec/github_raw_content_include_processor_spec.rb
+++ b/spec/github_raw_content_include_processor_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe GitHubRawIncludeProcessor do
+describe GitHubIncludeProcessor do
it 'should include the raw content of a GitHub file successfully' do
input = <<~INPUT
[literal]
diff --git a/spec/gitlab_link_inline_macro_spec.rb b/spec/gitlab_link_inline_macro_spec.rb
index b2893ef..b643ce7 100644
--- a/spec/gitlab_link_inline_macro_spec.rb
+++ b/spec/gitlab_link_inline_macro_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe GitLabLinkInlineMacro do
+describe GitLabInlineMacro do
it 'should link to the GitLab page for GitLab project' do
input = 'gitlab:gitlab-org/gitlab[]'
diff --git a/spec/gitlab_raw_content_include_processor_spec.rb b/spec/gitlab_raw_content_include_processor_spec.rb
index 6603395..7cb56c8 100644
--- a/spec/gitlab_raw_content_include_processor_spec.rb
+++ b/spec/gitlab_raw_content_include_processor_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe GitLabRawIncludeProcessor, if: ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN'] do
+describe GitLabIncludeProcessor, if: ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN'] do
it 'should include the GitLab CI configuration from freedesktop-sdk/freedesktop-sdk from the default instance' do
commit = 'bcb3e0de957519e87a4c7b8c0e40af9876e531e7'
input = <<~INPUT
diff --git a/spec/musicbrainz_link_inline_macro_spec.rb b/spec/musicbrainz_link_inline_macro_spec.rb
index 5938a98..a80e236 100644
--- a/spec/musicbrainz_link_inline_macro_spec.rb
+++ b/spec/musicbrainz_link_inline_macro_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe MusicBrainzLinkInlineMacro do
+describe MusicBrainzInlineMacro do
it 'should create a MusicBrainz release object with the right captions' do
input = 'musicbrainz:9adcff14-7dba-4ccf-a6a6-298bcde3dd46[]'
diff --git a/spec/repology_link_inline_macro_spec.rb b/spec/repology_link_inline_macro_spec.rb
index 1ada452..14b0c11 100644
--- a/spec/repology_link_inline_macro_spec.rb
+++ b/spec/repology_link_inline_macro_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe RepologyLinkInlineMacro do
+describe RepologyInlineMacro do
it 'should link to the Repology page for beets' do
input = 'repology:beets[]'
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index d6453b8..608e6ce 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,8 +1,9 @@
# frozen_string_literal: true
require 'asciidoctor'
-require 'asciidoctor/foodogsquared-extensions'
+require 'asciidoctor-foodogsquared-extensions'
+include Asciidoctor::Foodogsquared::Extensions
RSpec.configure do
def fixtures_dir
File.join __dir__, 'fixtures'