Skip to content

Commit 9cd897f

Browse files
authored
Merge pull request #305 from 3v0k4/versionless
Warn about vendored versionless packages
2 parents 7fefb0d + 2d711e1 commit 9cd897f

File tree

3 files changed

+61
-26
lines changed

3 files changed

+61
-26
lines changed

lib/importmap/npm.rb

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@
33
require "json"
44

55
class Importmap::Npm
6+
PIN_REGEX = /^pin ["']([^["']]*)["'].*/
7+
68
Error = Class.new(StandardError)
79
HTTPError = Class.new(Error)
810

911
singleton_class.attr_accessor :base_uri
1012
self.base_uri = URI("https://registry.npmjs.org")
1113

12-
def initialize(importmap_path = "config/importmap.rb")
14+
def initialize(importmap_path = "config/importmap.rb", vendor_path: "vendor/javascript")
1315
@importmap_path = Pathname.new(importmap_path)
16+
@vendor_path = Pathname.new(vendor_path)
1417
end
1518

1619
def outdated_packages
1720
packages_with_versions.each.with_object([]) do |(package, current_version), outdated_packages|
18-
outdated_package = OutdatedPackage.new(name: package,
19-
current_version: current_version)
21+
outdated_package = OutdatedPackage.new(name: package, current_version: current_version)
2022

2123
if !(response = get_package(package))
2224
outdated_package.error = 'Response error'
@@ -36,28 +38,33 @@ def outdated_packages
3638
def vulnerable_packages
3739
get_audit.flat_map do |package, vulnerabilities|
3840
vulnerabilities.map do |vulnerability|
39-
VulnerablePackage.new(name: package,
40-
severity: vulnerability['severity'],
41-
vulnerable_versions: vulnerability['vulnerable_versions'],
42-
vulnerability: vulnerability['title'])
41+
VulnerablePackage.new(
42+
name: package,
43+
severity: vulnerability['severity'],
44+
vulnerable_versions: vulnerability['vulnerable_versions'],
45+
vulnerability: vulnerability['title']
46+
)
4347
end
4448
end.sort_by { |p| [p.name, p.severity] }
4549
end
4650

4751
def packages_with_versions
4852
# We cannot use the name after "pin" because some dependencies are loaded from inside packages
4953
# Eg. pin "buffer", to: "https://ga.jspm.io/npm:@jspm/[email protected]/nodelibs/browser/buffer.js"
54+
with_versions = importmap.scan(/^pin .*(?<=npm:|npm\/|skypack\.dev\/|unpkg\.com\/)(.*)(?=@\d+\.\d+\.\d+)@(\d+\.\d+\.\d+(?:[^\/\s["']]*)).*$/) |
55+
importmap.scan(/#{PIN_REGEX} #.*@(\d+\.\d+\.\d+(?:[^\s]*)).*$/)
56+
57+
vendored_packages_without_version(with_versions).each do |package, path|
58+
$stdout.puts "Ignoring #{package} (#{path}) since no version is specified in the importmap"
59+
end
5060

51-
importmap.scan(/^pin .*(?<=npm:|npm\/|skypack\.dev\/|unpkg\.com\/)(.*)(?=@\d+\.\d+\.\d+)@(\d+\.\d+\.\d+(?:[^\/\s["']]*)).*$/) |
52-
importmap.scan(/^pin ["']([^["']]*)["'].* #.*@(\d+\.\d+\.\d+(?:[^\s]*)).*$/)
61+
with_versions
5362
end
5463

5564
private
5665
OutdatedPackage = Struct.new(:name, :current_version, :latest_version, :error, keyword_init: true)
5766
VulnerablePackage = Struct.new(:name, :severity, :vulnerable_versions, :vulnerability, keyword_init: true)
5867

59-
60-
6168
def importmap
6269
@importmap ||= File.read(@importmap_path)
6370
end
@@ -130,4 +137,27 @@ def post_json(uri, body)
130137
rescue => error
131138
raise HTTPError, "Unexpected transport error (#{error.class}: #{error.message})"
132139
end
140+
141+
def vendored_packages_without_version(packages_with_versions)
142+
versioned_packages = packages_with_versions.map(&:first).to_set
143+
144+
importmap
145+
.lines
146+
.filter_map { |line| find_unversioned_vendored_package(line, versioned_packages) }
147+
end
148+
149+
def find_unversioned_vendored_package(line, versioned_packages)
150+
regexp = line.include?("to:")? /#{PIN_REGEX}to: ["']([^["']]*)["'].*/ : PIN_REGEX
151+
match = line.match(regexp)
152+
153+
return unless match
154+
155+
package, filename = match.captures
156+
filename ||= "#{package}.js"
157+
158+
return if versioned_packages.include?(package)
159+
160+
path = File.join(@vendor_path, filename)
161+
[package, path] if File.exist?(path)
162+
end
133163
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pin "foo", preload: true
2+
pin "@bar/baz", to: "baz.js", preload: true

test/npm_test.rb

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,21 @@ class Importmap::NpmTest < ActiveSupport::TestCase
4646
end
4747
end
4848

49-
test "missing outdated packages with mock" do
50-
response = { "error" => "Not found" }.to_json
49+
test "warns (and ignores) vendored packages without version" do
50+
Dir.mktmpdir do |vendor_path|
51+
foo_path = create_vendored_file(vendor_path, "foo.js")
52+
baz_path = create_vendored_file(vendor_path, "baz.js")
5153

52-
@npm.stub(:get_json, response) do
53-
outdated_packages = @npm.outdated_packages
54+
npm = Importmap::Npm.new(file_fixture("import_map_without_cdn_and_versions.rb"), vendor_path: vendor_path)
5455

55-
assert_equal(1, outdated_packages.size)
56-
assert_equal('md5', outdated_packages[0].name)
57-
assert_equal('2.2.0', outdated_packages[0].current_version)
58-
assert_equal('Not found', outdated_packages[0].error)
59-
end
60-
end
56+
outdated_packages = []
57+
stdout, _stderr = capture_io { outdated_packages = npm.outdated_packages }
6158

62-
test "failed outdated packages request with exception" do
63-
Net::HTTP.stub(:start, proc { raise "Unexpected Error" }) do
64-
assert_raises(Importmap::Npm::HTTPError) do
65-
@npm.outdated_packages
66-
end
59+
assert_equal(<<~OUTPUT, stdout)
60+
Ignoring foo (#{foo_path}) since no version is specified in the importmap
61+
Ignoring @bar/baz (#{baz_path}) since no version is specified in the importmap
62+
OUTPUT
63+
assert_equal(0, outdated_packages.size)
6764
end
6865
end
6966

@@ -142,4 +139,10 @@ def code() "200" end
142139
assert_equal('version not found', outdated_packages[0].latest_version)
143140
end
144141
end
142+
143+
def create_vendored_file(dir, name)
144+
path = File.join(dir, name)
145+
File.write(path, "console.log(123)")
146+
path
147+
end
145148
end

0 commit comments

Comments
 (0)