|
3 | 3 | require "json" |
4 | 4 |
|
5 | 5 | class Importmap::Npm |
| 6 | + PIN_REGEX = /^pin ["']([^["']]*)["'].*/ |
| 7 | + |
6 | 8 | Error = Class.new(StandardError) |
7 | 9 | HTTPError = Class.new(Error) |
8 | 10 |
|
9 | 11 | singleton_class.attr_accessor :base_uri |
10 | 12 | self.base_uri = URI("https://registry.npmjs.org") |
11 | 13 |
|
12 | | - def initialize(importmap_path = "config/importmap.rb") |
| 14 | + def initialize(importmap_path = "config/importmap.rb", vendor_path: "vendor/javascript") |
13 | 15 | @importmap_path = Pathname.new(importmap_path) |
| 16 | + @vendor_path = Pathname.new(vendor_path) |
14 | 17 | end |
15 | 18 |
|
16 | 19 | def outdated_packages |
@@ -48,16 +51,20 @@ def packages_with_versions |
48 | 51 | # We cannot use the name after "pin" because some dependencies are loaded from inside packages |
49 | 52 | # Eg. pin "buffer", to: "https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.19/nodelibs/browser/buffer.js" |
50 | 53 |
|
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 |
53 | 62 | end |
54 | 63 |
|
55 | 64 | private |
56 | 65 | OutdatedPackage = Struct.new(:name, :current_version, :latest_version, :error, keyword_init: true) |
57 | 66 | VulnerablePackage = Struct.new(:name, :severity, :vulnerable_versions, :vulnerability, keyword_init: true) |
58 | 67 |
|
59 | | - |
60 | | - |
61 | 68 | def importmap |
62 | 69 | @importmap ||= File.read(@importmap_path) |
63 | 70 | end |
@@ -130,4 +137,19 @@ def post_json(uri, body) |
130 | 137 | rescue => error |
131 | 138 | raise HTTPError, "Unexpected transport error (#{error.class}: #{error.message})" |
132 | 139 | 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 |
133 | 155 | end |
0 commit comments