dependabot-npm_and_yarn 0.291.0 → 0.293.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/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 +42 -4
- 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 +46 -183
- 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/version.rb +17 -1
- data/lib/dependabot/npm_and_yarn/yarn_package_manager.rb +56 -0
- metadata +13 -6
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|
|