dependabot-npm_and_yarn 0.292.0 → 0.293.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/dependabot/npm_and_yarn/bun_package_manager.rb +46 -0
- data/lib/dependabot/npm_and_yarn/dependency_files_filterer.rb +2 -1
- data/lib/dependabot/npm_and_yarn/file_fetcher.rb +50 -33
- data/lib/dependabot/npm_and_yarn/file_parser/bun_lock.rb +141 -0
- data/lib/dependabot/npm_and_yarn/file_parser/lockfile_parser.rb +33 -27
- data/lib/dependabot/npm_and_yarn/file_parser/pnpm_lock.rb +47 -0
- data/lib/dependabot/npm_and_yarn/file_parser.rb +9 -1
- data/lib/dependabot/npm_and_yarn/file_updater/bun_lockfile_updater.rb +144 -0
- data/lib/dependabot/npm_and_yarn/file_updater/pnpm_lockfile_updater.rb +46 -0
- data/lib/dependabot/npm_and_yarn/file_updater.rb +48 -0
- data/lib/dependabot/npm_and_yarn/helpers.rb +40 -0
- data/lib/dependabot/npm_and_yarn/language.rb +45 -0
- data/lib/dependabot/npm_and_yarn/npm_package_manager.rb +70 -0
- data/lib/dependabot/npm_and_yarn/package_manager.rb +12 -194
- data/lib/dependabot/npm_and_yarn/pnpm_package_manager.rb +55 -0
- data/lib/dependabot/npm_and_yarn/sub_dependency_files_filterer.rb +1 -0
- data/lib/dependabot/npm_and_yarn/update_checker/dependency_files_builder.rb +14 -7
- data/lib/dependabot/npm_and_yarn/update_checker/subdependency_version_resolver.rb +14 -0
- data/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb +19 -0
- data/lib/dependabot/npm_and_yarn/yarn_package_manager.rb +56 -0
- metadata +12 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d548c0891264c8b407f2b673e39266b3494683e431ac1e8b9ebc899319208f5
|
4
|
+
data.tar.gz: b43aeb89fb1a1c1e32a9d86eee5ccc188d8fc3da548ee4cbbcfbc4c76cfd59c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95eef6390619686a8017fc949e5a5609e34f3675920fea726975fb42c55904e9901ef55b80df005ffa43bf74e87623ed00a9a287005af9446c93b78fcb0c010d
|
7
|
+
data.tar.gz: 9a104350702acef102f005bdc0c4649b7713288de3685992538f9e58384487802f48a1f1c6e57dd6ac244fb11e849fd89b72f2f3648355eb3115d1174846e21f
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# typed: strong
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Dependabot
|
5
|
+
module NpmAndYarn
|
6
|
+
class BunPackageManager < Ecosystem::VersionManager
|
7
|
+
extend T::Sig
|
8
|
+
NAME = "bun"
|
9
|
+
LOCKFILE_NAME = "bun.lock"
|
10
|
+
|
11
|
+
# In Bun 1.1.39, the lockfile format was changed from a binary bun.lockb to a text-based bun.lock.
|
12
|
+
# https://bun.sh/blog/bun-lock-text-lockfile
|
13
|
+
MIN_SUPPORTED_VERSION = Version.new("1.1.39")
|
14
|
+
SUPPORTED_VERSIONS = T.let([MIN_SUPPORTED_VERSION].freeze, T::Array[Dependabot::Version])
|
15
|
+
DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
|
16
|
+
|
17
|
+
sig do
|
18
|
+
params(
|
19
|
+
detected_version: T.nilable(String),
|
20
|
+
raw_version: T.nilable(String),
|
21
|
+
requirement: T.nilable(Dependabot::NpmAndYarn::Requirement)
|
22
|
+
).void
|
23
|
+
end
|
24
|
+
def initialize(detected_version: nil, raw_version: nil, requirement: nil)
|
25
|
+
super(
|
26
|
+
name: NAME,
|
27
|
+
detected_version: detected_version ? Version.new(detected_version) : nil,
|
28
|
+
version: raw_version ? Version.new(raw_version) : nil,
|
29
|
+
deprecated_versions: DEPRECATED_VERSIONS,
|
30
|
+
supported_versions: SUPPORTED_VERSIONS,
|
31
|
+
requirement: requirement
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
sig { override.returns(T::Boolean) }
|
36
|
+
def deprecated?
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
sig { override.returns(T::Boolean) }
|
41
|
+
def unsupported?
|
42
|
+
supported_versions.all? { |supported| supported > version }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -82,7 +82,7 @@ module Dependabot
|
|
82
82
|
|
83
83
|
sig { params(lockfile: DependencyFile).returns(T::Boolean) }
|
84
84
|
def workspaces_lockfile?(lockfile)
|
85
|
-
return false unless ["yarn.lock", "package-lock.json", "pnpm-lock.yaml"].include?(lockfile.name)
|
85
|
+
return false unless ["yarn.lock", "package-lock.json", "pnpm-lock.yaml", "bun.lock"].include?(lockfile.name)
|
86
86
|
|
87
87
|
return false unless parsed_root_package_json["workspaces"] || dependency_files.any? do |file|
|
88
88
|
file.name.end_with?("pnpm-workspace.yaml") && File.dirname(file.name) == File.dirname(lockfile.name)
|
@@ -148,6 +148,7 @@ module Dependabot
|
|
148
148
|
"package-lock.json",
|
149
149
|
"yarn.lock",
|
150
150
|
"pnpm-lock.yaml",
|
151
|
+
"bun.lock",
|
151
152
|
"npm-shrinkwrap.json"
|
152
153
|
)
|
153
154
|
end
|
@@ -68,6 +68,7 @@ module Dependabot
|
|
68
68
|
package_managers["npm"] = npm_version if npm_version
|
69
69
|
package_managers["yarn"] = yarn_version if yarn_version
|
70
70
|
package_managers["pnpm"] = pnpm_version if pnpm_version
|
71
|
+
package_managers["bun"] = bun_version if bun_version
|
71
72
|
package_managers["unknown"] = 1 if package_managers.empty?
|
72
73
|
|
73
74
|
{
|
@@ -83,6 +84,7 @@ module Dependabot
|
|
83
84
|
fetched_files += npm_files if npm_version
|
84
85
|
fetched_files += yarn_files if yarn_version
|
85
86
|
fetched_files += pnpm_files if pnpm_version
|
87
|
+
fetched_files += bun_files if bun_version
|
86
88
|
fetched_files += lerna_files
|
87
89
|
fetched_files += workspace_package_jsons
|
88
90
|
fetched_files += path_dependencies(fetched_files)
|
@@ -120,6 +122,13 @@ module Dependabot
|
|
120
122
|
fetched_pnpm_files
|
121
123
|
end
|
122
124
|
|
125
|
+
sig { returns(T::Array[DependencyFile]) }
|
126
|
+
def bun_files
|
127
|
+
fetched_bun_files = []
|
128
|
+
fetched_bun_files << bun_lock if bun_lock
|
129
|
+
fetched_bun_files
|
130
|
+
end
|
131
|
+
|
123
132
|
sig { returns(T::Array[DependencyFile]) }
|
124
133
|
def lerna_files
|
125
134
|
fetched_lerna_files = []
|
@@ -202,6 +211,16 @@ module Dependabot
|
|
202
211
|
)
|
203
212
|
end
|
204
213
|
|
214
|
+
sig { returns(T.nilable(T.any(Integer, String))) }
|
215
|
+
def bun_version
|
216
|
+
return @bun_version = nil unless Experiments.enabled?(:bun_updates)
|
217
|
+
|
218
|
+
@bun_version ||= T.let(
|
219
|
+
package_manager_helper.setup(BunPackageManager::NAME),
|
220
|
+
T.nilable(T.any(Integer, String))
|
221
|
+
)
|
222
|
+
end
|
223
|
+
|
205
224
|
sig { returns(PackageManagerHelper) }
|
206
225
|
def package_manager_helper
|
207
226
|
@package_manager_helper ||= T.let(
|
@@ -219,7 +238,8 @@ module Dependabot
|
|
219
238
|
{
|
220
239
|
npm: package_lock || shrinkwrap,
|
221
240
|
yarn: yarn_lock,
|
222
|
-
pnpm: pnpm_lock
|
241
|
+
pnpm: pnpm_lock,
|
242
|
+
bun: bun_lock
|
223
243
|
}
|
224
244
|
end
|
225
245
|
|
@@ -261,17 +281,18 @@ module Dependabot
|
|
261
281
|
|
262
282
|
return @pnpm_lock if @pnpm_lock || directory == "/"
|
263
283
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
end
|
284
|
+
@pnpm_lock = fetch_file_from_parent_directories(PNPMPackageManager::LOCKFILE_NAME)
|
285
|
+
end
|
286
|
+
|
287
|
+
sig { returns(T.nilable(DependencyFile)) }
|
288
|
+
def bun_lock
|
289
|
+
return @bun_lock if defined?(@bun_lock)
|
290
|
+
|
291
|
+
@bun_lock ||= T.let(fetch_file_if_present(BunPackageManager::LOCKFILE_NAME), T.nilable(DependencyFile))
|
273
292
|
|
274
|
-
@
|
293
|
+
return @bun_lock if @bun_lock || directory == "/"
|
294
|
+
|
295
|
+
@bun_lock = fetch_file_from_parent_directories(BunPackageManager::LOCKFILE_NAME)
|
275
296
|
end
|
276
297
|
|
277
298
|
sig { returns(T.nilable(DependencyFile)) }
|
@@ -294,17 +315,7 @@ module Dependabot
|
|
294
315
|
|
295
316
|
return @npmrc if @npmrc || directory == "/"
|
296
317
|
|
297
|
-
|
298
|
-
(1..directory.split("/").count).each do |i|
|
299
|
-
@npmrc = fetch_file_from_host(("../" * i) + NpmPackageManager::RC_FILENAME)
|
300
|
-
.tap { |f| f.support_file = true }
|
301
|
-
break if @npmrc
|
302
|
-
rescue Dependabot::DependencyFileNotFound
|
303
|
-
# Ignore errors (.npmrc may not be present)
|
304
|
-
nil
|
305
|
-
end
|
306
|
-
|
307
|
-
@npmrc
|
318
|
+
@npmrc = fetch_file_from_parent_directories(NpmPackageManager::RC_FILENAME)
|
308
319
|
end
|
309
320
|
|
310
321
|
sig { returns(T.nilable(DependencyFile)) }
|
@@ -315,17 +326,7 @@ module Dependabot
|
|
315
326
|
|
316
327
|
return @yarnrc if @yarnrc || directory == "/"
|
317
328
|
|
318
|
-
|
319
|
-
(1..directory.split("/").count).each do |i|
|
320
|
-
@yarnrc = fetch_file_from_host(("../" * i) + YarnPackageManager::RC_FILENAME)
|
321
|
-
.tap { |f| f.support_file = true }
|
322
|
-
break if @yarnrc
|
323
|
-
rescue Dependabot::DependencyFileNotFound
|
324
|
-
# Ignore errors (.yarnrc may not be present)
|
325
|
-
nil
|
326
|
-
end
|
327
|
-
|
328
|
-
@yarnrc
|
329
|
+
@yarnrc = fetch_file_from_parent_directories(YarnPackageManager::RC_FILENAME)
|
329
330
|
end
|
330
331
|
|
331
332
|
sig { returns(T.nilable(DependencyFile)) }
|
@@ -699,6 +700,22 @@ module Dependabot
|
|
699
700
|
Dependabot.logger.info("Repository contents path does not exist")
|
700
701
|
end
|
701
702
|
end
|
703
|
+
|
704
|
+
sig { params(filename: String).returns(T.nilable(DependencyFile)) }
|
705
|
+
def fetch_file_with_support(filename)
|
706
|
+
fetch_file_from_host(filename).tap { |f| f.support_file = true }
|
707
|
+
rescue Dependabot::DependencyFileNotFound
|
708
|
+
nil
|
709
|
+
end
|
710
|
+
|
711
|
+
sig { params(filename: String).returns(T.nilable(DependencyFile)) }
|
712
|
+
def fetch_file_from_parent_directories(filename)
|
713
|
+
(1..directory.split("/").count).each do |i|
|
714
|
+
file = fetch_file_with_support(("../" * i) + filename)
|
715
|
+
return file if file
|
716
|
+
end
|
717
|
+
nil
|
718
|
+
end
|
702
719
|
end
|
703
720
|
end
|
704
721
|
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "yaml"
|
5
|
+
require "dependabot/errors"
|
6
|
+
require "dependabot/npm_and_yarn/helpers"
|
7
|
+
require "sorbet-runtime"
|
8
|
+
|
9
|
+
module Dependabot
|
10
|
+
module NpmAndYarn
|
11
|
+
class FileParser < Dependabot::FileParsers::Base
|
12
|
+
class BunLock
|
13
|
+
extend T::Sig
|
14
|
+
|
15
|
+
sig { params(dependency_file: DependencyFile).void }
|
16
|
+
def initialize(dependency_file)
|
17
|
+
@dependency_file = dependency_file
|
18
|
+
end
|
19
|
+
|
20
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
21
|
+
def parsed
|
22
|
+
@parsed ||= begin
|
23
|
+
content = begin
|
24
|
+
# Since bun.lock is a JSONC file, which is a subset of YAML, we can use YAML to parse it
|
25
|
+
YAML.load(T.must(@dependency_file.content))
|
26
|
+
rescue Psych::SyntaxError => e
|
27
|
+
raise_invalid!("malformed JSONC at line #{e.line}, column #{e.column}")
|
28
|
+
end
|
29
|
+
raise_invalid!("expected to be an object") unless content.is_a?(Hash)
|
30
|
+
|
31
|
+
version = content["lockfileVersion"]
|
32
|
+
raise_invalid!("expected 'lockfileVersion' to be an integer") unless version.is_a?(Integer)
|
33
|
+
raise_invalid!("expected 'lockfileVersion' to be >= 0") unless version >= 0
|
34
|
+
raise_invalid!("unsupported 'lockfileVersion' = #{version}") unless version.zero?
|
35
|
+
|
36
|
+
T.let(content, T.untyped)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
41
|
+
def dependencies
|
42
|
+
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
43
|
+
|
44
|
+
# bun.lock v0 format:
|
45
|
+
# https://github.com/oven-sh/bun/blob/c130df6c589fdf28f9f3c7f23ed9901140bc9349/src/install/bun.lock.zig#L595-L605
|
46
|
+
|
47
|
+
packages = parsed["packages"]
|
48
|
+
raise_invalid!("expected 'packages' to be an object") unless packages.is_a?(Hash)
|
49
|
+
|
50
|
+
packages.each do |key, details|
|
51
|
+
raise_invalid!("expected 'packages.#{key}' to be an array") unless details.is_a?(Array)
|
52
|
+
|
53
|
+
resolution = details.first
|
54
|
+
raise_invalid!("expected 'packages.#{key}[0]' to be a string") unless resolution.is_a?(String)
|
55
|
+
|
56
|
+
name, version = resolution.split(/(?<=\w)\@/)
|
57
|
+
next if name.empty?
|
58
|
+
|
59
|
+
semver = Version.semver_for(version)
|
60
|
+
next unless semver
|
61
|
+
|
62
|
+
dependency_set << Dependency.new(
|
63
|
+
name: name,
|
64
|
+
version: semver.to_s,
|
65
|
+
package_manager: "npm_and_yarn",
|
66
|
+
requirements: []
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
dependency_set
|
71
|
+
end
|
72
|
+
|
73
|
+
sig do
|
74
|
+
params(dependency_name: String, requirement: T.untyped, _manifest_name: String)
|
75
|
+
.returns(T.nilable(T::Hash[String, T.untyped]))
|
76
|
+
end
|
77
|
+
def details(dependency_name, requirement, _manifest_name)
|
78
|
+
packages = parsed["packages"]
|
79
|
+
return unless packages.is_a?(Hash)
|
80
|
+
|
81
|
+
candidates =
|
82
|
+
packages
|
83
|
+
.select { |name, _| name == dependency_name }
|
84
|
+
.values
|
85
|
+
|
86
|
+
# If there's only one entry for this dependency, use it, even if
|
87
|
+
# the requirement in the lockfile doesn't match
|
88
|
+
if candidates.one?
|
89
|
+
parse_details(candidates.first)
|
90
|
+
else
|
91
|
+
candidate = candidates.find do |label, _|
|
92
|
+
label.scan(/(?<=\w)\@(?:npm:)?([^\s,]+)/).flatten.include?(requirement)
|
93
|
+
end&.last
|
94
|
+
parse_details(candidate)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
sig { params(message: String).void }
|
101
|
+
def raise_invalid!(message)
|
102
|
+
raise Dependabot::DependencyFileNotParseable.new(@dependency_file.path, "Invalid bun.lock file: #{message}")
|
103
|
+
end
|
104
|
+
|
105
|
+
sig do
|
106
|
+
params(entry: T.nilable(T::Array[T.untyped])).returns(T.nilable(T::Hash[String, T.untyped]))
|
107
|
+
end
|
108
|
+
def parse_details(entry)
|
109
|
+
return unless entry.is_a?(Array)
|
110
|
+
|
111
|
+
# Either:
|
112
|
+
# - "{name}@{version}", registry, details, integrity
|
113
|
+
# - "{name}@{resolution}", details
|
114
|
+
resolution = entry.first
|
115
|
+
return unless resolution.is_a?(String)
|
116
|
+
|
117
|
+
name, version = resolution.split(/(?<=\w)\@/)
|
118
|
+
semver = Version.semver_for(version)
|
119
|
+
|
120
|
+
if semver
|
121
|
+
registry, details, integrity = entry[1..3]
|
122
|
+
{
|
123
|
+
"name" => name,
|
124
|
+
"version" => semver.to_s,
|
125
|
+
"registry" => registry,
|
126
|
+
"details" => details,
|
127
|
+
"integrity" => integrity
|
128
|
+
}
|
129
|
+
else
|
130
|
+
details = entry[1]
|
131
|
+
{
|
132
|
+
"name" => name,
|
133
|
+
"resolution" => version,
|
134
|
+
"details" => details
|
135
|
+
}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -15,6 +15,11 @@ module Dependabot
|
|
15
15
|
require "dependabot/npm_and_yarn/file_parser/yarn_lock"
|
16
16
|
require "dependabot/npm_and_yarn/file_parser/pnpm_lock"
|
17
17
|
require "dependabot/npm_and_yarn/file_parser/json_lock"
|
18
|
+
require "dependabot/npm_and_yarn/file_parser/bun_lock"
|
19
|
+
|
20
|
+
DEFAULT_LOCKFILES = %w(package-lock.json yarn.lock pnpm-lock.yaml bun.lock npm-shrinkwrap.json).freeze
|
21
|
+
|
22
|
+
LockFile = T.type_alias { T.any(JsonLock, YarnLock, PnpmLock, BunLock) }
|
18
23
|
|
19
24
|
sig { params(dependency_files: T::Array[DependencyFile]).void }
|
20
25
|
def initialize(dependency_files:)
|
@@ -29,7 +34,7 @@ module Dependabot
|
|
29
34
|
# end up unique by name. That's not a perfect representation of
|
30
35
|
# the nested nature of JS resolution, but it makes everything work
|
31
36
|
# comparably to other flat-resolution strategies
|
32
|
-
(yarn_locks + pnpm_locks + package_locks + shrinkwraps).each do |file|
|
37
|
+
(yarn_locks + pnpm_locks + package_locks + bun_locks + shrinkwraps).each do |file|
|
33
38
|
dependency_set += lockfile_for(file).dependencies
|
34
39
|
end
|
35
40
|
|
@@ -64,58 +69,59 @@ module Dependabot
|
|
64
69
|
sig { params(manifest_filename: String).returns(T::Array[DependencyFile]) }
|
65
70
|
def potential_lockfiles_for_manifest(manifest_filename)
|
66
71
|
dir_name = File.dirname(manifest_filename)
|
67
|
-
possible_lockfile_names =
|
68
|
-
|
69
|
-
|
70
|
-
end +
|
71
|
-
%w(yarn.lock pnpm-lock.yaml package-lock.json npm-shrinkwrap.json)
|
72
|
+
possible_lockfile_names = DEFAULT_LOCKFILES.map do |f|
|
73
|
+
Pathname.new(File.join(dir_name, f)).cleanpath.to_path
|
74
|
+
end + DEFAULT_LOCKFILES
|
72
75
|
|
73
76
|
possible_lockfile_names.uniq
|
74
77
|
.filter_map { |nm| dependency_files.find { |f| f.name == nm } }
|
75
78
|
end
|
76
79
|
|
77
|
-
sig { params(file: DependencyFile).returns(
|
80
|
+
sig { params(file: DependencyFile).returns(LockFile) }
|
78
81
|
def lockfile_for(file)
|
79
|
-
@lockfiles ||= T.let({}, T.nilable(T::Hash[String,
|
80
|
-
@lockfiles[file.name] ||=
|
82
|
+
@lockfiles ||= T.let({}, T.nilable(T::Hash[String, LockFile]))
|
83
|
+
@lockfiles[file.name] ||= case file.name
|
84
|
+
when *package_locks.map(&:name), *shrinkwraps.map(&:name)
|
81
85
|
JsonLock.new(file)
|
82
|
-
|
86
|
+
when *yarn_locks.map(&:name)
|
83
87
|
YarnLock.new(file)
|
84
|
-
|
88
|
+
when *pnpm_locks.map(&:name)
|
85
89
|
PnpmLock.new(file)
|
90
|
+
when *bun_locks.map(&:name)
|
91
|
+
BunLock.new(file)
|
92
|
+
else
|
93
|
+
raise "Unexpected lockfile: #{file.name}"
|
86
94
|
end
|
87
95
|
end
|
88
96
|
|
97
|
+
sig { params(extension: String).returns(T::Array[DependencyFile]) }
|
98
|
+
def select_files_by_extension(extension)
|
99
|
+
dependency_files.select { |f| f.name.end_with?(extension) }
|
100
|
+
end
|
101
|
+
|
89
102
|
sig { returns(T::Array[DependencyFile]) }
|
90
103
|
def package_locks
|
91
|
-
@package_locks ||= T.let(
|
92
|
-
dependency_files
|
93
|
-
.select { |f| f.name.end_with?("package-lock.json") }, T.nilable(T::Array[DependencyFile])
|
94
|
-
)
|
104
|
+
@package_locks ||= T.let(select_files_by_extension("package-lock.json"), T.nilable(T::Array[DependencyFile]))
|
95
105
|
end
|
96
106
|
|
97
107
|
sig { returns(T::Array[DependencyFile]) }
|
98
108
|
def pnpm_locks
|
99
|
-
@pnpm_locks ||= T.let(
|
100
|
-
|
101
|
-
|
102
|
-
|
109
|
+
@pnpm_locks ||= T.let(select_files_by_extension("pnpm-lock.yaml"), T.nilable(T::Array[DependencyFile]))
|
110
|
+
end
|
111
|
+
|
112
|
+
sig { returns(T::Array[DependencyFile]) }
|
113
|
+
def bun_locks
|
114
|
+
@bun_locks ||= T.let(select_files_by_extension("bun.lock"), T.nilable(T::Array[DependencyFile]))
|
103
115
|
end
|
104
116
|
|
105
117
|
sig { returns(T::Array[DependencyFile]) }
|
106
118
|
def yarn_locks
|
107
|
-
@yarn_locks ||= T.let(
|
108
|
-
dependency_files
|
109
|
-
.select { |f| f.name.end_with?("yarn.lock") }, T.nilable(T::Array[DependencyFile])
|
110
|
-
)
|
119
|
+
@yarn_locks ||= T.let(select_files_by_extension("yarn.lock"), T.nilable(T::Array[DependencyFile]))
|
111
120
|
end
|
112
121
|
|
113
122
|
sig { returns(T::Array[DependencyFile]) }
|
114
123
|
def shrinkwraps
|
115
|
-
@shrinkwraps ||= T.let(
|
116
|
-
dependency_files
|
117
|
-
.select { |f| f.name.end_with?("npm-shrinkwrap.json") }, T.nilable(T::Array[DependencyFile])
|
118
|
-
)
|
124
|
+
@shrinkwraps ||= T.let(select_files_by_extension("npm-shrinkwrap.json"), T.nilable(T::Array[DependencyFile]))
|
119
125
|
end
|
120
126
|
|
121
127
|
sig { returns(T.class_of(Dependabot::NpmAndYarn::Version)) }
|
@@ -26,6 +26,10 @@ module Dependabot
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def dependencies
|
29
|
+
if Dependabot::Experiments.enabled?(:enable_fix_for_pnpm_no_change_error)
|
30
|
+
return dependencies_with_prioritization
|
31
|
+
end
|
32
|
+
|
29
33
|
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
30
34
|
|
31
35
|
parsed.each do |details|
|
@@ -52,6 +56,49 @@ module Dependabot
|
|
52
56
|
dependency_set
|
53
57
|
end
|
54
58
|
|
59
|
+
def dependencies_with_prioritization
|
60
|
+
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
61
|
+
|
62
|
+
# Separate dependencies into two categories: with specifiers and without specifiers.
|
63
|
+
dependencies_with_specifiers = [] # Main dependencies with specifiers.
|
64
|
+
dependencies_without_specifiers = [] # Subdependencies without specifiers.
|
65
|
+
|
66
|
+
parsed.each do |details|
|
67
|
+
next if details["aliased"]
|
68
|
+
|
69
|
+
name = details["name"]
|
70
|
+
version = details["version"]
|
71
|
+
|
72
|
+
dependency_args = {
|
73
|
+
name: name,
|
74
|
+
version: version,
|
75
|
+
package_manager: "npm_and_yarn",
|
76
|
+
requirements: []
|
77
|
+
}
|
78
|
+
|
79
|
+
# Add metadata for subdependencies if marked as a dev dependency.
|
80
|
+
dependency_args[:subdependency_metadata] = [{ production: !details["dev"] }] if details["dev"]
|
81
|
+
|
82
|
+
specifiers = details["specifiers"]
|
83
|
+
if specifiers&.any?
|
84
|
+
dependencies_with_specifiers << dependency_args
|
85
|
+
else
|
86
|
+
dependencies_without_specifiers << dependency_args
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Add prioritized dependencies to the dependency set.
|
91
|
+
dependencies_with_specifiers.each do |dependency_args|
|
92
|
+
dependency_set << Dependency.new(**dependency_args)
|
93
|
+
end
|
94
|
+
|
95
|
+
dependencies_without_specifiers.each do |dependency_args|
|
96
|
+
dependency_set << Dependency.new(**dependency_args)
|
97
|
+
end
|
98
|
+
|
99
|
+
dependency_set
|
100
|
+
end
|
101
|
+
|
55
102
|
def details(dependency_name, requirement, _manifest_name)
|
56
103
|
details_candidates = parsed.select { |info| info["name"] == dependency_name }
|
57
104
|
|
@@ -110,7 +110,8 @@ module Dependabot
|
|
110
110
|
{
|
111
111
|
npm: package_lock || shrinkwrap,
|
112
112
|
yarn: yarn_lock,
|
113
|
-
pnpm: pnpm_lock
|
113
|
+
pnpm: pnpm_lock,
|
114
|
+
bun: bun_lock
|
114
115
|
}
|
115
116
|
end
|
116
117
|
|
@@ -167,6 +168,13 @@ module Dependabot
|
|
167
168
|
end, T.nilable(Dependabot::DependencyFile))
|
168
169
|
end
|
169
170
|
|
171
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
172
|
+
def bun_lock
|
173
|
+
@bun_lock ||= T.let(dependency_files.find do |f|
|
174
|
+
f.name == BunPackageManager::LOCKFILE_NAME
|
175
|
+
end, T.nilable(Dependabot::DependencyFile))
|
176
|
+
end
|
177
|
+
|
170
178
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
171
179
|
def npmrc
|
172
180
|
@npmrc ||= T.let(dependency_files.find do |f|
|