bibliothecary 12.0.0 → 12.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +2 -1
- data/.rubocop.yml +10 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +13 -0
- data/Gemfile +16 -1
- data/Rakefile +2 -0
- data/bibliothecary.gemspec +11 -13
- data/bin/bibliothecary +2 -1
- data/bin/console +1 -0
- data/lib/bibliothecary/analyser/analysis.rb +13 -8
- data/lib/bibliothecary/analyser/determinations.rb +2 -0
- data/lib/bibliothecary/analyser/matchers.rb +17 -17
- data/lib/bibliothecary/analyser.rb +11 -8
- data/lib/bibliothecary/cli.rb +3 -1
- data/lib/bibliothecary/configuration.rb +3 -8
- data/lib/bibliothecary/dependency.rb +17 -15
- data/lib/bibliothecary/exceptions.rb +6 -2
- data/lib/bibliothecary/file_info.rb +9 -11
- data/lib/bibliothecary/multi_parsers/bundler_like_manifest.rb +13 -10
- data/lib/bibliothecary/multi_parsers/cyclonedx.rb +10 -8
- data/lib/bibliothecary/multi_parsers/dependencies_csv.rb +11 -4
- data/lib/bibliothecary/multi_parsers/json_runtime.rb +5 -2
- data/lib/bibliothecary/multi_parsers/spdx.rb +24 -19
- data/lib/bibliothecary/parsers/bower.rb +5 -3
- data/lib/bibliothecary/parsers/cargo.rb +10 -4
- data/lib/bibliothecary/parsers/cocoapods.rb +15 -11
- data/lib/bibliothecary/parsers/conda.rb +20 -18
- data/lib/bibliothecary/parsers/cpan.rb +6 -4
- data/lib/bibliothecary/parsers/cran.rb +10 -6
- data/lib/bibliothecary/parsers/dub.rb +4 -2
- data/lib/bibliothecary/parsers/elm.rb +4 -1
- data/lib/bibliothecary/parsers/go.rb +51 -43
- data/lib/bibliothecary/parsers/haxelib.rb +2 -1
- data/lib/bibliothecary/parsers/julia.rb +5 -1
- data/lib/bibliothecary/parsers/maven.rb +93 -77
- data/lib/bibliothecary/parsers/meteor.rb +2 -0
- data/lib/bibliothecary/parsers/npm.rb +89 -75
- data/lib/bibliothecary/parsers/nuget.rb +37 -28
- data/lib/bibliothecary/parsers/packagist.rb +21 -11
- data/lib/bibliothecary/parsers/pub.rb +4 -2
- data/lib/bibliothecary/parsers/pypi.rb +48 -29
- data/lib/bibliothecary/parsers/rubygems.rb +16 -12
- data/lib/bibliothecary/parsers/shard.rb +10 -7
- data/lib/bibliothecary/purl_util.rb +2 -1
- data/lib/bibliothecary/related_files_info.rb +7 -8
- data/lib/bibliothecary/runner/multi_manifest_filter.rb +5 -4
- data/lib/bibliothecary/runner.rb +12 -10
- data/lib/bibliothecary/version.rb +3 -1
- data/lib/bibliothecary.rb +7 -4
- data/lib/sdl_parser.rb +11 -6
- metadata +18 -101
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
|
3
5
|
module Bibliothecary
|
@@ -37,29 +39,29 @@ module Bibliothecary
|
|
37
39
|
add_multi_parser(Bibliothecary::MultiParsers::Spdx)
|
38
40
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
39
41
|
|
40
|
-
def self.parse_package_lock(file_contents, options: {})
|
42
|
+
def self.parse_package_lock(file_contents, options: {})
|
41
43
|
manifest = JSON.parse(file_contents)
|
42
44
|
# https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json#lockfileversion
|
43
45
|
if manifest["lockfileVersion"].to_i <= 1
|
44
46
|
# lockfileVersion 1 uses the "dependencies" object
|
45
|
-
parse_package_lock_v1(manifest)
|
47
|
+
parse_package_lock_v1(manifest, options.fetch(:filename, nil))
|
46
48
|
else
|
47
49
|
# lockfileVersion 2 has backwards-compatability by including both "packages" and the legacy "dependencies" object
|
48
50
|
# lockfileVersion 3 has no backwards-compatibility and only includes the "packages" object
|
49
|
-
parse_package_lock_v2(manifest)
|
51
|
+
parse_package_lock_v2(manifest, options.fetch(:filename, nil))
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
55
|
class << self
|
54
56
|
# "package-lock.json" and "npm-shrinkwrap.json" have same format, so use same parsing logic
|
55
|
-
|
57
|
+
alias parse_shrinkwrap parse_package_lock
|
56
58
|
end
|
57
59
|
|
58
|
-
def self.parse_package_lock_v1(manifest)
|
59
|
-
parse_package_lock_deps_recursively(manifest.fetch("dependencies", []))
|
60
|
+
def self.parse_package_lock_v1(manifest, source = nil)
|
61
|
+
parse_package_lock_deps_recursively(manifest.fetch("dependencies", []), source)
|
60
62
|
end
|
61
63
|
|
62
|
-
def self.parse_package_lock_v2(manifest)
|
64
|
+
def self.parse_package_lock_v2(manifest, source = nil)
|
63
65
|
# "packages" is a flat object where each key is the installed location of the dep, e.g. node_modules/foo/node_modules/bar.
|
64
66
|
manifest
|
65
67
|
.fetch("packages")
|
@@ -73,33 +75,39 @@ module Bibliothecary
|
|
73
75
|
Dependency.new(
|
74
76
|
name: name.split("node_modules/").last,
|
75
77
|
requirement: dep["version"],
|
76
|
-
type: dep.fetch("dev", false) || dep.fetch("devOptional", false)
|
78
|
+
type: dep.fetch("dev", false) || dep.fetch("devOptional", false) ? "development" : "runtime",
|
77
79
|
local: dep.fetch("link", false),
|
80
|
+
source: source
|
78
81
|
)
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
82
|
-
def self.parse_package_lock_deps_recursively(dependencies, depth=1)
|
85
|
+
def self.parse_package_lock_deps_recursively(dependencies, source = nil, depth = 1)
|
83
86
|
dependencies.flat_map do |name, requirement|
|
84
87
|
type = requirement.fetch("dev", false) ? "development" : "runtime"
|
85
88
|
version = requirement.key?("from") ? requirement["from"][/#(?:semver:)?v?(.*)/, 1] : nil
|
86
89
|
version ||= requirement["version"].split("#").last
|
87
90
|
child_dependencies = if depth >= PACKAGE_LOCK_JSON_MAX_DEPTH
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
+
[]
|
92
|
+
else
|
93
|
+
parse_package_lock_deps_recursively(requirement.fetch("dependencies", []), source, depth + 1)
|
91
94
|
end
|
92
95
|
|
93
96
|
[Dependency.new(
|
94
97
|
name: name,
|
95
98
|
requirement: version,
|
96
99
|
type: type,
|
100
|
+
source: source
|
97
101
|
)] + child_dependencies
|
98
102
|
end
|
99
103
|
end
|
100
104
|
|
101
|
-
def self.parse_manifest(file_contents, options: {})
|
105
|
+
def self.parse_manifest(file_contents, options: {})
|
106
|
+
# on ruby 3.2 we suddenly get this JSON error, so detect and return early: "package.json: unexpected token at ''"
|
107
|
+
return [] if file_contents.empty?
|
108
|
+
|
102
109
|
manifest = JSON.parse(file_contents)
|
110
|
+
|
103
111
|
raise "appears to be a lockfile rather than manifest format" if manifest.key?("lockfileVersion")
|
104
112
|
|
105
113
|
dependencies = manifest.fetch("dependencies", [])
|
@@ -109,7 +117,8 @@ module Bibliothecary
|
|
109
117
|
name: name,
|
110
118
|
requirement: requirement,
|
111
119
|
type: "runtime",
|
112
|
-
local: requirement.start_with?("file:")
|
120
|
+
local: requirement.start_with?("file:"),
|
121
|
+
source: options.fetch(:filename, nil)
|
113
122
|
)
|
114
123
|
end
|
115
124
|
|
@@ -120,19 +129,20 @@ module Bibliothecary
|
|
120
129
|
name: name,
|
121
130
|
requirement: requirement,
|
122
131
|
type: "development",
|
123
|
-
local: requirement.start_with?("file:")
|
132
|
+
local: requirement.start_with?("file:"),
|
133
|
+
source: options.fetch(:filename, nil)
|
124
134
|
)
|
125
135
|
end
|
126
136
|
|
127
137
|
dependencies
|
128
138
|
end
|
129
139
|
|
130
|
-
def self.parse_yarn_lock(file_contents, options: {})
|
140
|
+
def self.parse_yarn_lock(file_contents, options: {})
|
131
141
|
dep_hash = if file_contents.match(/__metadata:/)
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
142
|
+
parse_v2_yarn_lock(file_contents, options.fetch(:filename, nil))
|
143
|
+
else
|
144
|
+
parse_v1_yarn_lock(file_contents, options.fetch(:filename, nil))
|
145
|
+
end
|
136
146
|
|
137
147
|
dep_hash.map do |dep|
|
138
148
|
Dependency.new(
|
@@ -140,67 +150,70 @@ module Bibliothecary
|
|
140
150
|
requirement: dep[:version],
|
141
151
|
type: "runtime", # lockfile doesn't tell us more about the type of dep
|
142
152
|
local: dep[:requirements]&.first&.start_with?("file:"),
|
153
|
+
source: options.fetch(:filename, nil)
|
143
154
|
)
|
144
155
|
end
|
145
|
-
|
156
|
+
end
|
146
157
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
158
|
+
# Returns a hash representation of the deps in yarn.lock, eg:
|
159
|
+
# [{
|
160
|
+
# name: "foo",
|
161
|
+
# requirements: [["foo", "^1.0.0"], ["foo", "^1.0.1"]],
|
162
|
+
# version: "1.2.0",
|
163
|
+
# }, ...]
|
164
|
+
def self.parse_v1_yarn_lock(contents, source = nil)
|
165
|
+
contents
|
166
|
+
.gsub(/^#.*/, "")
|
167
|
+
.strip
|
168
|
+
.split("\n\n")
|
169
|
+
.map do |chunk|
|
170
|
+
requirements = chunk
|
171
|
+
.lines
|
172
|
+
.find { |l| !l.start_with?(" ") && l.strip.end_with?(":") } # first line, eg: '"@bar/foo@1.0.0", "@bar/foo@^1.0.1":'
|
173
|
+
.strip
|
174
|
+
.gsub(/"|:$/, "") # don't need quotes or trailing colon
|
175
|
+
.split(",") # split the list of requirements
|
176
|
+
.map { |d| d.strip.split(/(?<!^)@/, 2) } # split each requirement on name/version "@"", not on leading namespace "@"
|
177
|
+
version = chunk.match(/version "?([^"]*)"?/)[1]
|
178
|
+
|
179
|
+
{
|
180
|
+
name: requirements.first.first,
|
181
|
+
requirements: requirements.map { |x| x[1] },
|
182
|
+
version: version,
|
183
|
+
source: source,
|
184
|
+
}
|
185
|
+
end
|
186
|
+
end
|
175
187
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
188
|
+
def self.parse_v2_yarn_lock(contents, source = nil)
|
189
|
+
parsed = YAML.load(contents)
|
190
|
+
parsed = parsed.except("__metadata")
|
191
|
+
parsed
|
192
|
+
.reject do |packages, info|
|
193
|
+
# yarn v4+ creates a lockfile entry: "myproject@workspace" with a "use.local" version
|
194
|
+
# this lockfile entry is a reference to the project to which the lockfile belongs
|
195
|
+
# skip this self-referential package
|
196
|
+
info["version"].to_s.include?("use.local") && packages.include?("workspace")
|
197
|
+
end
|
198
|
+
.map do |packages, info|
|
199
|
+
packages = packages.split(", ")
|
200
|
+
# use first requirement's name, assuming that deps will always resolve from deps of the same name
|
201
|
+
name = packages.first.rpartition("@").first
|
202
|
+
requirements = packages.map { |p| p.rpartition("@").last.gsub(/^.*:/, "") }
|
191
203
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
204
|
+
{
|
205
|
+
name: name,
|
206
|
+
requirements: requirements,
|
207
|
+
version: info["version"].to_s,
|
208
|
+
source: source,
|
209
|
+
}
|
210
|
+
end
|
211
|
+
end
|
199
212
|
|
200
|
-
def self.parse_ls(file_contents, options: {})
|
213
|
+
def self.parse_ls(file_contents, options: {})
|
201
214
|
manifest = JSON.parse(file_contents)
|
202
215
|
|
203
|
-
transform_tree_to_array(manifest.fetch("dependencies", {}))
|
216
|
+
transform_tree_to_array(manifest.fetch("dependencies", {}), options.fetch(:filename, nil))
|
204
217
|
end
|
205
218
|
|
206
219
|
def self.lockfile_preference_order(file_infos)
|
@@ -215,15 +228,16 @@ module Bibliothecary
|
|
215
228
|
end
|
216
229
|
end
|
217
230
|
|
218
|
-
private_class_method def self.transform_tree_to_array(deps_by_name)
|
231
|
+
private_class_method def self.transform_tree_to_array(deps_by_name, source = nil)
|
219
232
|
deps_by_name.map do |name, metadata|
|
220
233
|
[
|
221
234
|
Dependency.new(
|
222
235
|
name: name,
|
223
236
|
requirement: metadata["version"],
|
224
237
|
type: "runtime",
|
238
|
+
source: source
|
225
239
|
),
|
226
|
-
] + transform_tree_to_array(metadata.fetch("dependencies", {}))
|
240
|
+
] + transform_tree_to_array(metadata.fetch("dependencies", {}), source)
|
227
241
|
end.flatten(1)
|
228
242
|
end
|
229
243
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "ox"
|
2
4
|
require "json"
|
3
5
|
|
@@ -48,23 +50,24 @@ module Bibliothecary
|
|
48
50
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
49
51
|
add_multi_parser(Bibliothecary::MultiParsers::Spdx)
|
50
52
|
|
51
|
-
def self.parse_project_lock_json(file_contents, options: {})
|
53
|
+
def self.parse_project_lock_json(file_contents, options: {})
|
52
54
|
manifest = JSON.parse file_contents
|
53
|
-
manifest.fetch("libraries",[]).map do |name, _requirement|
|
55
|
+
manifest.fetch("libraries", []).map do |name, _requirement|
|
54
56
|
dep = name.split("/")
|
55
57
|
Dependency.new(
|
56
58
|
name: dep[0],
|
57
59
|
requirement: dep[1],
|
58
60
|
type: "runtime",
|
61
|
+
source: options.fetch(:filename, nil)
|
59
62
|
)
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
63
|
-
def self.parse_packages_lock_json(file_contents, options: {})
|
66
|
+
def self.parse_packages_lock_json(file_contents, options: {})
|
64
67
|
manifest = JSON.parse file_contents
|
65
68
|
|
66
69
|
frameworks = {}
|
67
|
-
manifest.fetch("dependencies",[]).each do |framework, deps|
|
70
|
+
manifest.fetch("dependencies", []).each do |framework, deps|
|
68
71
|
frameworks[framework] = deps
|
69
72
|
.reject { |_name, details| details["type"] == "Project" } # Projects do not have versions
|
70
73
|
.map do |name, details|
|
@@ -74,44 +77,46 @@ module Bibliothecary
|
|
74
77
|
# so fallback to requested is pure paranoia
|
75
78
|
requirement: details.fetch("resolved", details.fetch("requested", "*")),
|
76
79
|
type: "runtime",
|
80
|
+
source: options.fetch(:filename, nil)
|
77
81
|
)
|
78
82
|
end
|
79
83
|
end
|
80
84
|
|
81
|
-
|
85
|
+
unless frameworks.empty?
|
82
86
|
# we should really return multiple manifests, but bibliothecary doesn't
|
83
87
|
# do that yet so at least pick deterministically.
|
84
88
|
|
85
89
|
# Note, frameworks can be empty, so remove empty ones and then return the last sorted item if any
|
86
90
|
frameworks = frameworks.delete_if { |_k, v| v.empty? }
|
87
|
-
return frameworks[frameworks.keys.
|
91
|
+
return frameworks[frameworks.keys.max] unless frameworks.empty?
|
88
92
|
end
|
89
93
|
[]
|
90
94
|
end
|
91
95
|
|
92
|
-
def self.parse_packages_config(file_contents, options: {})
|
96
|
+
def self.parse_packages_config(file_contents, options: {})
|
93
97
|
manifest = Ox.parse file_contents
|
94
98
|
manifest.packages.locate("package").map do |dependency|
|
95
99
|
Dependency.new(
|
96
100
|
name: dependency.id,
|
97
101
|
requirement: (dependency.version if dependency.respond_to? "version"),
|
98
102
|
type: dependency.respond_to?("developmentDependency") && dependency.developmentDependency == "true" ? "development" : "runtime",
|
103
|
+
source: options.fetch(:filename, nil)
|
99
104
|
)
|
100
105
|
end
|
101
|
-
rescue
|
106
|
+
rescue StandardError
|
102
107
|
[]
|
103
108
|
end
|
104
109
|
|
105
|
-
def self.parse_csproj(file_contents, options: {})
|
110
|
+
def self.parse_csproj(file_contents, options: {})
|
106
111
|
manifest = Ox.parse file_contents
|
107
112
|
|
108
|
-
packages = manifest.locate("ItemGroup/PackageReference").select{ |dep| dep.respond_to? "Include" }.map do |dependency|
|
113
|
+
packages = manifest.locate("ItemGroup/PackageReference").select { |dep| dep.respond_to? "Include" }.map do |dependency|
|
109
114
|
requirement = (dependency.Version if dependency.respond_to? "Version")
|
110
115
|
if requirement.is_a?(Ox::Element)
|
111
|
-
requirement = dependency.nodes.detect{ |n| n.value == "Version" }&.text
|
116
|
+
requirement = dependency.nodes.detect { |n| n.value == "Version" }&.text
|
112
117
|
end
|
113
118
|
|
114
|
-
type = if dependency.nodes.first
|
119
|
+
type = if (dependency.nodes.first&.nodes&.include?("all") && dependency.nodes.first.value.include?("PrivateAssets")) || dependency.attributes[:PrivateAssets] == "All"
|
115
120
|
"development"
|
116
121
|
else
|
117
122
|
"runtime"
|
@@ -121,27 +126,29 @@ module Bibliothecary
|
|
121
126
|
name: dependency.Include,
|
122
127
|
requirement: requirement,
|
123
128
|
type: type,
|
129
|
+
source: options.fetch(:filename, nil)
|
124
130
|
)
|
125
131
|
end
|
126
|
-
packages.uniq
|
127
|
-
rescue
|
132
|
+
packages.uniq(&:name)
|
133
|
+
rescue StandardError
|
128
134
|
[]
|
129
135
|
end
|
130
136
|
|
131
|
-
def self.parse_nuspec(file_contents, options: {})
|
137
|
+
def self.parse_nuspec(file_contents, options: {})
|
132
138
|
manifest = Ox.parse file_contents
|
133
139
|
manifest.package.metadata.dependencies.locate("dependency").map do |dependency|
|
134
140
|
Dependency.new(
|
135
141
|
name: dependency.id,
|
136
142
|
requirement: dependency.attributes[:version],
|
137
143
|
type: dependency.respond_to?("developmentDependency") && dependency.developmentDependency == "true" ? "development" : "runtime",
|
144
|
+
source: options.fetch(:filename, nil)
|
138
145
|
)
|
139
146
|
end
|
140
|
-
rescue
|
147
|
+
rescue StandardError
|
141
148
|
[]
|
142
149
|
end
|
143
150
|
|
144
|
-
def self.parse_paket_lock(file_contents, options: {})
|
151
|
+
def self.parse_paket_lock(file_contents, options: {})
|
145
152
|
lines = file_contents.split("\n")
|
146
153
|
package_version_re = /\s+(?<name>\S+)\s\((?<version>\d+\.\d+[\.\d+[\.\d+]*]*)\)/
|
147
154
|
packages = lines.select { |line| package_version_re.match(line) }.map { |line| package_version_re.match(line) }.map do |match|
|
@@ -149,36 +156,38 @@ module Bibliothecary
|
|
149
156
|
name: match[:name].strip,
|
150
157
|
requirement: match[:version],
|
151
158
|
type: "runtime",
|
159
|
+
source: options.fetch(:filename, nil)
|
152
160
|
)
|
153
161
|
end
|
154
162
|
# we only have to enforce uniqueness by name because paket ensures that there is only the single version globally in the project
|
155
|
-
packages.uniq
|
163
|
+
packages.uniq(&:name)
|
156
164
|
end
|
157
165
|
|
158
|
-
def self.parse_project_assets_json(file_contents, options: {})
|
166
|
+
def self.parse_project_assets_json(file_contents, options: {})
|
159
167
|
manifest = JSON.parse file_contents
|
160
168
|
|
161
169
|
frameworks = {}
|
162
|
-
manifest.fetch("targets",[]).each do |framework, deps|
|
170
|
+
manifest.fetch("targets", []).each do |framework, deps|
|
163
171
|
frameworks[framework] = deps
|
164
172
|
.select { |_name, details| details["type"] == "package" }
|
165
173
|
.map do |name, _details|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
174
|
+
name_split = name.split("/")
|
175
|
+
Dependency.new(
|
176
|
+
name: name_split[0],
|
177
|
+
requirement: name_split[1],
|
178
|
+
type: "runtime",
|
179
|
+
source: options.fetch(:filename, nil)
|
180
|
+
)
|
172
181
|
end
|
173
182
|
end
|
174
183
|
|
175
|
-
|
184
|
+
unless frameworks.empty?
|
176
185
|
# we should really return multiple manifests, but bibliothecary doesn't
|
177
186
|
# do that yet so at least pick deterministically.
|
178
187
|
|
179
188
|
# Note, frameworks can be empty, so remove empty ones and then return the last sorted item if any
|
180
189
|
frameworks = frameworks.delete_if { |_k, v| v.empty? }
|
181
|
-
return frameworks[frameworks.keys.
|
190
|
+
return frameworks[frameworks.keys.max] unless frameworks.empty?
|
182
191
|
end
|
183
192
|
[]
|
184
193
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
|
3
5
|
module Bibliothecary
|
@@ -22,39 +24,47 @@ module Bibliothecary
|
|
22
24
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
23
25
|
add_multi_parser(Bibliothecary::MultiParsers::Spdx)
|
24
26
|
|
25
|
-
def self.parse_lockfile(file_contents, options: {})
|
27
|
+
def self.parse_lockfile(file_contents, options: {})
|
26
28
|
manifest = JSON.parse file_contents
|
27
|
-
manifest.fetch("packages",[]).map do |dependency|
|
29
|
+
manifest.fetch("packages", []).map do |dependency|
|
28
30
|
requirement = dependency["version"]
|
29
31
|
|
30
32
|
# Store Drupal version if Drupal, but include the original manifest version for reference
|
31
|
-
|
33
|
+
if drupal_module?(dependency)
|
34
|
+
original_requirement = requirement
|
35
|
+
requirement = dependency.dig("source", "reference")
|
36
|
+
end
|
32
37
|
|
33
38
|
Dependency.new(
|
34
39
|
name: dependency["name"],
|
35
40
|
requirement: requirement,
|
36
41
|
type: "runtime",
|
37
|
-
original_requirement: original_requirement
|
42
|
+
original_requirement: original_requirement,
|
43
|
+
source: options.fetch(:filename, nil)
|
38
44
|
)
|
39
|
-
end + manifest.fetch("packages-dev",[]).map do |dependency|
|
45
|
+
end + manifest.fetch("packages-dev", []).map do |dependency|
|
40
46
|
requirement = dependency["version"]
|
41
47
|
|
42
48
|
# Store Drupal version if Drupal, but include the original manifest version for reference
|
43
|
-
|
49
|
+
if drupal_module?(dependency)
|
50
|
+
original_requirement = requirement
|
51
|
+
requirement = dependency.dig("source", "reference")
|
52
|
+
end
|
44
53
|
|
45
54
|
Dependency.new(
|
46
55
|
name: dependency["name"],
|
47
56
|
requirement: requirement,
|
48
57
|
type: "development",
|
49
|
-
original_requirement: original_requirement
|
58
|
+
original_requirement: original_requirement,
|
59
|
+
source: options.fetch(:filename, nil)
|
50
60
|
)
|
51
61
|
end
|
52
62
|
end
|
53
63
|
|
54
|
-
def self.parse_manifest(file_contents, options: {})
|
64
|
+
def self.parse_manifest(file_contents, options: {})
|
55
65
|
manifest = JSON.parse file_contents
|
56
|
-
map_dependencies(manifest, "require", "runtime") +
|
57
|
-
|
66
|
+
map_dependencies(manifest, "require", "runtime", options.fetch(:filename, nil)) +
|
67
|
+
map_dependencies(manifest, "require-dev", "development", options.fetch(:filename, nil))
|
58
68
|
end
|
59
69
|
|
60
70
|
# Drupal hosts its own Composer repository, where its "modules" are indexed and searchable. The best way to
|
@@ -65,7 +75,7 @@ module Bibliothecary
|
|
65
75
|
# (https://www.drupal.org/project/project_composer/issues/2622450),
|
66
76
|
# so we return the Drupal requirement instead of semver requirement if it's here
|
67
77
|
# (https://www.drupal.org/docs/develop/using-composer/using-composer-to-install-drupal-and-manage-dependencies#s-about-semantic-versioning)
|
68
|
-
private_class_method def self.
|
78
|
+
private_class_method def self.drupal_module?(dependency)
|
69
79
|
dependency["type"] =~ /drupal/ && dependency.dig("source", "reference")
|
70
80
|
end
|
71
81
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "yaml"
|
2
4
|
|
3
5
|
module Bibliothecary
|
@@ -23,7 +25,7 @@ module Bibliothecary
|
|
23
25
|
def self.parse_yaml_manifest(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
|
24
26
|
manifest = YAML.load file_contents
|
25
27
|
map_dependencies(manifest, "dependencies", "runtime") +
|
26
|
-
|
28
|
+
map_dependencies(manifest, "dev_dependencies", "development")
|
27
29
|
end
|
28
30
|
|
29
31
|
def self.parse_yaml_lockfile(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
|
@@ -32,7 +34,7 @@ module Bibliothecary
|
|
32
34
|
Dependency.new(
|
33
35
|
name: name,
|
34
36
|
requirement: dep["version"],
|
35
|
-
type: "runtime"
|
37
|
+
type: "runtime"
|
36
38
|
)
|
37
39
|
end
|
38
40
|
end
|