bibliothecary 11.0.1 → 12.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +2 -1
- data/.rubocop.yml +10 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +24 -0
- data/Gemfile +16 -1
- data/Rakefile +2 -0
- data/bibliothecary.gemspec +11 -14
- 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 -11
- 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 +56 -33
- 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 +97 -34
- 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 -37
- data/lib/bibliothecary/parsers/rubygems.rb +16 -12
- data/lib/bibliothecary/parsers/shard.rb +10 -7
- data/lib/bibliothecary/purl_util.rb +2 -4
- 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 -120
- data/lib/bibliothecary/parsers/carthage.rb +0 -52
- data/lib/bibliothecary/parsers/clojars.rb +0 -38
- data/lib/bibliothecary/parsers/hackage.rb +0 -53
- data/lib/bibliothecary/parsers/hex.rb +0 -54
- data/lib/bibliothecary/parsers/swift_pm.rb +0 -35
@@ -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,38 +129,91 @@ 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: {})
|
131
|
-
|
140
|
+
def self.parse_yarn_lock(file_contents, options: {})
|
141
|
+
dep_hash = if file_contents.match(/__metadata:/)
|
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
|
146
|
+
|
147
|
+
dep_hash.map do |dep|
|
148
|
+
Dependency.new(
|
149
|
+
name: dep[:name],
|
150
|
+
requirement: dep[:version],
|
151
|
+
type: "runtime", # lockfile doesn't tell us more about the type of dep
|
152
|
+
local: dep[:requirements]&.first&.start_with?("file:"),
|
153
|
+
source: options.fetch(:filename, nil)
|
154
|
+
)
|
155
|
+
end
|
156
|
+
end
|
132
157
|
|
133
|
-
|
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
|
134
187
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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")
|
140
197
|
end
|
141
|
-
.map do |
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
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(/^.*:/, "") }
|
203
|
+
|
204
|
+
{
|
205
|
+
name: name,
|
206
|
+
requirements: requirements,
|
207
|
+
version: info["version"].to_s,
|
208
|
+
source: source,
|
209
|
+
}
|
148
210
|
end
|
149
211
|
end
|
150
212
|
|
151
|
-
def self.parse_ls(file_contents, options: {})
|
213
|
+
def self.parse_ls(file_contents, options: {})
|
152
214
|
manifest = JSON.parse(file_contents)
|
153
215
|
|
154
|
-
transform_tree_to_array(manifest.fetch("dependencies", {}))
|
216
|
+
transform_tree_to_array(manifest.fetch("dependencies", {}), options.fetch(:filename, nil))
|
155
217
|
end
|
156
218
|
|
157
219
|
def self.lockfile_preference_order(file_infos)
|
@@ -166,15 +228,16 @@ module Bibliothecary
|
|
166
228
|
end
|
167
229
|
end
|
168
230
|
|
169
|
-
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)
|
170
232
|
deps_by_name.map do |name, metadata|
|
171
233
|
[
|
172
234
|
Dependency.new(
|
173
235
|
name: name,
|
174
236
|
requirement: metadata["version"],
|
175
237
|
type: "runtime",
|
238
|
+
source: source
|
176
239
|
),
|
177
|
-
] + transform_tree_to_array(metadata.fetch("dependencies", {}))
|
240
|
+
] + transform_tree_to_array(metadata.fetch("dependencies", {}), source)
|
178
241
|
end.flatten(1)
|
179
242
|
end
|
180
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
|