Refactor DependencyLinker::BaseLinker
This commit is contained in:
parent
52527be438
commit
aa24feed6f
5 changed files with 77 additions and 68 deletions
|
@ -1,6 +1,8 @@
|
|||
module Gitlab
|
||||
module DependencyLinker
|
||||
class BaseLinker
|
||||
URL_REGEX = %r{https?://[^'"]+}.freeze
|
||||
|
||||
class_attribute :file_type
|
||||
|
||||
def self.support?(blob_name)
|
||||
|
@ -26,59 +28,17 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def package_url(name)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def link_dependencies
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def package_link(name, url = package_url(name))
|
||||
return name unless url
|
||||
|
||||
%{<a href="#{ERB::Util.html_escape_once(url)}" rel="noopener noreferrer" target="_blank">#{ERB::Util.html_escape_once(name)}</a>}
|
||||
def license_url(name)
|
||||
Licensee::License.find(name)&.url
|
||||
end
|
||||
|
||||
# Links package names in a method call or assignment string argument.
|
||||
#
|
||||
# Example:
|
||||
# link_method_call("gem")
|
||||
# # Will link `package` in `gem "package"`, `gem("package")` and `gem = "package"`
|
||||
#
|
||||
# link_method_call("gem", "specific_package")
|
||||
# # Will link `specific_package` in `gem "specific_package"`
|
||||
#
|
||||
# link_method_call("github", /[^\/]+\/[^\/]+/)
|
||||
# # Will link `user/repo` in `github "user/repo"`, but not `github "package"`
|
||||
#
|
||||
# link_method_call(%w[add_dependency add_development_dependency])
|
||||
# # Will link `spec.add_dependency "package"` and `spec.add_development_dependency "package"`
|
||||
#
|
||||
# link_method_call("name")
|
||||
# # Will link `package` in `self.name = "package"`
|
||||
def link_method_call(method_names, value = nil, &url_proc)
|
||||
value =
|
||||
case value
|
||||
when String
|
||||
Regexp.escape(value)
|
||||
when nil
|
||||
/[^'"]+/
|
||||
else
|
||||
value
|
||||
end
|
||||
|
||||
method_names = Array(method_names).map { |name| Regexp.escape(name) }
|
||||
|
||||
regex = %r{
|
||||
#{Regexp.union(method_names)} # Method name
|
||||
\s* # Whitespace
|
||||
[(=]? # Opening brace or equals sign
|
||||
\s* # Whitespace
|
||||
['"](?<name>#{value})['"] # Package name in quotes
|
||||
}x
|
||||
|
||||
link_regex(regex, &url_proc)
|
||||
def link_tag(name, url)
|
||||
%{<a href="#{ERB::Util.html_escape_once(url)}" rel="nofollow noreferrer noopener" target="_blank">#{ERB::Util.html_escape_once(name)}</a>}
|
||||
end
|
||||
|
||||
# Links package names based on regex.
|
||||
|
@ -86,13 +46,13 @@ module Gitlab
|
|||
# Example:
|
||||
# link_regex(/(github:|:github =>)\s*['"](?<name>[^'"]+)['"]/)
|
||||
# # Will link `user/repo` in `github: "user/repo"` or `:github => "user/repo"`
|
||||
def link_regex(regex)
|
||||
def link_regex(regex, &url_proc)
|
||||
highlighted_lines.map!.with_index do |rich_line, i|
|
||||
marker = StringRegexMarker.new(plain_lines[i], rich_line.html_safe)
|
||||
|
||||
marker.mark(regex, group: :name) do |text, left:, right:|
|
||||
url = block_given? ? yield(text) : package_url(text)
|
||||
package_link(text, url)
|
||||
url = yield(text)
|
||||
url ? link_tag(text, url) : text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
module Gitlab
|
||||
module DependencyLinker
|
||||
class GemfileLinker < BaseLinker
|
||||
class GemfileLinker < MethodLinker
|
||||
self.file_type = :gemfile
|
||||
|
||||
private
|
||||
|
||||
def link_dependencies
|
||||
# Link `gem "package_name"` to https://rubygems.org/gems/package_name
|
||||
link_method_call("gem")
|
||||
|
||||
# Link `github: "user/repo"` to https://github.com/user/repo
|
||||
link_regex(/(github:|:github\s*=>)\s*['"](?<name>[^'"]+)['"]/) do |name|
|
||||
"https://github.com/#{name}"
|
||||
end
|
||||
|
||||
# Link `git: "https://gitlab.example.com/user/repo"` to https://gitlab.example.com/user/repo
|
||||
link_regex(%r{(git:|:git\s*=>)\s*['"](?<name>https?://[^'"]+)['"]}) { |url| url }
|
||||
|
||||
# Link `source "https://rubygems.org"` to https://rubygems.org
|
||||
link_method_call("source", %r{https?://[^'"]+}) { |url| url }
|
||||
link_urls
|
||||
link_packages
|
||||
end
|
||||
|
||||
def package_url(name)
|
||||
"https://rubygems.org/gems/#{name}"
|
||||
def link_urls
|
||||
# Link `github: "user/repo"` to https://github.com/user/repo
|
||||
link_regex(/(github:|:github\s*=>)\s*['"](?<name>[^'"]+)['"]/, &method(:github_url))
|
||||
|
||||
# Link `git: "https://gitlab.example.com/user/repo"` to https://gitlab.example.com/user/repo
|
||||
link_regex(%r{(git:|:git\s*=>)\s*['"](?<name>#{URL_REGEX})['"]}, &:itself)
|
||||
|
||||
# Link `source "https://rubygems.org"` to https://rubygems.org
|
||||
link_method_call('source', URL_REGEX, &:itself)
|
||||
end
|
||||
|
||||
def link_packages
|
||||
# Link `gem "package_name"` to https://rubygems.org/gems/package_name
|
||||
link_method_call('gem') do |name|
|
||||
"https://rubygems.org/gems/#{name}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
48
lib/gitlab/dependency_linker/method_linker.rb
Normal file
48
lib/gitlab/dependency_linker/method_linker.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
module Gitlab
|
||||
module DependencyLinker
|
||||
class MethodLinker < BaseLinker
|
||||
private
|
||||
|
||||
# Links package names in a method call or assignment string argument.
|
||||
#
|
||||
# Example:
|
||||
# link_method_call('gem')
|
||||
# # Will link `package` in `gem "package"`, `gem("package")` and `gem = "package"`
|
||||
#
|
||||
# link_method_call('gem', 'specific_package')
|
||||
# # Will link `specific_package` in `gem "specific_package"`
|
||||
#
|
||||
# link_method_call('github', /[^\/"]+\/[^\/"]+/)
|
||||
# # Will link `user/repo` in `github "user/repo"`, but not `github "package"`
|
||||
#
|
||||
# link_method_call(%w[add_dependency add_development_dependency])
|
||||
# # Will link `spec.add_dependency "package"` and `spec.add_development_dependency "package"`
|
||||
#
|
||||
# link_method_call('name')
|
||||
# # Will link `package` in `self.name = "package"`
|
||||
def link_method_call(method_names, value = nil, &url_proc)
|
||||
method_names = Array(method_names).map { |name| Regexp.escape(name) }
|
||||
|
||||
value =
|
||||
case value
|
||||
when String
|
||||
Regexp.escape(value)
|
||||
when nil
|
||||
/[^'"]+/
|
||||
else
|
||||
value
|
||||
end
|
||||
|
||||
regex = %r{
|
||||
#{Regexp.union(method_names)} # Method name
|
||||
\s* # Whitespace
|
||||
[(=]? # Opening brace or equals sign
|
||||
\s* # Whitespace
|
||||
['"](?<name>#{value})['"] # Package name in quotes
|
||||
}x
|
||||
|
||||
link_regex(regex, &url_proc)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -33,7 +33,7 @@ describe Gitlab::DependencyLinker::GemfileLinker, lib: true do
|
|||
subject { Gitlab::Highlight.highlight(file_name, file_content) }
|
||||
|
||||
def link(name, url)
|
||||
%{<a href="#{url}" rel="noopener noreferrer" target="_blank">#{name}</a>}
|
||||
%{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
|
||||
end
|
||||
|
||||
it 'links sources' do
|
||||
|
|
|
@ -59,8 +59,6 @@ describe Gitlab::Highlight, lib: true do
|
|||
end
|
||||
|
||||
describe '#highlight' do
|
||||
subject { described_class.highlight(file_name, file_content, nowrap: false) }
|
||||
|
||||
it 'links dependencies via DependencyLinker' do
|
||||
expect(Gitlab::DependencyLinker).to receive(:link).
|
||||
with('file.name', 'Contents', anything).and_call_original
|
||||
|
|
Loading…
Reference in a new issue