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'