Skip to content

Commit 5195c6c

Browse files
committed
Warn about vendored versionless packages
1 parent 7fefb0d commit 5195c6c

File tree

3 files changed

+53
-22
lines changed

3 files changed

+53
-22
lines changed

lib/importmap/npm.rb

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
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
@@ -48,16 +51,20 @@ def packages_with_versions
4851
# We cannot use the name after "pin" because some dependencies are loaded from inside packages
4952
# Eg. pin "buffer", to: "https://ga.jspm.io/npm:@jspm/[email protected]/nodelibs/browser/buffer.js"
5053

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]*)).*$/)
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
60+
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,19 @@ 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+
importmap
143+
.lines
144+
.filter_map do |line|
145+
next line.match(/#{PIN_REGEX}to: ["']([^["']]*)["'].*/).captures if line.include?("to:")
146+
match = line.match(PIN_REGEX)
147+
[match.captures.first, "#{match.captures.first}.js"] if match
148+
end
149+
.filter_map do |package, filename|
150+
next if packages_with_versions.map(&:first).include?(package)
151+
path = File.join(@vendor_path, filename)
152+
[package, path] if File.exist?(path)
153+
end
154+
end
133155
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: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,22 @@ 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
51-
52-
@npm.stub(:get_json, response) do
53-
outdated_packages = @npm.outdated_packages
54-
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
61-
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
49+
test "warns (and ignores) vendored packages without version" do
50+
Dir.mktmpdir do |vendor_path|
51+
with_vendored_package(vendor_path, "foo.js") do |foo_path|
52+
with_vendored_package(vendor_path, "baz.js") do |baz_path|
53+
npm = Importmap::Npm.new(file_fixture("import_map_without_cdn_and_versions.rb"), vendor_path: vendor_path)
54+
55+
outdated_packages = []
56+
stdout, _stderr = capture_io { outdated_packages = npm.outdated_packages }
57+
58+
expected = [
59+
"Ignoring foo (#{foo_path}) since no version is specified in the importmap\n",
60+
"Ignoring @bar/baz (#{baz_path}) since no version is specified in the importmap\n"
61+
]
62+
assert_equal(expected, stdout.lines)
63+
assert_equal(0, outdated_packages.size)
64+
end
6665
end
6766
end
6867
end
@@ -142,4 +141,12 @@ def code() "200" end
142141
assert_equal('version not found', outdated_packages[0].latest_version)
143142
end
144143
end
144+
145+
def with_vendored_package(dir, name)
146+
path = File.join(dir, name)
147+
File.write(path, "console.log(123)")
148+
yield path
149+
ensure
150+
File.delete(path)
151+
end
145152
end

0 commit comments

Comments
 (0)