diff options
author | Douwe Maan <douwe@selenight.nl> | 2017-05-16 15:27:50 -0500 |
---|---|---|
committer | Douwe Maan <douwe@selenight.nl> | 2017-05-23 15:35:17 -0500 |
commit | 83747783e25b2d8b60efa2cb1aa9d6bd823fcdfe (patch) | |
tree | f9a41ffe3708b3ffda738b964b8932b3a213261e /lib | |
parent | 02ad8c0c68b575ca4957e0a478714ef2144a9b8a (diff) | |
download | gitlab-ce-83747783e25b2d8b60efa2cb1aa9d6bd823fcdfe.tar.gz |
Autolink package names in package.json
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gitlab/dependency_linker.rb | 1 | ||||
-rw-r--r-- | lib/gitlab/dependency_linker/base_linker.rb | 4 | ||||
-rw-r--r-- | lib/gitlab/dependency_linker/json_linker.rb | 63 | ||||
-rw-r--r-- | lib/gitlab/dependency_linker/package_json_linker.rb | 44 |
4 files changed, 112 insertions, 0 deletions
diff --git a/lib/gitlab/dependency_linker.rb b/lib/gitlab/dependency_linker.rb index 14fc506fbb7..88f4ebedb9f 100644 --- a/lib/gitlab/dependency_linker.rb +++ b/lib/gitlab/dependency_linker.rb @@ -3,6 +3,7 @@ module Gitlab LINKERS = [ GemfileLinker, GemspecLinker, + PackageJsonLinker, ].freeze def self.linker(blob_name) diff --git a/lib/gitlab/dependency_linker/base_linker.rb b/lib/gitlab/dependency_linker/base_linker.rb index 019e670081e..15fa9f40116 100644 --- a/lib/gitlab/dependency_linker/base_linker.rb +++ b/lib/gitlab/dependency_linker/base_linker.rb @@ -2,6 +2,7 @@ module Gitlab module DependencyLinker class BaseLinker URL_REGEX = %r{https?://[^'"]+}.freeze + REPO_REGEX = %r{[^/'"]+/[^/'"]+}.freeze class_attribute :file_type @@ -36,6 +37,9 @@ module Gitlab Licensee::License.find(name)&.url end + def github_url(name) + "https://github.com/#{name}" + end 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>} diff --git a/lib/gitlab/dependency_linker/json_linker.rb b/lib/gitlab/dependency_linker/json_linker.rb new file mode 100644 index 00000000000..021347b6429 --- /dev/null +++ b/lib/gitlab/dependency_linker/json_linker.rb @@ -0,0 +1,63 @@ +module Gitlab + module DependencyLinker + class JsonLinker < BaseLinker + def link + return highlighted_text unless json + + super + end + + private + + # Links package names in a JSON key or values. + # + # Example: + # link_json('name') + # # Will link `package` in `"name": "package"` + # + # link_json('name', 'specific_package') + # # Will link `specific_package` in `"name": "specific_package"` + # + # link_json('name', /[^\/]+\/[^\/]+/) + # # Will link `user/repo` in `"name": "user/repo"`, but not `"name": "package"` + # + # link_json('specific_package', '1.0.1', link: :key) + # # Will link `specific_package` in `"specific_package": "1.0.1"` + def link_json(key, value = nil, link: :value, &url_proc) + key = + case key + when Array + Regexp.union(key.map { |name| Regexp.escape(name) }) + when String + Regexp.escape(key) + when nil + '[^"]+' + else + key + end + + value = + case value + when String + Regexp.escape(value) + when nil + '[^"]+' + else + value + end + + if link == :value + value = "(?<name>#{value})" + else + key = "(?<name>#{key})" + end + + link_regex(/"#{key}":\s*"#{value}"/, &url_proc) + end + + def json + @json ||= JSON.parse(plain_text) rescue nil + end + end + end +end diff --git a/lib/gitlab/dependency_linker/package_json_linker.rb b/lib/gitlab/dependency_linker/package_json_linker.rb new file mode 100644 index 00000000000..330c95f0880 --- /dev/null +++ b/lib/gitlab/dependency_linker/package_json_linker.rb @@ -0,0 +1,44 @@ +module Gitlab + module DependencyLinker + class PackageJsonLinker < JsonLinker + self.file_type = :package_json + + private + + def link_dependencies + link_json('name', json["name"], &method(:package_url)) + link_json('license', &method(:license_url)) + link_json(%w[homepage url], URL_REGEX, &:itself) + + link_packages + end + + def link_packages + link_packages_at_key("dependencies", &method(:package_url)) + link_packages_at_key("devDependencies", &method(:package_url)) + end + + def link_packages_at_key(key, &url_proc) + dependencies = json[key] + return unless dependencies + + dependencies.each do |name, version| + link_json(name, version, link: :key, &url_proc) + + link_json(name) do |value| + case value + when /\A#{URL_REGEX}\z/ + value + when /\A#{REPO_REGEX}\z/ + github_url(value) + end + end + end + end + + def package_url(name) + "https://npmjs.com/package/#{name}" + end + end + end +end |